Author: mrdon
Date: Sun Aug  7 00:11:49 2005
New Revision: 230648

URL: http://svn.apache.org/viewcvs?rev=230648&view=rev
Log:
 * Added global Ti configuration system which allows global properties
   to be set:
    1. Set in a builtin defaults properties file
    2. Set as web.xml init parameters
    3. Set as a ti.properties file
 * Integrated global properties into spring config
 * Added experimental "devMode" which allows applications to be
   developed without any manual compilation or tag processing
 * Added automatic processing of xdoclet tags on every request when in
   dev mode
 * Added automatic compilation of classes when in dev mode and src dir
   is specified

Added:
    
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/CompilingObjectFactory.java
   (with props)
    
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/ProcessTagsInDevMode.java
   (with props)
    struts/sandbox/trunk/ti/src/java/ti-defaults.properties
Modified:
    struts/sandbox/trunk/ti/project.xml
    struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTags.java
    struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTagsTask.java
    
struts/sandbox/trunk/ti/src/java/org/apache/ti/config/spring-config-servlet.xml
    
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/InitXWork.java
    
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/chain-config-servlet.xml
    struts/sandbox/trunk/ti/src/java/org/apache/ti/servlet/StrutsTiServlet.java

Modified: struts/sandbox/trunk/ti/project.xml
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/project.xml?rev=230648&r1=230647&r2=230648&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/project.xml (original)
+++ struts/sandbox/trunk/ti/project.xml Sun Aug  7 00:11:49 2005
@@ -255,6 +255,52 @@
     </dependency>
     
     <dependency>
+      <groupId>commons-jci</groupId>
+      <artifactId>commons-jci</artifactId>
+      <version>SNAPSHOT</version>
+      <properties>
+        <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>
+
+<!--
+    <dependency>
+      <groupId>janino</groupId>
+      <artifactId>janino</artifactId>
+      <version>2.3.7</version>
+      <properties>
+        <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>
+-->
+    <dependency>
+      <groupId>eclipse</groupId>
+      <artifactId>jdtcore</artifactId>
+      <version>3.1.0</version>
+      <properties>
+        <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>1.0</version>
+      <properties>
+        <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>
+
+  <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>2.1</version>
+      <properties>
+        <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>
+
+   <dependency>
       <groupId>ant</groupId>
       <artifactId>ant</artifactId>
       <version>1.6.5</version>

Modified: struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTags.java
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTags.java?rev=230648&r1=230647&r2=230648&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTags.java 
(original)
+++ struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTags.java Sun 
Aug  7 00:11:49 2005
@@ -38,7 +38,7 @@
     private static final Log log = LogFactory.getLog(ProcessTags.class);
     private static final String SEP = File.separator;
 
-    public void setXDocletParser(XDocletParser parser) {
+    public void setXdocletParser(XDocletParser parser) {
         this.xdocletParser = parser;
     }
 

Modified: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTagsTask.java
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTagsTask.java?rev=230648&r1=230647&r2=230648&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTagsTask.java 
(original)
+++ struts/sandbox/trunk/ti/src/java/org/apache/ti/config/ProcessTagsTask.java 
Sun Aug  7 00:11:49 2005
@@ -49,7 +49,7 @@
         XDocletParser parser = new XDocletParser();
         parser.init();
         ProcessTags pt = new ProcessTags();
-        pt.setXDocletParser(parser);
+        pt.setXdocletParser(parser);
 
         List outputs = new ArrayList();
         outputs.add(new OutputType("org/apache/ti/config/xdocletToXWork.vm", 
"xwork.xml", false));

Modified: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/config/spring-config-servlet.xml
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/org/apache/ti/config/spring-config-servlet.xml?rev=230648&r1=230647&r2=230648&view=diff
==============================================================================
--- 
struts/sandbox/trunk/ti/src/java/org/apache/ti/config/spring-config-servlet.xml 
(original)
+++ 
struts/sandbox/trunk/ti/src/java/org/apache/ti/config/spring-config-servlet.xml 
Sun Aug  7 00:11:49 2005
@@ -19,14 +19,36 @@
   
   <bean id="controllerContext" 
class="org.apache.ti.processor.ControllerContext" />
   
+  <bean id="javaCompiler" 
class="org.apache.commons.jci.compilers.eclipse.EclipseJavaCompiler" />
+
+  <bean id="compilingObjectFactory" 
class="org.apache.ti.processor.CompilingObjectFactory">
+    <property name="javaCompiler" ref="javaCompiler" />
+    <property name="srcPath"><value>${ti.srcPath}</value></property>
+  </bean>
+  
+  <bean id="processTagsInDevMode" 
class="org.apache.ti.processor.chain.ProcessTagsInDevMode">
+    <property name="processTags" ref="processTags" />
+    <property name="devMode"><value>${ti.devMode}</value></property>
+    <property name="srcPath"><value>${ti.srcPath}</value></property>
+    <property name="classesPath"><value>${ti.classesPath}</value></property>
+  </bean>
+  
   <bean id="actionProxyFactory" 
class="org.apache.ti.processor.ControllerActionProxyFactory" />
   
+  <bean id="processTags" class="org.apache.ti.config.ProcessTags">
+    <property name="xdocletParser" ref="xdocletParser" />
+  </bean>
+
+  <bean id="xdocletParser" class="org.apache.ti.config.XDocletParser" 
init-method="init" />
+  
   <!-- Chain commands that need DI -->
   <bean id="createActionMapping" 
class="org.apache.ti.processor.chain.CreateActionMapping">
     <property name="actionMapper" ref="actionMapper" />
   </bean>
   <bean id="initXWork" class="org.apache.ti.processor.chain.InitXWork">
     <property name="actionProxyFactory" ref="actionProxyFactory" />
+    <property name="compilingObjectFactory" ref="compilingObjectFactory" />
+    <property name="devMode"><value>${ti.devMode}</value></property>
   </bean>
   <bean id="initControllerContext" 
class="org.apache.ti.processor.chain.InitControllerContext">
     <property name="controllerContext" ref="controllerContext" />

Added: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/CompilingObjectFactory.java
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/CompilingObjectFactory.java?rev=230648&view=auto
==============================================================================
--- 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/CompilingObjectFactory.java
 (added)
+++ 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/CompilingObjectFactory.java
 Sun Aug  7 00:11:49 2005
@@ -0,0 +1,69 @@
+/*
+ * $Id: ControllerContext.java 230400 2005-08-05 05:13:54Z martinc $
+ *
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ti.processor;
+
+import org.apache.ti.config.*;
+import java.util.*;
+import java.io.*;
+
+import com.opensymphony.xwork.ObjectFactory;
+import com.opensymphony.xwork.Action;
+
+import java.io.File;
+
+import org.apache.commons.jci.CompilingClassLoader;
+import org.apache.commons.jci.compilers.JavaCompiler;
+
+import org.apache.commons.logging.*;
+
+
+/**
+ * Builds actions from the config.  If an Action is not created, it is assumed 
to be a Controller.
+ */
+public class CompilingObjectFactory extends ObjectFactory {
+
+    private static final Log log = 
LogFactory.getLog(CompilingObjectFactory.class);
+    private CompilingClassLoader cl;
+    private JavaCompiler compiler;
+
+    public void setJavaCompiler(JavaCompiler jc) {
+        this.compiler = jc;
+    }    
+    
+
+    public void setSrcPath(String src) {
+        if (src != null && src.length() > 0) {
+            File file = new File(src);
+            if (file.exists()) {
+                cl = new CompilingClassLoader(
+                        Thread.currentThread().getContextClassLoader(), 
+                        file,
+                        compiler);
+            } else {
+                log.error("Specified source directory, "+src+" doesn't exist");
+            }
+        }    
+    }
+    
+    public Class getClassInstance(String className) throws 
ClassNotFoundException {
+        log.info("Looking up class "+className+" in compiling classloader");
+       
+        Class cls = cl.loadClass(className);
+        return cl.loadClass(className);
+    }    
+}

Propchange: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/CompilingObjectFactory.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/InitXWork.java
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/InitXWork.java?rev=230648&r1=230647&r2=230648&view=diff
==============================================================================
--- 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/InitXWork.java 
(original)
+++ 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/InitXWork.java 
Sun Aug  7 00:11:49 2005
@@ -17,6 +17,8 @@
  */
 package org.apache.ti.processor.chain;
 
+import org.apache.ti.processor.CompilingObjectFactory;
+
 import org.apache.commons.chain.Command;
 import org.apache.commons.chain.Context;
 import org.apache.commons.chain.web.WebContext;
@@ -34,17 +36,32 @@
 
     private static final Log log = LogFactory.getLog(InitXWork.class);
 
+    protected CompilingObjectFactory clObjectFactory;
     protected ActionProxyFactory actionProxyFactory;
+    protected boolean devMode = false;
 
     public void setActionProxyFactory(ActionProxyFactory factory) {
         this.actionProxyFactory = factory;
     }
 
+    public void setCompilingObjectFactory(CompilingObjectFactory fac) {
+        this.clObjectFactory = fac;
+    }
+
+    public void setDevMode(boolean mode) {
+        this.devMode = mode;
+    }    
+
     public boolean execute(Context origctx) {
         log.debug("Initializing XWork");
         WebContext ctx = (WebContext) origctx;
 
         ActionProxyFactory.setFactory(actionProxyFactory);
+
+        if (devMode) {
+            log.info("Dev mode enabled, using compiling classloader");
+            ObjectFactory.setObjectFactory(clObjectFactory);
+        }
 
         return false;
     }

Added: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/ProcessTagsInDevMode.java
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/ProcessTagsInDevMode.java?rev=230648&view=auto
==============================================================================
--- 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/ProcessTagsInDevMode.java
 (added)
+++ 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/ProcessTagsInDevMode.java
 Sun Aug  7 00:11:49 2005
@@ -0,0 +1,88 @@
+/*
+ * $Id: ProcessTagsInDevMode.java 230578 2005-08-06 20:21:45Z mrdon $
+ *
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ti.processor.chain;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.ti.processor.*;
+import org.apache.ti.config.*;
+
+import org.apache.commons.chain.Command;
+import org.apache.commons.chain.Context;
+import org.apache.commons.chain.web.WebContext;
+
+import com.opensymphony.xwork.ActionProxyFactory;
+import com.opensymphony.xwork.ObjectFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *  Initializes XWork by replacing default factories
+ */
+public class ProcessTagsInDevMode implements Command {
+
+    private static final Log log = 
LogFactory.getLog(ProcessTagsInDevMode.class);
+
+    protected boolean devMode = false;
+    private ProcessTags processTags;
+    private List outputs;
+    private File src;
+    private File classes;
+    private String controllerSourceName = "Controller.java";
+
+    public void setProcessTags(ProcessTags pt) {
+        this.processTags = pt;
+        outputs = new ArrayList();
+        outputs.add(new OutputType("org/apache/ti/config/xdocletToXWork.vm", 
"xwork.xml", false));
+        outputs.add(new 
OutputType("org/apache/ti/config/xdocletToValidation.vm", 
"$c-$a-validation.xml", true));
+    }    
+
+    public void setControllerSourceName(String name) {
+        this.controllerSourceName = name;
+    }    
+    
+    public void setClassesPath(String dest) {
+        classes = new File(dest);
+    }    
+   
+    public void setSrcPath(String src) {
+        if (src != null && src.length() > 0) {
+            File file = new File(src);
+            if (file.exists()) {
+                this.src = file;
+            } else {
+                log.error("Specified source directory, "+src+" doesn't exist");
+            }
+        }    
+    }
+ 
+    public void setDevMode(boolean mode) {
+        this.devMode = mode;
+    }    
+
+   
+    public boolean execute(Context ctx) throws Exception {
+        if (devMode) {
+            processTags.process(src, controllerSourceName, classes, outputs);
+        }
+        
+        return false;
+    }    
+}

Propchange: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/ProcessTagsInDevMode.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/chain-config-servlet.xml
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/chain-config-servlet.xml?rev=230648&r1=230647&r2=230648&view=diff
==============================================================================
--- 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/chain-config-servlet.xml
 (original)
+++ 
struts/sandbox/trunk/ti/src/java/org/apache/ti/processor/chain/chain-config-servlet.xml
 Sun Aug  7 00:11:49 2005
@@ -38,6 +38,7 @@
 
     <chain     name="start" >
       <command name="createActionMapping"  />
+      <command name="processTagsInDevMode"  />
       <command name="populateContextForRequest" 
className="org.apache.ti.processor.chain.PopulateContextForRequest"/>
       <command name="populateContextForWebWork" 
className="org.apache.ti.processor.chain.webwork.PopulateContextForWebWork" />
       <command name="createWebWorkActionProxy" 
className="org.apache.ti.processor.chain.webwork.CreateWebWorkActionProxy"/>

Modified: 
struts/sandbox/trunk/ti/src/java/org/apache/ti/servlet/StrutsTiServlet.java
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/org/apache/ti/servlet/StrutsTiServlet.java?rev=230648&r1=230647&r2=230648&view=diff
==============================================================================
--- struts/sandbox/trunk/ti/src/java/org/apache/ti/servlet/StrutsTiServlet.java 
(original)
+++ struts/sandbox/trunk/ti/src/java/org/apache/ti/servlet/StrutsTiServlet.java 
Sun Aug  7 00:11:49 2005
@@ -20,17 +20,14 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import javax.servlet.ServletException;
 import javax.servlet.UnavailableException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletContext;
 
 import org.apache.commons.chain.web.servlet.ServletWebContext;
 import org.apache.commons.digester.Digester;
@@ -39,6 +36,7 @@
 import org.apache.ti.processor.RequestProcessor;
 import org.springframework.beans.factory.BeanFactory;
 import org.springframework.beans.factory.xml.XmlBeanFactory;
+import org.springframework.beans.factory.config.*;
 import org.springframework.core.io.UrlResource;
 import org.xml.sax.SAXException;
 
@@ -51,12 +49,15 @@
     public static final String SERVLET_MAPPINGS_KEY = "servletMappings";
 
     protected String springConfig = 
"org/apache/ti/config/spring-config-servlet.xml";
+    protected String tiConfig = "ti.properties";
+    protected String tiDefaultsConfig = "ti-defaults.properties";
 
     protected static Log log = LogFactory.getLog(StrutsTiServlet.class);
 
     protected BeanFactory beanFactory = null;
     protected List servletMappings = new ArrayList();
     protected RequestProcessor processor = null;
+    protected Properties tiProps = new Properties();
 
     public void destroy() {
 
@@ -77,21 +78,69 @@
     public void init() throws ServletException {
         super.init();
 
+        initProperties();
         initSpring();
         initServlet();
 
         Map initParameters = new HashMap();
-        String key;
-        for (Enumeration e = getInitParameterNames(); e.hasMoreElements();) {
-            key = (String) e.nextElement();
-            initParameters.put(key, getInitParameter(key));
-        }
+        initParameters.putAll(tiProps);
         initParameters.put(SERVLET_MAPPINGS_KEY, servletMappings);
 
         processor = (RequestProcessor) beanFactory.getBean("requestProcessor");
         processor.init(initParameters, new 
ServletWebContext(getServletContext(), null, null));
     }
 
+    protected void initProperties() throws ServletException {
+        String s = getInitParameter("tiConfig");
+        if (s != null) {
+            tiConfig = s;
+        }    
+        try {
+            // First, load defaults
+            tiProps.load(resolve(tiDefaultsConfig).openStream());
+
+            // Next, load from web.xml
+            String key;
+            for (Enumeration e = getInitParameterNames(); 
e.hasMoreElements();) {
+                key = (String) e.nextElement();
+                tiProps.put("ti."+key, getInitParameter(key));
+            }
+            
+            // Finally, load from user's properties file 
+            URL resource = resolve(tiConfig, false);
+            if (resource != null) {
+                tiProps.load(resource.openStream());
+             }
+        } catch(IOException ex) {
+            log.error("Unable to load properties", ex);
+            throw new UnavailableException("Unable to load 
properties:"+ex.getMessage());
+        }
+
+        // Resolve all properties ending with Path against the servlet 
context, if possibile
+        String key, value;
+        String realPath;
+        ServletContext ctx = getServletContext();
+        for (Iterator i = tiProps.keySet().iterator(); i.hasNext(); ) {
+            key = (String) i.next();
+            if (key.startsWith("ti.") && key.endsWith("Path")) {
+                value = tiProps.getProperty(key);
+                if (value != null && value.length() > 0) {
+                    realPath = ctx.getRealPath(value);
+                    if (realPath != null) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("Resolved "+value+" as "+realPath+" for 
key "+key);
+                        }    
+                        tiProps.setProperty(key, realPath);
+                    } else {
+                        log.info("Unable to resolve path "+value+" for key 
"+key);
+                    }
+                }    
+            }
+        }    
+    }    
+                
+        
+
     protected void initSpring() throws ServletException {
         // Parse the configuration file specified by path or resource
         try {
@@ -103,6 +152,14 @@
             URL resource = resolve(springConfig);
             log.info("Loading spring configuration from " + resource);
             beanFactory = new XmlBeanFactory(new UrlResource(resource));
+
+            // create placeholderconfigurer to bring in some property
+            // values from a Properties file
+            PropertyPlaceholderConfigurer cfg = new 
PropertyPlaceholderConfigurer();
+            cfg.setProperties(tiProps);
+            // now actually do the replacement
+            cfg.postProcessBeanFactory((XmlBeanFactory)beanFactory);
+            
         } catch (Exception e) {
             String msg = "Exception loading spring configuration";
             log.error(msg, e);
@@ -129,6 +186,10 @@
 
 
     protected URL resolve(String path) throws ServletException {
+        return resolve(path, true);
+    }    
+    
+    protected URL resolve(String path, boolean force) throws ServletException {
         URL resource = null;
         ClassLoader loader = Thread.currentThread().getContextClassLoader();
         if (loader == null) {
@@ -148,9 +209,11 @@
                 }
                 Enumeration e = loader.getResources(path);
                 if (!e.hasMoreElements()) {
-                    String msg = "Resource not found: " + path;
-                    log.error(msg);
-                    throw new UnavailableException(msg);
+                    if (force) {
+                        String msg = "Resource not found: " + path;
+                        log.error(msg);
+                        throw new UnavailableException(msg);
+                    }    
                 } else {
                     resource = (URL) e.nextElement();
                     if (e.hasMoreElements()) {
@@ -160,8 +223,10 @@
                 }
             }
         } catch (Exception e) {
-            log.error(e);
-            throw new UnavailableException("Unable to load resource at " + 
path);
+            if (force) {
+                log.error("Unable to load resource at " + path, e);
+                throw new UnavailableException("Unable to load resource at " + 
path);
+            }    
         }
 
         return resource;

Added: struts/sandbox/trunk/ti/src/java/ti-defaults.properties
URL: 
http://svn.apache.org/viewcvs/struts/sandbox/trunk/ti/src/java/ti-defaults.properties?rev=230648&view=auto
==============================================================================
--- struts/sandbox/trunk/ti/src/java/ti-defaults.properties (added)
+++ struts/sandbox/trunk/ti/src/java/ti-defaults.properties Sun Aug  7 00:11:49 
2005
@@ -0,0 +1,3 @@
+ti.devMode=false
+ti.srcPath=
+ti.classesPath=/WEB-INF/classes



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

Reply via email to