sebb        2004/09/25 13:59:50

  Modified:    bin      Tag: rel-2_0 jmeter.properties
               src/functions/org/apache/jmeter/functions Tag: rel-2_0
                        PackageTest.java BeanShell.java
               src/protocol/java/org/apache/jmeter/protocol/java/sampler
                        Tag: rel-2_0 BeanShellSampler.java
               xdocs/usermanual Tag: rel-2_0 functions.xml
                        component_reference.xml
  Added:       bin      Tag: rel-2_0 BeanShellSampler.bshrc
                        BeanShellFunction.bshrc
               bin/testfiles Tag: rel-2_0 BeanShellTest.bsh
  Log:
  Update BeanShell sampler and Function to add initialisation file;
  update documentation on Bsh variables; add new unit tests and files
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.100.2.7 +5 -1      jakarta-jmeter/bin/jmeter.properties
  
  Index: jmeter.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/bin/jmeter.properties,v
  retrieving revision 1.100.2.6
  retrieving revision 1.100.2.7
  diff -u -r1.100.2.6 -r1.100.2.7
  --- jmeter.properties 21 Sep 2004 00:41:14 -0000      1.100.2.6
  +++ jmeter.properties 25 Sep 2004 20:59:50 -0000      1.100.2.7
  @@ -283,6 +283,10 @@
   #
   # Define the server initialisation file
   #beanshell.server.file=initial.bsh
  +#
  +# Define the intialisation files for BeanShell Sampler and Function elements
  +#beanshell.sampler.init=BeanShellSampler.bshrc
  +#beanshell.function.init=BeanShellFunction.bshrc
   
   #TestBeanGui
   #
  
  
  
  No                   revision
  
  Index: jmeter.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/bin/jmeter.properties,v
  retrieving revision 1.100.2.6
  retrieving revision 1.100.2.7
  diff -u -r1.100.2.6 -r1.100.2.7
  --- jmeter.properties 21 Sep 2004 00:41:14 -0000      1.100.2.6
  +++ jmeter.properties 25 Sep 2004 20:59:50 -0000      1.100.2.7
  @@ -283,6 +283,10 @@
   #
   # Define the server initialisation file
   #beanshell.server.file=initial.bsh
  +#
  +# Define the intialisation files for BeanShell Sampler and Function elements
  +#beanshell.sampler.init=BeanShellSampler.bshrc
  +#beanshell.function.init=BeanShellFunction.bshrc
   
   #TestBeanGui
   #
  
  
  
  No                   revision
  
  Index: jmeter.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/bin/jmeter.properties,v
  retrieving revision 1.100.2.6
  retrieving revision 1.100.2.7
  diff -u -r1.100.2.6 -r1.100.2.7
  --- jmeter.properties 21 Sep 2004 00:41:14 -0000      1.100.2.6
  +++ jmeter.properties 25 Sep 2004 20:59:50 -0000      1.100.2.7
  @@ -283,6 +283,10 @@
   #
   # Define the server initialisation file
   #beanshell.server.file=initial.bsh
  +#
  +# Define the intialisation files for BeanShell Sampler and Function elements
  +#beanshell.sampler.init=BeanShellSampler.bshrc
  +#beanshell.function.init=BeanShellFunction.bshrc
   
   #TestBeanGui
   #
  
  
  
  1.1.2.1   +30 -0     jakarta-jmeter/bin/Attic/BeanShellSampler.bshrc
  
  
  
  
  1.1.2.1   +30 -0     jakarta-jmeter/bin/Attic/BeanShellFunction.bshrc
  
  
  
  
  No                   revision
  No                   revision
  1.10.2.6  +35 -4     
jakarta-jmeter/src/functions/org/apache/jmeter/functions/PackageTest.java
  
  Index: PackageTest.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-jmeter/src/functions/org/apache/jmeter/functions/PackageTest.java,v
  retrieving revision 1.10.2.5
  retrieving revision 1.10.2.6
  diff -u -r1.10.2.5 -r1.10.2.6
  --- PackageTest.java  23 Sep 2004 23:12:50 -0000      1.10.2.5
  +++ PackageTest.java  25 Sep 2004 20:59:50 -0000      1.10.2.6
  @@ -38,6 +38,7 @@
   import org.apache.jmeter.threads.JMeterContext;
   import org.apache.jmeter.threads.JMeterContextService;
   import org.apache.jmeter.threads.JMeterVariables;
  +import org.apache.jmeter.util.JMeterUtils;
   import org.apache.jorphan.logging.LoggingManager;
   import org.apache.jorphan.util.JMeterStopThreadException;
   import org.apache.log.Logger;
  @@ -167,6 +168,7 @@
   
       public void BSH1() throws Exception
        {
  +             String fn = "testfiles/BeanShellTest.bsh";
        BeanShell bsh;
        try
                {
  @@ -190,6 +192,16 @@
                assertEquals("2",bsh.execute());
                assertEquals("2",vars.get("VAR"));
   
  +             // Check some initial variables
  +             bsh = BSHFParams("return threadName",null,null);
  +             assertEquals(Thread.currentThread().getName(),bsh.execute());
  +             bsh = BSHFParams("return log.getClass().getName()",null,null);
  +             assertEquals(log.getClass().getName(),bsh.execute());
  +
  +             // Check source works
  +             bsh = BSHFParams("source (\"testfiles/BeanShellTest.bsh\")",null,null);
  +             assertEquals("9876",bsh.execute());
  +
                // Check persistence
                bsh = BSHFParams("${SCR1}",null,null);
   
  @@ -202,10 +214,29 @@
                vars.put("SCR1","x=var1");
                assertEquals("11",bsh.execute());
   
  -             vars.put("SCR1","x");
  -             assertEquals("11",bsh.execute());
  +             vars.put("SCR1","++x");
  +             assertEquals("12",bsh.execute());
   
  +             vars.put("VAR1","test");
  +             vars.put("SCR1","vars.get(\"VAR1\")");
  +             assertEquals("test",bsh.execute());
  +
  +
  +             // Check init file functioning
  +             JMeterUtils.getJMeterProperties()
  +                 .setProperty(BeanShell.INIT_FILE,fn);
  +             bsh = BSHFParams("${SCR2}",null,null);
  +             vars.put("SCR2","getprop(\""+BeanShell.INIT_FILE+"\")");
  +             assertEquals(fn,bsh.execute());// Check that bsh has read the file
  +             vars.put("SCR2","getprop(\"avavaav\",\"default\")");
  +             assertEquals("default",bsh.execute());
  +             vars.put("SCR2","++i");
  +             assertEquals("1",bsh.execute());
  +             vars.put("SCR2","++i");
  +             assertEquals("2",bsh.execute());
  +             
        }
  +    
       public void SplitTest1() throws Exception
       {
        SplitFunction split=null;
  
  
  
  1.3.2.2   +62 -20    
jakarta-jmeter/src/functions/org/apache/jmeter/functions/BeanShell.java
  
  Index: BeanShell.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-jmeter/src/functions/org/apache/jmeter/functions/BeanShell.java,v
  retrieving revision 1.3.2.1
  retrieving revision 1.3.2.2
  diff -u -r1.3.2.1 -r1.3.2.2
  --- BeanShell.java    23 Sep 2004 23:07:37 -0000      1.3.2.1
  +++ BeanShell.java    25 Sep 2004 20:59:50 -0000      1.3.2.2
  @@ -19,6 +19,7 @@
   package org.apache.jmeter.functions;
   
   import java.io.Serializable;
  +import java.lang.reflect.InvocationTargetException;
   import java.lang.reflect.Method;
   import java.util.Collection;
   import java.util.LinkedList;
  @@ -27,6 +28,8 @@
   import org.apache.jmeter.engine.util.CompoundVariable;
   import org.apache.jmeter.samplers.SampleResult;
   import org.apache.jmeter.samplers.Sampler;
  +import org.apache.jmeter.threads.JMeterContext;
  +import org.apache.jmeter.threads.JMeterContextService;
   import org.apache.jmeter.threads.JMeterVariables;
   import org.apache.jmeter.util.JMeterUtils;
   import org.apache.jorphan.logging.LoggingManager;
  @@ -47,7 +50,8 @@
        protected static Logger log = LoggingManager.getLoggerForClass();
   
       private static final List desc = new LinkedList();
  -    private static final String KEY = "__BeanShell";
  +    private static final String KEY = "__BeanShell";  //$NON-NLS-1$
  +    public static final String INIT_FILE = "beanshell.function.init";  //$NON-NLS-1$
   
        
       static {
  @@ -75,12 +79,13 @@
           throws InvalidVariableException
       {
   
  -     if (setObj == null) // did we find BeanShell?
  +     if (bshSet == null) // did we find BeanShell?
        {
                throw new InvalidVariableException("BeanShell not found");
        }
        
  -        JMeterVariables vars = getVariables();
  +     JMeterContext jmctx = JMeterContextService.getContext();
  +        JMeterVariables vars = jmctx.getVariables();
   
           String script  = ((CompoundVariable) values[0]).execute();
           String varName = "";
  @@ -96,20 +101,23 @@
           {
   
                        // Pass in some variables
  -             if (currentSampler != null) {
  -                             setObj.invoke(instance, new Object[] 
{"Sampler",currentSampler});
  +             if (currentSampler != null)
  +             {
  +                             bshInvoke(bshSet,"Sampler",currentSampler);  
//$NON-NLS-1$
                }
                        
                        if (previousResult != null)
                        {
  -                             setObj.invoke(instance, new Object[] 
{"SampleResult",previousResult});
  +                             bshInvoke(bshSet,"SampleResult",previousResult);  
//$NON-NLS-1$
                        }
  -                             
  -                     setObj.invoke(instance, new Object[] {"log",log});
  -                     setObj.invoke(instance, new Object[] {"t",this});
  +                     
  +                     // Allow access to context and variables directly
  +                     bshInvoke(bshSet,"ctx",jmctx);  //$NON-NLS-1$
  +                     bshInvoke(bshSet,"vars",vars); //$NON-NLS-1$
  +                     
bshInvoke(bshSet,"threadName",Thread.currentThread().getName());  //$NON-NLS-1$
                        
               // Execute the script
  -            Object bshOut = eval.invoke(instance, new Object[]{script});
  +            Object bshOut = bshInvoke(bshEval,script,null);
                        if (bshOut != null) {
                                resultStr = bshOut.toString();
                        }
  @@ -120,7 +128,7 @@
           }
                catch (Exception ex) // Mainly for bsh.EvalError
                {
  -                     log.warn("",ex);
  +                     log.warn("Error running BSH script",ex);
                }
   
           log.debug("Output="+resultStr);
  @@ -137,12 +145,37 @@
       }
   
        transient private Object instance;
  -     transient private Method setObj;
  -     transient private Method eval;
  +     transient private Method bshSet;
  +     transient private Method bshEval;
  +     transient private Method bshSource;
   
   //TODO move to common class (in jorphan?) so can be shared with other BSH modules
   
  -    private void setupBeanShell()
  +
  +     // Helper method for invoking bsh methods
  +     private Object bshInvoke(Method m, String s, Object o)
  +     {
  +             Object r=null;
  +             try {
  +                     if (o == null)
  +                     {
  +                             r = m.invoke(instance, new Object[] {s});
  +                     }
  +                     else
  +                     {
  +                         r = m.invoke(instance, new Object[] {s, o});
  +                     }
  +             } catch (IllegalArgumentException e) {
  +                     log.error("Error invoking bsh method "+m.getName()+"\n",e);
  +             } catch (IllegalAccessException e) {
  +                     log.error("Error invoking bsh method "+m.getName()+"\n",e);
  +             } catch (InvocationTargetException e) {
  +                     log.error("Error invoking bsh method "+m.getName()+"\n",e);
  +             }               
  +             return r;
  +     }
  +
  +     private void setupBeanShell()
       {    
                ClassLoader loader = Thread.currentThread().getContextClassLoader();
   
  @@ -153,12 +186,17 @@
                Class string = String.class;
                Class object = Object.class;
                        
  -             eval = Interpreter.getMethod(
  -                             "eval",
  +             bshEval = Interpreter.getMethod(
  +                             "eval", //$NON-NLS-1$
                                new Class[] {string});
  -             setObj = Interpreter.getMethod(
  -                             "set",
  +             bshSet = Interpreter.getMethod(
  +                             "set", //$NON-NLS-1$
                                new Class[] {string,object});
  +             
  +             bshSource = Interpreter.getMethod(
  +                             "source", //$NON-NLS-1$
  +                             new Class[] {string});
  +
        }
        catch(ClassNotFoundException e ){
                log.error("Beanshell Interpreter not found");
  @@ -168,6 +206,10 @@
                log.error("Problem starting BeanShell server ",e);
        }
   
  +     // These don't vary between executes, so can be done once
  +     bshInvoke(bshSet,"log",log); //$NON-NLS-1$
  +    String initFile = JMeterUtils.getPropDefault(INIT_FILE,null);
  +     if (initFile!=null) bshInvoke(bshSource,initFile,null);
        }
        
       /* (non-Javadoc)
  
  
  
  No                   revision
  No                   revision
  1.1.2.1   +20 -0     jakarta-jmeter/bin/testfiles/Attic/BeanShellTest.bsh
  
  
  
  
  No                   revision
  No                   revision
  1.6.2.1   +22 -5     
jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/sampler/BeanShellSampler.java
  
  Index: BeanShellSampler.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/sampler/BeanShellSampler.java,v
  retrieving revision 1.6
  retrieving revision 1.6.2.1
  diff -u -r1.6 -r1.6.2.1
  --- BeanShellSampler.java     11 Mar 2004 01:20:18 -0000      1.6
  +++ BeanShellSampler.java     25 Sep 2004 20:59:50 -0000      1.6.2.1
  @@ -18,6 +18,7 @@
   
   package org.apache.jmeter.protocol.java.sampler;
   
  +import java.io.FileNotFoundException;
   import java.io.IOException;
   
   //import bsh.EvalError;
  @@ -26,6 +27,7 @@
   import org.apache.jmeter.samplers.AbstractSampler;
   import org.apache.jmeter.samplers.Entry;
   import org.apache.jmeter.samplers.SampleResult;
  +import org.apache.jmeter.util.JMeterUtils;
   import org.apache.jorphan.logging.LoggingManager;
   import org.apache.jorphan.util.JOrphanUtils;
   import org.apache.log.Logger;
  @@ -42,13 +44,28 @@
       public static final String FILENAME   = "BeanShellSampler.filename"; 
//$NON-NLS-1$
        public static final String SCRIPT     = "BeanShellSampler.query"; //$NON-NLS-1$
        public static final String PARAMETERS = "BeanShellSampler.parameters"; 
//$NON-NLS-1$
  +     public static final String INIT_FILE = "beanshell.sampler.init"; //$NON-NLS-1$
   
       private Interpreter bshInterpreter;
        
        public BeanShellSampler()
        {
  +             String init="";
                try{
                        bshInterpreter = new Interpreter();
  +                     init = JMeterUtils.getPropDefault(INIT_FILE,null);
  +                     if (init != null)
  +                     {
  +                             try
  +                             {
  +                                      bshInterpreter.source(null);
  +                                      bshInterpreter.set("log",log);  //$NON-NLS-1$
  +                             } catch (IOException e){
  +                                     log.warn("Error processing init file "+init+" 
"+e);
  +                             } catch (Exception e){
  +                                     log.warn("Error processing init file "+init+" 
"+e);
  +                             }
  +                     }
                } catch (NoClassDefFoundError e){
                        bshInterpreter=null;
                }
  @@ -98,9 +115,9 @@
                }
   
                        //TODO - set some more variables?
  -                     bshInterpreter.set("Label",getLabel());
  -                     bshInterpreter.set("FileName",getFilename());
  -                     bshInterpreter.set("SampleResult",res);
  +                     bshInterpreter.set("Label",getLabel());  //$NON-NLS-1$
  +                     bshInterpreter.set("FileName",getFilename()); //$NON-NLS-1$
  +                     bshInterpreter.set("SampleResult",res); //$NON-NLS-1$
                        bshInterpreter.set("Parameters",getParameters());// as a 
single line
                        
bshInterpreter.set("bsh.args",JOrphanUtils.split(getParameters()," "));
   
  
  
  
  No                   revision
  No                   revision
  1.14.2.9  +58 -4     jakarta-jmeter/xdocs/usermanual/functions.xml
  
  Index: functions.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/xdocs/usermanual/functions.xml,v
  retrieving revision 1.14.2.8
  retrieving revision 1.14.2.9
  diff -u -r1.14.2.8 -r1.14.2.9
  --- functions.xml     23 Sep 2004 11:44:31 -0000      1.14.2.8
  +++ functions.xml     25 Sep 2004 20:59:50 -0000      1.14.2.9
  @@ -34,7 +34,24 @@
   Parentheses surround the parameters sent to the function.  The actual parameters 
vary from function 
   to function.  Functions that require no parameters can leave off the parentheses.  
The function itself
   is wrapped in ${}.</p>
  -
  +<p>List of functions:</p>
  +<ul>
  +        <li><a href="#__regexFunction">regexFunction - regular expression 
evaluator</a></li>
  +        <li><a href="#__counter">counter</a></li>
  +        <li><a href="#__threadNum">threadNum - get thread number</a></li>
  +        <li><a href="#__intSum">intSum - add variables</a></li>
  +        <li><a href="#__StringFromFile">StringFromFile - read a line from a 
file</a></li>
  +        <li><a href="#__machineName">machineName - get the local machine 
name</a></li>
  +        <li><a href="#__javaScript">JavaScript (Apache Rhino)</a></li>
  +        <li><a href="#__Random">random number</a></li>
  +        <li><a href="#__CSVRead">CSVRead -read from CSV delimited file</a></li>
  +        <li><a href="#__property">read a property</a></li>
  +        <li><a href="#__P">P -read a property</a></li>
  +        <li><a href="#__log">log - log a message</a></li>
  +        <li><a href="#__logn">log - log a message</a></li>
  +        <li><a href="#__BeanShell">BeanShell - run BeanShell</a></li>
  +        <li><a href="#__split">split - Split a string into variables</a></li>
  +</ul>
   
   <subsection name="16.1 What can functions do" anchor="what_can_do">
   <p>There are two kinds of functions: user-defined static values, and built-in 
functions.<br/>
  @@ -175,7 +192,10 @@
   </properties>
   </component>
   
  +<!-- Alternate spelling -->
  +<a name="__StringFromFile"/>
   <component index="16.5.5" name="_StringFromFile">
  +
   <description>
        <p>
        The StringFromFile function can be used to read strings from a text file. 
  @@ -418,7 +438,34 @@
   <description>
        <p>
        The BeanShell function evaluates the script passed to it, and returns the 
result.
  -     </p>
  +</p>
  +<p>
  +Note that a different Interpreter is used for each independent occurence of the 
function
  +in a test script, but the same Interpreter is used for subsequent invocations.
  +This means that variables persist across calls to the function.
  +</p>
  +<p>
  +A single instance of a function may be called from multiple threads.
  +However the function execute() method is synchronised.
  +</p>
  +<p>
  +If the property "beanshell.function.init" is defined, it is passed to the 
Interpreter
  +as the name of a sourced file. This can be used to define common methods and 
variables. There is a
  +sample init file in the bin directory: BeanShellFunction.bshrc.
  +</p>
  +<p>
  +The following variables are set before the script is executed:
  +<ul>
  +<li>log - the logger for the BeanShell function (*)</li>
  +<li>ctx - the current JMeter context variable</li>
  +<li>vars - the current JMeter variables</li>
  +<li>threadName - the threadName</li>
  +<li>Sampler the current Sampler, if any</li>
  +<li>SampleResult - the current SampleResult, if any</li>
  +</ul>
  +(*) means that this is set before the init file, if any, is processed. 
  +Other variables vary from invocation to invocation.
  +</p>
   </description>
   
   <properties>
  @@ -427,6 +474,13 @@
                  computed by this function.</property>
           
   </properties>
  +<p>
  +Example:
  +<pre>
  +${__BeanShell(123*456)} - returns 56088
  +${__BeanShell(source("function.bsh"))} - processes the script in function.bsh
  +</pre>
  +</p>
   </component>
   
   <component index="16.5.14" name="__split">
  
  
  
  1.87.2.7  +29 -18    jakarta-jmeter/xdocs/usermanual/component_reference.xml
  
  Index: component_reference.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/xdocs/usermanual/component_reference.xml,v
  retrieving revision 1.87.2.6
  retrieving revision 1.87.2.7
  diff -u -r1.87.2.6 -r1.87.2.7
  --- component_reference.xml   5 Jun 2004 14:44:28 -0000       1.87.2.6
  +++ component_reference.xml   25 Sep 2004 20:59:50 -0000      1.87.2.7
  @@ -403,28 +403,37 @@
   
   <component name="BeanShell Sampler" index="15.1.9" screenshot="">
   <center><h2>(Beta Code)</h2></center>
  -     <description><p>This sampler allows you to write a sampler using the BeanShell 
scripting language.<br></br>
  -             
  -             <br></br>
  -             Please note that the BeanShell jar file is not included with JMeter; 
it needs to be separately downloaded.
  -             For full details on using BeanShell, please see the BeanShell web-site 
at http://www.beanshell.org/.
  -             
  -             </p>
  +     <description><p>This sampler allows you to write a sampler using the BeanShell 
scripting language.              
  +</p><p>
  +             <b>Please note that the BeanShell jar file is not included with 
JMeter; it needs to be separately downloaded.
  +             <br/>
  +        For full details on using BeanShell, please see the BeanShell web-site at 
http://www.beanshell.org/.</b>
  +</p>
        </description>
   <properties>
        <property name="Name" required="no">Descriptive name for this controller that 
is shown in the tree.</property>
        <property name="Parameters" required="no">List of parameters to be passed to 
the script file or the script.</property>
  -     <property name="Script File" required="no">Name of a file to be used as a 
BeanShell script</property>
  -     <property name="Script" required="no">Script to be passed to 
BeanShell</property>
  +     <property name="Script File" required="(yes)">Name of a file to be used as a 
BeanShell script</property>
  +     <property name="Script" required="(yes)">Script to be passed to 
BeanShell</property>
   </properties>
  -<p>If a script file is supplied, that will be used, otherwise the script will be 
used.</p>
  -             <p>Before invoking the script, some variable are set up in the 
BeanShell interpreter:
  +<p>
  +N.B. Each Sampler instance has its own BeanShell interpeter,
  +and Samplers are only called from a single thread
  +</p><p>
  +If the property "beanshell.sampler.init" is defined, it is passed to the Interpreter
  +as the name of a sourced file.
  +This can be used to define common methods and variables. 
  +There is a sample init file in the bin directory: BeanShellFunction.bshrc.
  +</p><p>
  +If a script file is supplied, that will be used, otherwise the script will be 
used.</p>
  +             <p>Before invoking the script, some variables are set up in the 
BeanShell interpreter:
                        </p>
                                <p>The contents of the Parameters field is put into 
the variable "Parameters".
                        The string is also split into separate tokens using a single 
space as the separator, and the resulting list
                        is stored in the String array bsh.args.</p>
                        <p>The full list of variables that is set up is as follows:</p>
                <ul>
  +             <li>log - the Logger</li>
                <li>Label - the Sampler label</li>
                <li>FileName - the file name, if any</li>
                <li>Parameters - text from the Parameters field</li>
  @@ -446,12 +455,14 @@
                                methods in the SampleResult. For example, the script 
has access to the methods
                                setStopThread(boolean) and setStopTest(boolean).
                                
  -                             Here is a simple example script:</p>
  +                             Here is a simple (not very useful!) example script:</p>
                                
   <pre>
  -     if (bsh.args[0].equalsIgnoreCase("StopThread")) {
  -         SampleResult.StopThread(bsh.args[1]);
  -     }
  +if (bsh.args[0].equalsIgnoreCase("StopThread")) {
  +    log.info("Stop Thread detected!");
  +    SampleResult.StopThread(bsh.args[1]);
  +}
  +return "Data from sample with Label "+Label;
   </pre>
   </component>
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to