Author: alexoree
Date: Fri Aug 23 01:35:22 2013
New Revision: 1516675

URL: http://svn.apache.org/r1516675
Log:
JUDDI-636 adding a subscription callback API, configuration settings to match 
(Java only)
JUDDI-637 adding some additional documentation
JUDDI-605 functionality stubbed out, however technical implementation is highly 
dependent on soap stack.

Modified:
    
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/ClientConfig.java
    
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClerk.java
    
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClient.java
    
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIClientSubscriptionListenerImpl.java
    
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIServiceCache.java
    juddi/trunk/juddi-client/src/main/resources/xsd/uddi-client.xsd
    juddi/trunk/juddi-core/src/main/java/org/apache/juddi/config/Property.java
    
juddi/trunk/juddi-core/src/main/java/org/apache/juddi/subscription/notify/HTTPNotifier.java
    
juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiDigitalSignatureTmodel.java
    juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiSubscribe.java

Modified: 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/ClientConfig.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/ClientConfig.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/ClientConfig.java
 (original)
+++ 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/ClientConfig.java
 Fri Aug 23 01:35:22 2013
@@ -21,8 +21,6 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import javax.xml.crypto.dsig.CanonicalizationMethod;
 
 import org.apache.commons.configuration.CompositeConfiguration;
@@ -318,6 +316,8 @@ public class ClientConfig 
             return configurationFile;
         }
 
+        
+        
         /**
          * Fetches all digital signature related properties for the digital 
signature utility.
          * warning, this will decrypt all passwords

Modified: 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClerk.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClerk.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClerk.java
 (original)
+++ 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClerk.java
 Fri Aug 23 01:35:22 2013
@@ -118,6 +118,11 @@ public class UDDIClerk implements Serial
     public String[] getClassWithAnnotations() {
         return classWithAnnotations;
     }
+    
+    public UDDINode getUDDINode()
+    {
+        return this.uddiNode;
+    }
 
     public void setClassWithAnnotations(String[] classWithAnnotations) {
         this.classWithAnnotations = classWithAnnotations;
@@ -699,7 +704,17 @@ public class UDDIClerk implements Serial
         }
     }
 
-    private String getAuthToken(String endpointURL) throws TransportException, 
DispositionReportFaultMessage, RemoteException {
+    /**
+     * Gets an auth token from the uddi server using the uddi auth token
+     * 
+     * notes: changed to protected to have access from the subscription 
callback API 8/20/2013 AO
+     * @param endpointURL
+     * @return
+     * @throws TransportException
+     * @throws DispositionReportFaultMessage
+     * @throws RemoteException 
+     */
+    public String getAuthToken(String endpointURL) throws TransportException, 
DispositionReportFaultMessage, RemoteException {
         //if the token is older then 10 minutes discard it, and create a new 
one.
         if ((authToken != null && !"".equals(authToken)) && (tokenBirthDate != 
null && System.currentTimeMillis() > tokenBirthDate.getTime() + 600000)) {
             DiscardAuthToken discardAuthToken = new DiscardAuthToken();
@@ -779,11 +794,7 @@ public class UDDIClerk implements Serial
         apiClerk.setPublisher(publisher);
         return apiClerk;
     }
-
-    public UDDINode getUDDINode() {
-        return uddiNode;
-    }
-
+    
     public String getName() {
         return name;
     }

Modified: 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClient.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClient.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClient.java
 (original)
+++ 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/config/UDDIClient.java
 Fri Aug 23 01:35:22 2013
@@ -309,8 +309,17 @@ public class UDDIClient {
                }
        }
        
+        /**
+         * Gets the UDDI Clerk, the entry point into many functions of the 
juddi client
+         * @param clerkName - This references the uddi/client/clern@name of 
the juddi client config file.
+         * it stores credentials if necessary and associates it with a 
particular UDDI node (server/cluster)
+         * If not specificed, the value of "default" will be used.
+         * @return 
+         */
        public UDDIClerk getClerk(String clerkName) {
-               return getClientConfig().getUDDIClerks().get(clerkName);
+            if (clerkName==null || clerkName.length()==0)
+                return getClientConfig().getUDDIClerks().get("default");
+            return getClientConfig().getUDDIClerks().get(clerkName);
        }
        
        /**

Modified: 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIClientSubscriptionListenerImpl.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIClientSubscriptionListenerImpl.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIClientSubscriptionListenerImpl.java
 (original)
+++ 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIClientSubscriptionListenerImpl.java
 Fri Aug 23 01:35:22 2013
@@ -38,12 +38,15 @@ import org.uddi.v3_service.UDDISubscript
  * the UDDI registry when any change to a Service or BindingTemplate
  * call in to it.
  * 
+ * @deprecated Use SubscriptionCallbackListener instead
  * @author kstam
+ * @see SubscriptionCallbackListener
  *
  */
 @WebService(serviceName="UDDIClientSubscriptionListenerService", 
                        
endpointInterface="org.uddi.v3_service.UDDISubscriptionListenerPortType",
                        targetNamespace = "urn:uddi-org:v3_service")
+@Deprecated
 public class UDDIClientSubscriptionListenerImpl implements 
UDDISubscriptionListenerPortType {
        
        private static Log logger = 
LogFactory.getLog(UDDIClientSubscriptionListenerImpl.class);

Modified: 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIServiceCache.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIServiceCache.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIServiceCache.java
 (original)
+++ 
juddi/trunk/juddi-client/src/main/java/org/apache/juddi/v3/client/mapping/UDDIServiceCache.java
 Fri Aug 23 01:35:22 2013
@@ -36,6 +36,7 @@ import org.apache.commons.logging.LogFac
 import org.apache.juddi.v3.client.config.Property;
 import org.apache.juddi.v3.client.config.UDDIClerk;
 import org.apache.juddi.v3.client.config.UDDIKeyConvention;
+import org.apache.juddi.v3.client.subscription.SubscriptionCallbackListener;
 import org.apache.juddi.v3.client.transport.TransportException;
 import org.uddi.api_v3.FindQualifiers;
 import org.uddi.api_v3.FindService;
@@ -90,7 +91,9 @@ public class UDDIServiceCache {
                        log.info("Bring up Subscription Listener for manager " 
+ clerk.getManagerName() 
                                        + " with endpoint " + url);
                        bindingKey = 
UDDIKeyConvention.getBindingKey(properties, serviceQName, portName, serviceUrl);
-                       endpoint = Endpoint.create(new 
UDDIClientSubscriptionListenerImpl(bindingKey,this));
+                        endpoint = Endpoint.create(new 
SubscriptionCallbackListener());
+                        
+                       //endpoint = Endpoint.create(new 
UDDIClientSubscriptionListenerImpl(bindingKey,this));
                        endpoint.publish(serviceUrl.toExternalForm());
                        
                        WSDL2UDDI wsdl2UDDI = new WSDL2UDDI(clerk, 
urlLocalizer, properties);
@@ -135,6 +138,10 @@ public class UDDIServiceCache {
                serviceLocationMap.remove(serviceKey);
        }
        
+        /**
+         * Create a subscription for changes in any Service in the Registry
+         * @throws DatatypeConfigurationException 
+         */
        public void registerSubscription() throws 
DatatypeConfigurationException {
                
                //Create a subscription for changes in any Service in the 
Registry

Modified: juddi/trunk/juddi-client/src/main/resources/xsd/uddi-client.xsd
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-client/src/main/resources/xsd/uddi-client.xsd?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- juddi/trunk/juddi-client/src/main/resources/xsd/uddi-client.xsd (original)
+++ juddi/trunk/juddi-client/src/main/resources/xsd/uddi-client.xsd Fri Aug 23 
01:35:22 2013
@@ -183,6 +183,21 @@
                   </xsd:sequence>
                 </xsd:complexType>
               </xsd:element>
+              <xsd:element name="subscriptionCallbacks">
+                <xsd:complexType>
+                  <xsd:sequence>
+                    <xsd:element type="xsd:string" 
name="keyDomain"></xsd:element>
+                    <xsd:element type="xsd:string" 
name="listenUrl"></xsd:element>
+                    <xsd:element type="xsd:boolean" 
name="autoRegisterBindingTemplate"></xsd:element>
+                    <xsd:element type="xsd:string" 
name="autoRegisterBusinessServiceKey"></xsd:element>
+                    <xsd:element type="xsd:string" name="signatureBehavior">
+                      
<xsd:annotation><xsd:documentation>AbortIfSigned,Sign,DoNothing,SignOnlyIfParentIsntSigned</xsd:documentation></xsd:annotation>
+                    </xsd:element>
+                    
+                  </xsd:sequence>
+                </xsd:complexType>
+              </xsd:element>
+
             </xsd:sequence>
             <xsd:attribute type="xsd:string" name="name" />
           </xsd:complexType>

Modified: 
juddi/trunk/juddi-core/src/main/java/org/apache/juddi/config/Property.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-core/src/main/java/org/apache/juddi/config/Property.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- juddi/trunk/juddi-core/src/main/java/org/apache/juddi/config/Property.java 
(original)
+++ juddi/trunk/juddi-core/src/main/java/org/apache/juddi/config/Property.java 
Fri Aug 23 01:35:22 2013
@@ -67,6 +67,24 @@ public interface Property {
     public final static String JUDDI_SUBSCRIPTION_CHUNKEXPIRATION_MINUTES = 
"juddi.subscription.chunkexpiration.minutes";
     public final static String 
JUDDI_SUBSCRIPTION_MAXENTITIES="juddi.subscription.maxentities";
     
+    public final static String 
JUDDI_SUBSCRIPTION_TRUSTSTORE_TYPE="juddi.subscription.truststore.type";
+    public final static String 
JUDDI_SUBSCRIPTION_TRUSTSTORE_FILE="juddi.subscription.truststore.filename";
+    public final static String 
JUDDI_SUBSCRIPTION_TRUSTSTORE_PASSWORD="juddi.subscription.truststore.password";
+    public final static String 
JUDDI_SUBSCRIPTION_TRUSTSTORE_ENCRYPTED="juddi.subscription.truststore.password[@isPasswordEncrypted]";
+    public final static String 
JUDDI_SUBSCRIPTION_TRUSTSTORE_CRYPTOPROVIDER="juddi.subscription.truststore.password[@cryptoProvider]";
+    
+    
+    public final static String 
JUDDI_SUBSCRIPTION_KEYSTORE_TYPE="juddi.subscription.keystore.type";
+    public final static String 
JUDDI_SUBSCRIPTION_KEYSTORE_FILE="juddi.subscription.keystore.filename";
+    public final static String 
JUDDI_SUBSCRIPTION_KEYSTORE_PASSWORD="juddi.subscription.keystore.password";
+    public final static String 
JUDDI_SUBSCRIPTION_KEYALIAS="juddi.subscription.keystore.alias";
+    public final static String 
JUDDI_SUBSCRIPTION_KEYPASSWORD="juddi.subscription.keystore.keypassword";
+    public final static String 
JUDDI_SUBSCRIPTION_KEYPASSWORD_ENCRYPTED="juddi.subscription.keystore.keypassword[@isPasswordEncrypted]";
+    public final static String 
JUDDI_SUBSCRIPTION_KEYPASSWORD_CRYPTOPROVIDER="juddi.subscription.keypassword.password[@cryptoProvider]";
+    public final static String 
JUDDI_SUBSCRIPTION_KEYSTORE_ENCRYPTED="juddi.subscription.keystore.password[@isPasswordEncrypted]";
+    public final static String 
JUDDI_SUBSCRIPTION_KEYSTORE_CRYPTOPROVIDER="juddi.subscription.keystore.password[@cryptoProvider]";
+    
+    
     public final static String JUDDI_NOTIFICATION_START_BUFFER = 
"juddi.notification.start.buffer";
     public final static String JUDDI_NOTIFICATION_INTERVAL = 
"juddi.notification.interval";
     public final static String JUDDI_NOTIFICATION_ACCEPTABLE_LAGTIME = 
"juddi.notification.acceptable.lagtime";

Modified: 
juddi/trunk/juddi-core/src/main/java/org/apache/juddi/subscription/notify/HTTPNotifier.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-core/src/main/java/org/apache/juddi/subscription/notify/HTTPNotifier.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- 
juddi/trunk/juddi-core/src/main/java/org/apache/juddi/subscription/notify/HTTPNotifier.java
 (original)
+++ 
juddi/trunk/juddi-core/src/main/java/org/apache/juddi/subscription/notify/HTTPNotifier.java
 Fri Aug 23 01:35:22 2013
@@ -12,6 +12,9 @@ import javax.xml.ws.Service;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.juddi.api_v3.AccessPointType;
+import org.apache.juddi.config.AppConfig;
+import org.apache.juddi.config.Property;
+import org.apache.juddi.cryptor.CryptorFactory;
 import org.apache.juddi.model.BindingTemplate;
 import org.apache.juddi.v3.client.UDDIService;
 import org.uddi.api_v3.DispositionReport;
@@ -20,39 +23,51 @@ import org.uddi.v3_service.DispositionRe
 import org.uddi.v3_service.UDDISubscriptionListenerPortType;
 
 public class HTTPNotifier implements Notifier {
-       
-       private static String SUBR_V3_NAMESPACE = "urn:uddi-org:v3_service";
-       private static String SUBSCRIPTION_LISTENER_SERVICE = 
"UDDISubscriptionListenerImplPort";
-       
-       Log log = LogFactory.getLog(this.getClass());
-       UDDISubscriptionListenerPortType subscriptionListenerPort = null;
-       
-       public HTTPNotifier(BindingTemplate bindingTemplate) throws IOException 
{
-               super();
-               String accessPointUrl = 
bindingTemplate.getAccessPointUrl().toLowerCase();
-               if (!accessPointUrl.startsWith("http")) {
-                       log.warn("http accessPointUrl for bindingTemplate " + 
bindingTemplate.getEntityKey() + 
-                                       " should start with 'http' or 'https'");
-               }
-               //fix for JIRA JUDDI-597
-               accessPointUrl = bindingTemplate.getAccessPointUrl();
-               if 
(AccessPointType.WSDL_DEPLOYMENT.toString().equalsIgnoreCase(bindingTemplate.getAccessPointType()))
 {
-                       //WSDL deployment type
-                       //TODO, let user override the 
SUBSCRIPTION_LISTENER_SERVICE setting
-                       QName qName = new QName(SUBR_V3_NAMESPACE, 
SUBSCRIPTION_LISTENER_SERVICE);
-                       Service service = Service.create(new 
URL(bindingTemplate.getAccessPointUrl()), qName);
-                       subscriptionListenerPort = 
(UDDISubscriptionListenerPortType) 
service.getPort(UDDISubscriptionListenerPortType.class);
-               } else if 
(AccessPointType.END_POINT.toString().equalsIgnoreCase(bindingTemplate.getAccessPointType()))
 {
-                       //endpoint deployment type
-                       UDDIService uddiService = new UDDIService();
-                       subscriptionListenerPort =  
uddiService.getUDDISubscriptionListenerPort();
-                       Map<String, Object> requestContext = ((BindingProvider) 
subscriptionListenerPort).getRequestContext();
-                       
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, accessPointUrl);
-                       
-               }
-       }
 
-       public DispositionReport 
notifySubscriptionListener(NotifySubscriptionListener body) throws 
DispositionReportFaultMessage, RemoteException {
-               return 
subscriptionListenerPort.notifySubscriptionListener(body);
-       }
+    private static String SUBR_V3_NAMESPACE = "urn:uddi-org:v3_service";
+    private static String SUBSCRIPTION_LISTENER_SERVICE = 
"UDDISubscriptionListenerImplPort";
+    Log log = LogFactory.getLog(this.getClass());
+    UDDISubscriptionListenerPortType subscriptionListenerPort = null;
+
+    public HTTPNotifier(BindingTemplate bindingTemplate) throws IOException {
+        super();
+        String accessPointUrl = 
bindingTemplate.getAccessPointUrl().toLowerCase();
+        if (!accessPointUrl.startsWith("http")) {
+            log.warn("http accessPointUrl for bindingTemplate " + 
bindingTemplate.getEntityKey()
+                    + " should start with 'http' or 'https'");
+        }
+        //fix for JIRA JUDDI-597
+        accessPointUrl = bindingTemplate.getAccessPointUrl();
+        if 
(AccessPointType.WSDL_DEPLOYMENT.toString().equalsIgnoreCase(bindingTemplate.getAccessPointType()))
 {
+            //WSDL deployment type
+            //TODO, let user override the SUBSCRIPTION_LISTENER_SERVICE setting
+            QName qName = new QName(SUBR_V3_NAMESPACE, 
SUBSCRIPTION_LISTENER_SERVICE);
+            Service service = Service.create(new 
URL(bindingTemplate.getAccessPointUrl()), qName);
+            subscriptionListenerPort = (UDDISubscriptionListenerPortType) 
service.getPort(UDDISubscriptionListenerPortType.class);
+        } else if 
(AccessPointType.END_POINT.toString().equalsIgnoreCase(bindingTemplate.getAccessPointType()))
 {
+            //endpoint deployment type
+            UDDIService uddiService = new UDDIService();
+            subscriptionListenerPort = 
uddiService.getUDDISubscriptionListenerPort();
+            Map<String, Object> requestContext = ((BindingProvider) 
subscriptionListenerPort).getRequestContext();
+            requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, 
accessPointUrl);
+        }
+        /*if (accessPointUrl.toLowerCase().startsWith("https://";)) {
+            try {
+                String file = 
AppConfig.getConfiguration().getString(Property.JUDDI_SUBSCRIPTION_TRUSTSTORE_FILE);
+                String type = 
AppConfig.getConfiguration().getString(Property.JUDDI_SUBSCRIPTION_TRUSTSTORE_TYPE);
+                String password = 
AppConfig.getConfiguration().getString(Property.JUDDI_SUBSCRIPTION_TRUSTSTORE_PASSWORD);
+                if 
(AppConfig.getConfiguration().getBoolean(Property.JUDDI_SUBSCRIPTION_TRUSTSTORE_ENCRYPTED,
 false)) {
+                    password = 
CryptorFactory.getCryptor(AppConfig.getConfiguration().getString(Property.JUDDI_SUBSCRIPTION_TRUSTSTORE_CRYPTOPROVIDER)).decrypt(password);
+                }
+                
+            } catch (Exception ex) {
+                log.error(null, ex);
+            }
+
+        }*/
+    }
+
+    public DispositionReport 
notifySubscriptionListener(NotifySubscriptionListener body) throws 
DispositionReportFaultMessage, RemoteException {
+        return subscriptionListenerPort.notifySubscriptionListener(body);
+    }
 }

Modified: 
juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiDigitalSignatureTmodel.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiDigitalSignatureTmodel.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- 
juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiDigitalSignatureTmodel.java
 (original)
+++ 
juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiDigitalSignatureTmodel.java
 Fri Aug 23 01:35:22 2013
@@ -54,10 +54,6 @@ public class UddiDigitalSignatureTmodel 
      * @param args
      */
     public static void main(String args[]) {
-        if (args.length == 1 && args[0].equalsIgnoreCase("help")) {
-            DisplayHelp();
-            return;
-        }
         UddiDigitalSignatureTmodel sp = new UddiDigitalSignatureTmodel();
         sp.Fire(args);
     }

Modified: 
juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiSubscribe.java
URL: 
http://svn.apache.org/viewvc/juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiSubscribe.java?rev=1516675&r1=1516674&r2=1516675&view=diff
==============================================================================
--- 
juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiSubscribe.java 
(original)
+++ 
juddi/trunk/juddi-examples/uddi-samples/src/uddi/examples/UddiSubscribe.java 
Fri Aug 23 01:35:22 2013
@@ -184,8 +184,10 @@ public class UddiSubscribe {
         Holder<List<Subscription>> subscription = new 
Holder<List<Subscription>>();
         subscription.value = new ArrayList<Subscription>();
         Subscription sub = new Subscription();
-        sub.setBindingKey(callbackBindingTemplate);
+        
         //this is required
+        sub.setBindingKey(callbackBindingTemplate);
+        
         sub.setBrief(true);
         sub.setNotificationInterval(df.newDuration(0));
         sub.setSubscriptionFilter(new SubscriptionFilter());



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to