kward       2002/12/04 22:50:23

  Modified:    java/scratchpad/admin/src/org/apache/xindice/admin
                        XindiceAdmin.java
               java/scratchpad/admin/src/org/apache/xindice/admin/commandline
                        BaseCommand.java BasePrompt.java
                        CommandRegister.java Prompt.java XindiceTools.java
               java/scratchpad/admin/src/org/apache/xindice/admin/commands
                        CreateCommand.java DropCommand.java
                        InfoCommand.java ListCommand.java
                        RunScriptCommand.java UseCommand.java
  Log:
  adding SSL support
  
  Revision  Changes    Path
  1.3       +97 -2     
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/XindiceAdmin.java
  
  Index: XindiceAdmin.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/XindiceAdmin.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- XindiceAdmin.java 9 Nov 2002 01:24:55 -0000       1.2
  +++ XindiceAdmin.java 5 Dec 2002 06:50:23 -0000       1.3
  @@ -60,6 +60,20 @@
    */
   
   import org.apache.xindice.admin.commandline.ShellPrompt;
  +import org.apache.xindice.admin.xmlrpc.XindiceX509TrustManager;
  +import org.apache.xmlrpc.XmlRpc;
  +import org.apache.xmlrpc.XmlRpcClient;
  +
  +import java.util.Hashtable;
  +import java.util.Vector;
  +import java.security.Security;
  +
  +import com.sun.net.ssl.KeyManager;
  +import com.sun.net.ssl.SSLContext;
  +import com.sun.net.ssl.HostnameVerifier;
  +import com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnection;
  +
  +import javax.net.ssl.SSLSocketFactory;
   
   /**
    * Command line tools
  @@ -67,8 +81,89 @@
    */
   
   public class XindiceAdmin {
  +    protected static XmlRpcClient client;
  +    protected static String url = "http://localhost:8080/xindice-1.1b";;
  +    public static String DB = null;
        public static void main(String args[]) {
  -             ShellPrompt prompt = new ShellPrompt("Xindice ");
  +        XmlRpc.setEncoding("UTF8");
  +
  +        //url = "https://localhost:8443/xindice-1.1b";;
  +        //XmlRpc.setKeepAlive(true);
  +        //XmlRpc.setDebug(true);
  +
  +        if( url.startsWith("https") ) {
  +           System.out.println("Setting up SSL configuration...");
  +           try {
  +              setupSSL();
  +           } catch(Exception e) {
  +              System.out.println(e);
  +           }
  +        }
  +
  +        try {
  +            XmlRpc.setDriver("xerces");
  +        } catch(Exception e) {
  +            System.out.println("XML-RPC requires Xerces for UTF-8 support.");
  +        }
  +
  +        try {
  +           client = new XmlRpcClient( url );
  +        } catch(Exception e) {
  +
  +        }
  +
  +        DB = "/db";
  +             ShellPrompt prompt = new ShellPrompt("Xindice");
                prompt.start();
        }
  +
  +    private static void setupSSL() throws Exception {
  +       //set up system properties
  +       System.setProperty("java.protocol.handler.pkgs", 
"com.sun.net.ssl.internal.www.protocol");
  +       System.setProperty("com.sun.net.ssl.dhKeyExchangeFix", "true");
  +
  +       Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
  +
  +       //needed for untrusted sites - completely optional
  +       XindiceX509TrustManager tm = new XindiceX509TrustManager();
  +       KeyManager[] km = null;
  +       XindiceX509TrustManager[] tma = { tm };
  +       SSLContext sc = SSLContext.getInstance("SSL");
  +       sc.init(km,tma,new java.security.SecureRandom());
  +       SSLSocketFactory sf1 = sc.getSocketFactory();
  +       HttpsURLConnection.setDefaultSSLSocketFactory(sf1);
  +
  +  //Added to allow sites with different names then are on the certificate
  +  //completely optional
  +  HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
  +    public boolean verify(String urlHostname, String certHostname) {
  +     return true;
  +    }
  +   }
  +  );
  + }
  +
  +    public static Hashtable run(Hashtable message) throws Exception {
  +
  +        Vector params = new Vector();
  +        params.addElement(message);
  +        Hashtable result = new Hashtable();
  +        try {
  +            result = (Hashtable) client.execute("run", params);
  +        } catch(Exception e){
  +            System.out.println(e.getMessage());
  +            return null;
  +        }
  +
  +        return (result);
  +
  +   }
  +
  +    public static String getDB() {
  +        return DB;
  +    }
  +
  +    public static void setDB(String col) {
  +        DB = col;
  +    }
   }
  
  
  
  1.4       +14 -36    
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/BaseCommand.java
  
  Index: BaseCommand.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/BaseCommand.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- BaseCommand.java  9 Nov 2002 06:21:08 -0000       1.3
  +++ BaseCommand.java  5 Dec 2002 06:50:23 -0000       1.4
  @@ -59,8 +59,7 @@
    * $Id$
    */
   
  -import org.apache.xmlrpc.XmlRpc;
  -import org.apache.xmlrpc.XmlRpcClient;
  +import org.apache.xindice.admin.utility.StopWatch;
   
   import java.util.Iterator;
   import java.util.Vector;
  @@ -78,8 +77,6 @@
        protected CommandRegister register_;
        protected String help_;
   
  -    protected XmlRpcClient client;
  -
        protected static BasePrompt prompt = null;
   
        public BaseCommand(String name, int numArgs, String help) {
  @@ -87,7 +84,7 @@
                numArgs_ = numArgs;
                help_ = help;
        }
  -     
  +
        /**
         * This method is called by the CommandRegister whenever a new command 
is registered
         */
  @@ -99,7 +96,7 @@
        public CommandRegister getRegister() {
                return register_;
        }
  -     
  +
   
        static void setPrompt(BasePrompt prompt) {
                BaseCommand.prompt = prompt;
  @@ -125,14 +122,15 @@
        }
   
        public abstract void execute(String args[]);
  -     
  +
        /**
         * This method is called internally whenever a command is executed to
         * check the arguments. After checking arguments, it will call the
         * execute(String[]) method for the specific command.
         */
        public void execute(Iterator iter) {
  -
  +        StopWatch stopwatch = new StopWatch();
  +        stopwatch.start();
           String args[] = null;
                if (numArgs_ != -1) {
                        args = new String[numArgs_];
  @@ -150,7 +148,7 @@
                                return;
                        }
   
  -             } else {        
  +             } else {
                        Vector vector = new Vector(10);
                        while(iter.hasNext()) {
                                vector.add(iter.next());
  @@ -158,38 +156,18 @@
                        args = new String[vector.size()];
                        vector.toArray(args);
                }
  +
                execute(args);
  +        stopwatch.stop();
  +        prompt.out.println("\tElapsed Time: "+stopwatch.elapsed()+" ms");
  +
        }
  -     
  +
        /**
         * Return a the help string for this command.
         */
  -     public String getHelp() { 
  +     public String getHelp() {
                return "usage: " + name_ + " " + help_;
        }
  -
  -    public Hashtable run(Hashtable message) {
  -        XmlRpc.setEncoding("UTF8");
  -
  -        try {
  -            XmlRpc.setDriver("xerces");
  -        } catch(Exception e) {
  -            System.out.println("XML-RPC requires Xerces for UTF-8 support.");
  -        }
  -        try {
  -            client = new XmlRpcClient("http://localhost:8080/Xindice";);
  -        } catch(Exception e){
  -            System.out.println("Error connecting to Xindice");
  -        }
  -        Vector params = new Vector();
  -        params.addElement(message);
  -        Hashtable result = new Hashtable();
  -        try {
  -            result = (Hashtable) client.execute("run", params);
  -        } catch(Exception e){
  -            prompt.out.println(e);
  -        }
  -        return (result);
  -   }
   
   }
  
  
  
  1.4       +3 -3      
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/BasePrompt.java
  
  Index: BasePrompt.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/BasePrompt.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- BasePrompt.java   9 Nov 2002 06:21:08 -0000       1.3
  +++ BasePrompt.java   5 Dec 2002 06:50:23 -0000       1.4
  @@ -109,8 +109,8 @@
                register_.add(command);
        }
        
  -     public void registerPackage(XindiceToolAssemblyInterface ci) {
  -             register_.add(ci);
  +     public void registerPackage(XindiceToolAssembly xta) {
  +             register_.add(xta);
        }
   
        public void exit() {
  
  
  
  1.4       +3 -3      
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/CommandRegister.java
  
  Index: CommandRegister.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/CommandRegister.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- CommandRegister.java      9 Nov 2002 06:21:08 -0000       1.3
  +++ CommandRegister.java      5 Dec 2002 06:50:23 -0000       1.4
  @@ -83,7 +83,7 @@
                put(command.getName(), command);
        }
   
  -     public void add(XindiceToolAssemblyInterface xta) {
  +     public void add(XindiceToolAssembly xta) {
                String key = xta.getClass().getName();
                if (packages_.contains(key)) {
                        System.err.println("attempt to register duplicate 
package");
  @@ -100,7 +100,7 @@
        public void exit() {
                Iterator iter = packages_.values().iterator();
                while (iter.hasNext()) {
  -                     XindiceToolAssemblyInterface ci = 
(XindiceToolAssemblyInterface)iter.next();
  +                     XindiceToolAssembly ci = 
(XindiceToolAssembly)iter.next();
                        ci.exit();
                }
        }
  
  
  
  1.3       +1 -1      
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/Prompt.java
  
  Index: Prompt.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/Prompt.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Prompt.java       9 Nov 2002 06:21:08 -0000       1.2
  +++ Prompt.java       5 Dec 2002 06:50:23 -0000       1.3
  @@ -8,7 +8,7 @@
   public interface Prompt {
   
        public void registerCommand(Command command);
  -     public void registerPackage(XindiceToolAssemblyInterface xta);
  +     public void registerPackage(XindiceToolAssembly xta);
        public void start();
        public void exit();
   }
  
  
  
  1.4       +5 -4      
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/XindiceTools.java
  
  Index: XindiceTools.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commandline/XindiceTools.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- XindiceTools.java 9 Nov 2002 06:21:08 -0000       1.3
  +++ XindiceTools.java 5 Dec 2002 06:50:23 -0000       1.4
  @@ -68,7 +68,7 @@
    * Author: kward <[EMAIL PROTECTED]>
    */
   
  -class XindiceTools implements XindiceToolAssemblyInterface {
  +class XindiceTools implements XindiceToolAssembly {
   
        public Command[] getCommands() {
                Command[] commands = {
  @@ -78,9 +78,10 @@
               new InfoCommand(),
               new ListCommand(),
               new UseCommand(),
  -            new AddCommand(),
  +            //new AddCommand(),
               new CreateCommand(),
  -            new QueryCommand(),
  +            new DropCommand(),
  +            //new QueryCommand(),
               new RunScriptCommand(),
               new ExitCommand()
                };
  
  
  
  1.5       +25 -3     
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/CreateCommand.java
  
  Index: CreateCommand.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/CreateCommand.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- CreateCommand.java        10 Nov 2002 19:51:30 -0000      1.4
  +++ CreateCommand.java        5 Dec 2002 06:50:23 -0000       1.5
  @@ -61,9 +61,11 @@
   
   import java.util.Iterator;
   import java.util.Set;
  +import java.util.Hashtable;
   
   import org.apache.xindice.admin.commandline.BaseCommand;
   import org.apache.xindice.admin.commandline.Command;
  +import org.apache.xindice.admin.XindiceAdmin;
   
   /**
    * Command for creating collections
  @@ -77,8 +79,28 @@
        }
   
        public void execute(String args[]) {
  -             String collection = args[0];
  -             prompt.out.println("Created collection " + collection);
  +
  +        Hashtable message = new Hashtable();
  +        Hashtable result = null;
  +
  +        String collection = args[0];
  +
  +        message.put("message", "CreateCollection");
  +        message.put("collection", 
org.apache.xindice.admin.XindiceAdmin.getDB() );
  +        message.put("name", collection);
  +
  +        try {
  +            result = XindiceAdmin.run(message);
  +        } catch(Exception e) {
  +            return;
  +        }
  +
  +        if(result == null) {
  +            prompt.out.println("\terror creating collection");
  +            return;
  +        } else {
  +            prompt.out.println("\tCreated collection " + collection);
  +        }
   
        }
   
  
  
  
  1.2       +26 -2     
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/DropCommand.java
  
  Index: DropCommand.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/DropCommand.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DropCommand.java  10 Nov 2002 19:51:30 -0000      1.1
  +++ DropCommand.java  5 Dec 2002 06:50:23 -0000       1.2
  @@ -61,9 +61,11 @@
   
   import java.util.Iterator;
   import java.util.Set;
  +import java.util.Hashtable;
   
   import org.apache.xindice.admin.commandline.BaseCommand;
   import org.apache.xindice.admin.commandline.Command;
  +import org.apache.xindice.admin.XindiceAdmin;
   
   /**
    * Command for creating collections
  @@ -73,10 +75,32 @@
   public class DropCommand extends BaseCommand {
   
        public DropCommand() {
  -             super("drop", 2, "collection|document" + "\ndrops the specified 
collection|document");
  +             super("drop", 2, "collection|index|document" + "\ndrops the 
specified collection|document");
        }
   
        public void execute(String args[]) {
  +
  +        Hashtable message = new Hashtable();
  +        Hashtable result = null;
  +
  +        String collection = args[1];
  +
  +        message.put("message", "RemoveCollection");
  +        message.put("collection", XindiceAdmin.getDB());
  +        message.put("name", collection);
  +
  +        try {
  +            result = XindiceAdmin.run(message);
  +        } catch(Exception e) {
  +            return;
  +        }
  +
  +        if(result == null) {
  +            prompt.out.println("\terror dropping collection");
  +            return;
  +        } else {
  +            prompt.out.println("\tdropped collection " + collection);
  +        }
   
        }
   
  
  
  
  1.2       +29 -18    
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/InfoCommand.java
  
  Index: InfoCommand.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/InfoCommand.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- InfoCommand.java  9 Nov 2002 06:19:24 -0000       1.1
  +++ InfoCommand.java  5 Dec 2002 06:50:23 -0000       1.2
  @@ -1,6 +1,7 @@
   package org.apache.xindice.admin.commands;
   
   import org.apache.xindice.admin.commandline.BaseCommand;
  +import org.apache.xindice.admin.XindiceAdmin;
   import org.apache.xmlrpc.XmlRpc;
   import org.apache.xmlrpc.XmlRpcClient;
   import java.util.Hashtable;
  @@ -19,9 +20,34 @@
   
        public void execute(String args[]) {
   
  +        Hashtable message = new Hashtable();
  +        message.put("message", "GetServerVersion");
  +        Hashtable result = null;
  +        try {
  +            result = XindiceAdmin.run(message);
  +        } catch(Exception e) {
  +            return;
  +        }
  +
  +        if(result == null) {
  +            return;
  +        } else {
  +
  +            prompt.out.println("\n\tServer Version: " + 
result.get("result"));
  +
  +            message.clear();
  +            message.put("message", "GetApiVersion");
  +
  +            try {
  +                result = XindiceAdmin.run(message);
  +            } catch(Exception e) {
  +                return;
  +            }
  +            prompt.out.println("\tAPI Version: " + result.get("result"));
  +
                try {
                        String dir = System.getProperty("user.dir");
  -                     prompt.out.println("\n\tWorking directory: "+dir);
  +                     prompt.out.println("\tWorking directory: "+dir);
                } catch (SecurityException e) {
                        prompt.err.println("System security exception: " + e);
                } catch (NullPointerException e) {
  @@ -30,25 +56,10 @@
                        prompt.err.println("Bad system property key: " + e);
                }
   
  -        Hashtable message = new Hashtable();
  -        message.put("message", "GetServerVersion");
  -        Hashtable result = null;
  -        try {
  -            result = run(message);
  -        } catch(Exception e) {
  -
  -        }
  -        prompt.out.println("\tServer Version: " + result.get("result"));
  -
  -        message.clear();
  -        message.put("message", "GetApiVersion");
  +        prompt.out.println("\tCollection: " + 
org.apache.xindice.admin.XindiceAdmin.getDB());
   
  -        try {
  -            result = run(message);
  -        } catch(Exception e) {
  +            prompt.out.println("\tCopyright 2002, Apache Software 
Foundation");
   
           }
  -        prompt.out.println("\tAPI Version: " + result.get("result"));
  -        prompt.out.println("\tCopyright 2002, Apache Software Foundation\n");
        }
   }
  
  
  
  1.5       +14 -7     
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/ListCommand.java
  
  Index: ListCommand.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/ListCommand.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ListCommand.java  10 Nov 2002 19:22:19 -0000      1.4
  +++ ListCommand.java  5 Dec 2002 06:50:23 -0000       1.5
  @@ -61,6 +61,7 @@
   
   import org.apache.xindice.admin.commandline.BaseCommand;
   import org.apache.xindice.admin.commandline.CommandException;
  +import org.apache.xindice.admin.XindiceAdmin;
   
   import java.util.Hashtable;
   import java.util.Vector;
  @@ -94,18 +95,24 @@
   
           Hashtable message = new Hashtable();
           message.put("message", rpcmessage);
  -        message.put("collection", DB);
  +        message.put("collection", XindiceAdmin.getDB());
           Hashtable result = null;
           try {
  -            result = (Hashtable) run(message);
  +            result = (Hashtable) XindiceAdmin.run(message);
           } catch(Exception e) {
               //prompt.out.println(e);
               return;
  -        } finally {
  +        }
  +
  +        if(result != null) {
               Vector list = (Vector) result.get("result");
  -            Enumeration enum = list.elements();
  -            while ( enum.hasMoreElements() ) {
  -                prompt.out.println("\t" + enum.nextElement().toString());
  +            if( list.size() > 0) {
  +                Enumeration enum = list.elements();
  +                while ( enum.hasMoreElements() ) {
  +                    prompt.out.println("\t" + enum.nextElement().toString());
  +                }
  +            } else {
  +                prompt.out.println("\tNo collections");
               }
           }
   
  
  
  
  1.4       +2 -2      
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/RunScriptCommand.java
  
  Index: RunScriptCommand.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/RunScriptCommand.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- RunScriptCommand.java     9 Nov 2002 06:19:24 -0000       1.3
  +++ RunScriptCommand.java     5 Dec 2002 06:50:23 -0000       1.4
  @@ -78,7 +78,7 @@
        public void execute(String args[]) {
                Iterator urls = getURLs(args);
                if (urls == null || ( ! urls.hasNext()) ) {
  -                     prompt.err.println("must specify valid script URL");
  +                     prompt.err.println("\tmust specify valid script URL");
                        return;
                }
   
  
  
  
  1.4       +45 -4     
xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/UseCommand.java
  
  Index: UseCommand.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xindice/java/scratchpad/admin/src/org/apache/xindice/admin/commands/UseCommand.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- UseCommand.java   9 Nov 2002 06:19:24 -0000       1.3
  +++ UseCommand.java   5 Dec 2002 06:50:23 -0000       1.4
  @@ -59,10 +59,11 @@
    * $Id$
    */
   
  -import java.util.Iterator;
  -import java.util.Set;
  +import java.util.*;
  +
   import org.apache.xindice.admin.commandline.BaseCommand;
   import org.apache.xindice.admin.commandline.Command;
  +import org.apache.xindice.admin.XindiceAdmin;
   
   /**
    * Command for setting the working collection
  @@ -76,8 +77,48 @@
        }
   
        public void execute(String args[]) {
  +
                String collection = args[0];
  -             prompt.out.println("Collection changed to "+ collection);
  +        Hashtable message = new Hashtable();
  +        Hashtable result = null;
  +
  +        if(collection.startsWith("/")) {
  +
  +            message.put("message", "ListCollections");
  +            message.put("collection", collection);
  +
  +            try {
  +                result = (Hashtable) XindiceAdmin.run(message);
  +            } catch(Exception e) {
  +                //prompt.out.println(e.getMessage());
  +                return;
  +            }
  +
  +            if(result == null) {
  +                prompt.out.println("\tCollection does not exist.");
  +            } else {
  +                XindiceAdmin.setDB(collection);
  +                prompt.out.println("\tCollection changed to "+ 
XindiceAdmin.getDB());
  +            }
  +        } else {
  +            message.put("message", "ListCollections");
  +            message.put("collection", XindiceAdmin.getDB() + "/" + 
collection);
  +
  +            try {
  +                result = (Hashtable) XindiceAdmin.run(message);
  +            } catch(Exception e) {
  +                prompt.out.println(e.getMessage());
  +                return;
  +            }
  +
  +            if(result == null) {
  +                prompt.out.println("\tCollection does not exist.");
  +            } else {
  +                XindiceAdmin.setDB(XindiceAdmin.getDB() + "/" + collection);
  +                prompt.out.println("\tCollection changed to "+ 
XindiceAdmin.getDB());
  +            }
  +        }
  +
        }
   
   }
  
  
  

Reply via email to