Author: vmpn
Date: Mon Dec 24 02:59:18 2012
New Revision: 1425578

URL: http://svn.apache.org/viewvc?rev=1425578&view=rev
Log:
On the javahl-ra branch:

Bring up-to-date with trunk@1399063

Modified:
    subversion/branches/javahl-ra/   (props changed)
    subversion/branches/javahl-ra/subversion/include/svn_dav.h
    subversion/branches/javahl-ra/subversion/include/svn_error_codes.h
    subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c
    subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c
    subversion/branches/javahl-ra/subversion/libsvn_ra_serf/property.c
    subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h
    subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c
    subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c
    subversion/branches/javahl-ra/subversion/mod_dav_svn/dav_svn.h
    subversion/branches/javahl-ra/subversion/mod_dav_svn/deadprops.c
    subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c
    subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c
    subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c

Propchange: subversion/branches/javahl-ra/
------------------------------------------------------------------------------
  Merged /subversion/branches/http-dynamic-prop-namespaces:r1396196-1398972
  Merged /subversion/trunk:r1398942-1399063

Modified: subversion/branches/javahl-ra/subversion/include/svn_dav.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/include/svn_dav.h?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/include/svn_dav.h (original)
+++ subversion/branches/javahl-ra/subversion/include/svn_dav.h Mon Dec 24 
02:59:18 2012
@@ -260,6 +260,11 @@ extern "C" {
  */
 #define SVN_DAV_PROP_NS_DAV "http://subversion.tigris.org/xmlns/dav/";
 
+/** An extensible base URI from which other custom namespace URIs
+ * extend on an as-needed basis.
+ */
+#define SVN_DAV_PROP_NS_EXTENSIBLE "http://subversion.apache.org/xmlns/ext/";
+
 
 /**
  * @name Custom (extension) values for the DAV header.
@@ -312,6 +317,14 @@ extern "C" {
 #define SVN_DAV_NS_DAV_SVN_EPHEMERAL_TXNPROPS\
             SVN_DAV_PROP_NS_DAV "svn/ephemeral-txnprops"
 
+/** Presence of this in a DAV header in an OPTIONS request/response
+ * indicates that the transmitter knows how to properly handle
+ * Subversion properties delivered via WebDAV's PROPFIND and PROPPATCH
+ * mechanisms using Subversion's extensible property namespace
+ * SVN_DAV_PROP_NS_EXTENSIBLE. */
+#define SVN_DAV_NS_DAV_SVN_PROP_EXT_NS\
+            SVN_DAV_PROP_NS_DAV "svn/prop-ext-ns"
+
 /** @} */
 
 /** @} */

Modified: subversion/branches/javahl-ra/subversion/include/svn_error_codes.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/include/svn_error_codes.h?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/include/svn_error_codes.h 
(original)
+++ subversion/branches/javahl-ra/subversion/include/svn_error_codes.h Mon Dec 
24 02:59:18 2012
@@ -1418,7 +1418,7 @@ SVN_ERROR_START
   /** @since New in 1.8. */
   SVN_ERRDEF(SVN_ERR_MALFORMED_VERSION_STRING,
              SVN_ERR_MISC_CATEGORY_START + 37,
-             "too many memcached servers configured")
+             "failed to parse version number string")
 
   /* command-line client errors */
 

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c Mon Dec 24 
02:59:18 2012
@@ -61,6 +61,9 @@ typedef struct commit_context_t {
   svn_boolean_t keep_locks;
   apr_hash_t *deleted_entries;   /* deleted files (for delete+add detection) */
 
+  /* Stuff for extensible property XML namespaces. */
+  svn_boolean_t use_ext_prop_ns;
+
   /* HTTP v2 stuff */
   const char *txn_url;           /* txn URL (!svn/txn/TXN_NAME) */
   const char *txn_root_url;      /* commit anchor txn root URL */
@@ -670,7 +673,7 @@ proppatch_walker(void *baton,
   svn_boolean_t have_old_val;
   const svn_string_t *old_val;
   const svn_string_t *encoded_value;
-  const char *prop_name;
+  const char *prop_name, *xmlns = NULL;
 
   SVN_ERR(derive_old_val(&have_old_val, &old_val, wb, ns, name));
 
@@ -701,19 +704,31 @@ proppatch_walker(void *baton,
       cdata_bkt = NULL;
     }
 
-  /* Use the namespace prefix instead of adding the xmlns attribute to support
-     property names containing ':' */
+  /* To reduce the wire transfer size, use prefixes for property
+     namespace for which we've predefined them. */
   if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
-    prop_name = apr_pstrcat(wb->body_pool, "S:", name, (char *)NULL);
+    {
+      prop_name = apr_pstrcat(wb->body_pool, "S:", name, (char *)NULL);
+    }
   else if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
-    prop_name = apr_pstrcat(wb->body_pool, "C:", name, (char *)NULL);
+    {
+      prop_name = apr_pstrcat(wb->body_pool, "C:", name, (char *)NULL);
+    }
+  else if (strncmp(ns, SVN_DAV_PROP_NS_EXTENSIBLE,
+                   sizeof(SVN_DAV_PROP_NS_EXTENSIBLE) - 1) == 0)
+    {
+      prop_name = name;
+      xmlns = ns;
+    }
 
   if (cdata_bkt)
     svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
+                                      "xmlns", xmlns,
                                       "V:encoding", encoding,
                                       NULL);
   else
     svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
+                                      "xmlns", xmlns,
                                       "V:" SVN_DAV__OLD_VALUE__ABSENT, "1",
                                       NULL);
 
@@ -1468,23 +1483,18 @@ open_root(void *edit_baton,
         {
           const void *key;
           void *val;
-          const char *name;
+          const char *propname;
           svn_string_t *value;
-          const char *ns;
+          const char *ns, *name;
 
           apr_hash_this(hi, &key, NULL, &val);
-          name = key;
+          propname = key;
           value = val;
 
-          if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
-            {
-              ns = SVN_DAV_PROP_NS_SVN;
-              name += sizeof(SVN_PROP_PREFIX) - 1;
-            }
-          else
-            {
-              ns = SVN_DAV_PROP_NS_CUSTOM;
-            }
+          /* Calculate the wirename bits for this property name. */
+          svn_ra_serf__wirename_from_svnname(&ns, &name, propname,
+                                             dir->commit->use_ext_prop_ns,
+                                             ctx->pool);
 
           svn_ra_serf__set_prop(proppatch_ctx->changed_props,
                                 proppatch_ctx->path,
@@ -1739,12 +1749,12 @@ open_directory(const char *path,
 
 static svn_error_t *
 change_dir_prop(void *dir_baton,
-                const char *name,
+                const char *propname,
                 const svn_string_t *value,
                 apr_pool_t *pool)
 {
   dir_context_t *dir = dir_baton;
-  const char *ns;
+  const char *ns, *name;
   const char *proppatch_target;
 
 
@@ -1760,16 +1770,10 @@ change_dir_prop(void *dir_baton,
       proppatch_target = dir->working_url;
     }
 
-  name = apr_pstrdup(dir->pool, name);
-  if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
-    {
-      ns = SVN_DAV_PROP_NS_SVN;
-      name += sizeof(SVN_PROP_PREFIX) - 1;
-    }
-  else
-    {
-      ns = SVN_DAV_PROP_NS_CUSTOM;
-    }
+  /* Calculate the wirename bits for this property name. */
+  svn_ra_serf__wirename_from_svnname(&ns, &name, propname,
+                                     dir->commit->use_ext_prop_ns,
+                                     dir->pool);
 
   if (value)
     {
@@ -1993,24 +1997,17 @@ apply_textdelta(void *file_baton,
 
 static svn_error_t *
 change_file_prop(void *file_baton,
-                 const char *name,
+                 const char *propname,
                  const svn_string_t *value,
                  apr_pool_t *pool)
 {
   file_context_t *file = file_baton;
-  const char *ns;
+  const char *ns, *name;
 
-  name = apr_pstrdup(file->pool, name);
-
-  if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
-    {
-      ns = SVN_DAV_PROP_NS_SVN;
-      name += sizeof(SVN_PROP_PREFIX) - 1;
-    }
-  else
-    {
-      ns = SVN_DAV_PROP_NS_CUSTOM;
-    }
+  /* Calculate the wirename bits for this property name. */
+  svn_ra_serf__wirename_from_svnname(&ns, &name, propname,
+                                     file->commit->use_ext_prop_ns,
+                                     file->pool);
 
   if (value)
     {
@@ -2309,10 +2306,9 @@ svn_ra_serf__get_commit_editor(svn_ra_se
 
   ctx->callback = callback;
   ctx->callback_baton = callback_baton;
-
   ctx->lock_tokens = lock_tokens;
   ctx->keep_locks = keep_locks;
-
+  ctx->use_ext_prop_ns = session->use_ext_prop_ns;
   ctx->deleted_entries = apr_hash_make(ctx->pool);
 
   editor = svn_delta_default_editor(pool);
@@ -2347,7 +2343,7 @@ svn_ra_serf__get_commit_editor(svn_ra_se
 svn_error_t *
 svn_ra_serf__change_rev_prop(svn_ra_session_t *ra_session,
                              svn_revnum_t rev,
-                             const char *name,
+                             const char *propname,
                              const svn_string_t *const *old_value_p,
                              const svn_string_t *value,
                              apr_pool_t *pool)
@@ -2356,7 +2352,7 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
   proppatch_context_t *proppatch_ctx;
   commit_context_t *commit;
   const char *proppatch_target;
-  const char *ns;
+  const char *ns, *name;
   svn_error_t *err;
 
   if (old_value_p)
@@ -2376,6 +2372,7 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
 
   commit->session = session;
   commit->conn = session->conns[0];
+  commit->use_ext_prop_ns = session->use_ext_prop_ns;
 
   if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
     {
@@ -2394,15 +2391,9 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
                                           pool, pool));
     }
 
-  if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
-    {
-      ns = SVN_DAV_PROP_NS_SVN;
-      name += sizeof(SVN_PROP_PREFIX) - 1;
-    }
-  else
-    {
-      ns = SVN_DAV_PROP_NS_CUSTOM;
-    }
+  /* Calculate the wirename bits for this property name. */
+  svn_ra_serf__wirename_from_svnname(&ns, &name, propname,
+                                     commit->use_ext_prop_ns, pool);
 
   /* PROPPATCH our log message and pass it along.  */
   proppatch_ctx = apr_pcalloc(pool, sizeof(*proppatch_ctx));

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c Mon Dec 
24 02:59:18 2012
@@ -211,6 +211,13 @@ capabilities_headers_iterator_callback(v
                        SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS, 
APR_HASH_KEY_STRING,
                        capability_yes);
         }
+
+      /* The "extensible property namespace" feature is an artefact of
+         our WebDAV protocol only.  We handle it specially. */
+      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PROP_EXT_NS, vals))
+        {
+          session->use_ext_prop_ns = TRUE;
+        }
     }
 
   /* SVN-specific headers -- if present, server supports HTTP protocol v2 */

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/property.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/property.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/property.c 
(original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/property.c Mon Dec 
24 02:59:18 2012
@@ -832,6 +832,64 @@ svn_ra_serf__walk_all_paths(apr_hash_t *
 }
 
 
+void
+svn_ra_serf__wirename_from_svnname(const char **ns,
+                                   const char **name,
+                                   const char *svnname,
+                                   svn_boolean_t use_ext_prop_ns,
+                                   apr_pool_t *result_pool)
+{
+  /* If we're allowed to use the extensible property namespace... */
+  if (use_ext_prop_ns)
+    {
+      const char *colon;
+
+      /* If there's no colon in this property name, it's a custom
+         property (C:name). */
+      colon = strrchr(svnname, ':');
+      if (! colon)
+        {
+          *ns = SVN_DAV_PROP_NS_CUSTOM;
+          *name = apr_pstrdup(result_pool, svnname);
+        }
+      /* Otherwise... */
+      else
+        {
+          /* If the property name prefix is merely "svn:", it's a
+             Subversion property (S:name-without-the-prefix). */
+          if (strncmp(svnname, "svn:", colon - svnname) == 0)
+            {
+              *ns = SVN_DAV_PROP_NS_SVN;
+            }
+          /* ...but anything else requires the extensible namespace. */
+          else
+            {
+              const char *barename = apr_pstrndup(result_pool, svnname,
+                                                  colon - svnname);
+              *ns = apr_pstrcat(result_pool, SVN_DAV_PROP_NS_EXTENSIBLE,
+                                svn_path_uri_encode(barename, result_pool),
+                                (char *)NULL);
+            }
+
+          /* Either way, the base name begins after the colon. */
+          *name = apr_pstrdup(result_pool, colon + 1);
+        }
+    }
+  else
+    {
+      if (strncmp(svnname, "svn:", 4) == 0)
+        {
+          *ns = SVN_DAV_PROP_NS_SVN;
+          *name = apr_pstrdup(result_pool, svnname + 4);
+        }
+      else
+        {
+          *ns = SVN_DAV_PROP_NS_CUSTOM;
+          *name = apr_pstrdup(result_pool, svnname);
+        }
+    }
+}
+
 const char *
 svn_ra_serf__svnname_from_wirename(const char *ns,
                                    const char *name,
@@ -843,6 +901,16 @@ svn_ra_serf__svnname_from_wirename(const
   if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
     return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL);
 
+  /* Check for something within our extensible namespace. */
+  if (strncmp(ns, SVN_DAV_PROP_NS_EXTENSIBLE,
+              sizeof(SVN_DAV_PROP_NS_EXTENSIBLE) - 1) == 0)
+    {
+      const char *relpath =
+        svn_path_uri_decode(ns + (sizeof(SVN_DAV_PROP_NS_EXTENSIBLE) - 1),
+                            result_pool);
+      return apr_pstrcat(result_pool, relpath, ":", name, (char *)NULL);
+    }
+
   if (strcmp(ns, SVN_PROP_PREFIX) == 0)
     return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL);
 
@@ -932,6 +1000,13 @@ select_revprops(void *baton,
     prop_name = name;
   else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
     prop_name = apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL);
+  else if (strncmp(ns, SVN_DAV_PROP_NS_EXTENSIBLE,
+                   sizeof(SVN_DAV_PROP_NS_EXTENSIBLE) - 1) == 0)
+    {
+      const char *relpath = svn_uri_skip_ancestor(SVN_DAV_PROP_NS_EXTENSIBLE,
+                                                  ns, scratch_pool);
+      prop_name = apr_pstrcat(result_pool, relpath, ":", name, (char *)NULL);
+    }
   else if (strcmp(ns, SVN_PROP_PREFIX) == 0)
     prop_name = apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL);
   else if (strcmp(ns, "") == 0)

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h Mon Dec 
24 02:59:18 2012
@@ -173,6 +173,9 @@ struct svn_ra_serf__session_t {
      constants' addresses, therefore). */
   apr_hash_t *capabilities;
 
+  /* Does the server understand the extensible property XML namespace? */
+  svn_boolean_t use_ext_prop_ns;
+
   /* Are we using a proxy? */
   int using_proxy;
 
@@ -1188,6 +1191,19 @@ svn_ra_serf__walk_all_paths(apr_hash_t *
                             apr_pool_t *pool);
 
 
+/* Map a property SVNNAME as referred to internally by Subversion to
+   its corresponding wire namespace (*NS) and *NAME.
+
+   If USE_EXT_PROP_NS is set, the function may make use of the
+   extensible property XML namespace (SVN_DAV_PROP_NS_EXTENSIBLE).  */
+void
+svn_ra_serf__wirename_from_svnname(const char **ns,
+                                   const char **name,
+                                   const char *svnname,
+                                   svn_boolean_t use_ext_prop_ns,
+                                   apr_pool_t *result_pool);
+
+
 /* Map a property name, as passed over the wire, into its corresponding
    Subversion-internal name. The returned name will be a static value,
    or allocated within RESULT_POOL.

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c Mon Dec 24 
02:59:18 2012
@@ -676,6 +676,11 @@ dirent_walker(void *baton,
     {
       dwb->entry->has_props = TRUE;
     }
+  else if (strncmp(ns, SVN_DAV_PROP_NS_EXTENSIBLE,
+                   sizeof(SVN_DAV_PROP_NS_EXTENSIBLE) - 1) == 0)
+    {
+      dwb->entry->has_props = TRUE;
+    }
   else if (strcmp(ns, SVN_DAV_PROP_NS_DAV) == 0)
     {
       if(strcmp(name, "deadprop-count") == 0)

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c Mon Dec 24 
02:59:18 2012
@@ -702,6 +702,7 @@ setup_serf_req(serf_request_t *request,
   serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_DEPTH);
   serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_MERGEINFO);
   serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_LOG_REVPROPS);
+  serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_PROP_EXT_NS);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/dav_svn.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/dav_svn.h?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/dav_svn.h (original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/dav_svn.h Mon Dec 24 
02:59:18 2012
@@ -137,6 +137,11 @@ typedef struct dav_svn_repos {
      'is_svn_client' is false, then 'capabilities' should be empty. */
   apr_hash_t *client_capabilities;
 
+  /* Whether its okay to use the extensible property XML namespace
+     SVN_DAV_PROP_NS_SVN in PROPFIND/PROPPATCH requests and
+     responses. */
+  svn_boolean_t use_ext_prop_ns;
+
   /* The path to the activities db */
   const char *activities_db;
 
@@ -304,13 +309,6 @@ svn_boolean_t dav_svn__get_autoversionin
 /* for the repository referred to by this request, are bulk updates allowed? */
 svn_boolean_t dav_svn__get_bulk_updates_flag(request_rec *r);
 
-/* for the repository referred to by this request, should httpv2 be 
advertised? */
-svn_boolean_t dav_svn__get_v2_protocol_flag(request_rec *r);
-
-/* for the repository referred to by this request, should ephemeral
-   txnprop support be advertised? */
-svn_boolean_t dav_svn__get_ephemeral_txnprops_flag(request_rec *r);
-
 /* for the repository referred to by this request, are subrequests active? */
 svn_boolean_t dav_svn__get_pathauthz_flag(request_rec *r);
 
@@ -332,6 +330,21 @@ authz_svn__subreq_bypass_func_t dav_svn_
    SVNParentPath allowed? */
 svn_boolean_t dav_svn__get_list_parentpath_flag(request_rec *r);
 
+/* For the repository referred to by this request, should HTTPv2
+   protocol support be advertised?  Note that this also takes into
+   account the support level expected of based on the specified
+   master server version (if provided via SVNMasterVersion).  */
+svn_boolean_t dav_svn__check_httpv2_support(request_rec *r);
+
+/* For the repository referred to by this request, should ephemeral
+   txnprop support be advertised?  */
+svn_boolean_t dav_svn__check_ephemeral_txnprops_support(request_rec *r);
+
+/* For the repository referred to by this request, should support for
+   property on-the-wire XML namespaces under the extensible namespace
+   URI be advertised?  */
+svn_boolean_t dav_svn__check_prop_ext_ns_support(request_rec *r);
+
 
 /* SPECIAL URI
 
@@ -380,6 +393,11 @@ const char *dav_svn__get_xslt_uri(reques
 /* ### Is this assumed to be URI-encoded? */
 const char *dav_svn__get_master_uri(request_rec *r);
 
+/* Return the version of the master server (used for mirroring) iff a
+   master URI is in place for this location; otherwise, return NULL.
+   Comes from the <SVNMasterVersion> directive. */
+svn_version_t *dav_svn__get_master_version(request_rec *r);
+
 /* Return the disk path to the activities db.
    Comes from the <SVNActivitiesDB> directive. */
 const char *dav_svn__get_activities_db(request_rec *r);

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/deadprops.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/deadprops.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/deadprops.c (original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/deadprops.c Mon Dec 24 
02:59:18 2012
@@ -68,28 +68,112 @@ get_repos_path(struct dav_resource_priva
 }
 
 
-/* construct the repos-local name for the given DAV property name */
-static void
-get_repos_propname(dav_db *db,
-                   const dav_prop_name *name,
-                   const char **repos_propname)
+/* Return a Subversion property name constructed from the namespace
+   and bare name values found withing DAVNAME.  Use SCRATCH_POOL for
+   temporary allocations.
+
+   This is the reverse of the davname_to_propname() function. */
+static const char *
+davname_to_propname(dav_db *db,
+                    const dav_prop_name *davname)
 {
-  if (strcmp(name->ns, SVN_DAV_PROP_NS_SVN) == 0)
+  const char *propname = NULL;
+
+  if (strcmp(davname->ns, SVN_DAV_PROP_NS_SVN) == 0)
     {
       /* recombine the namespace ("svn:") and the name. */
       svn_stringbuf_set(db->work, SVN_PROP_PREFIX);
-      svn_stringbuf_appendcstr(db->work, name->name);
-      *repos_propname = db->work->data;
+      svn_stringbuf_appendcstr(db->work, davname->name);
+      propname = db->work->data;
     }
-  else if (strcmp(name->ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
+  else if (strcmp(davname->ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
     {
       /* the name of a custom prop is just the name -- no ns URI */
-      *repos_propname = name->name;
+      propname = davname->name;
+    }
+  else if (strncmp(davname->ns, SVN_DAV_PROP_NS_EXTENSIBLE,
+                   sizeof(SVN_DAV_PROP_NS_EXTENSIBLE) - 1) == 0)
+    {
+      const char *relpath =
+        svn_path_uri_decode(davname->ns +
+                            (sizeof(SVN_DAV_PROP_NS_EXTENSIBLE) - 1),
+                            db->resource->pool);
+      svn_stringbuf_set(db->work, relpath);
+      svn_stringbuf_appendbytes(db->work, ":", 1);
+      svn_stringbuf_appendcstr(db->work, davname->name);
+      propname = db->work->data;
+    }
+
+  return propname;
+}
+
+
+/* Return a dav_prop_name structure allocated from POOL which
+   describes the Subversion property name PROPNAME (with length
+   NAMELEN).  If ALLOW_EXT_NS is set, PROPNAME is parsed according to
+   the rules which apply when the custom Subversion extensible
+   property namespace is in use.  Otherwise, we fall back to old rules
+   which have been in place since Subversion's origins.
+
+   This is the reverse of the davname_to_propname() function.  */
+static dav_prop_name *
+propname_to_davname(const char *propname,
+                    int namelen,
+                    svn_boolean_t allow_ext_ns,
+                    apr_pool_t *pool)
+{
+  const char *colon;
+  dav_prop_name *davname = apr_pcalloc(pool, sizeof(*davname));
+
+  /* If we're allowed to use the extensible XML property namespace, we
+     parse pretty carefully. */
+  if (allow_ext_ns)
+    {
+      /* If there's no colon in this property name, it's a custom
+         property (C:name). */
+      colon = strrchr((char *)propname, ':');
+      if (! colon)
+        {
+          davname->ns = SVN_DAV_PROP_NS_CUSTOM;
+          davname->name = apr_pstrdup(pool, propname);
+        }
+
+      /* If the property name prefix is merely "svn:", it's a
+         Subversion property (S:name-without-the-prefix). */
+      else if (strncmp(propname, "svn:", colon - propname) == 0)
+        {
+          davname->ns = SVN_DAV_PROP_NS_SVN;
+          davname->name = apr_pstrdup(pool, colon + 1);
+        }
+
+      /* Anything else requires a custom xmlns prefix mapping beyond
+         the magic prefixes we've already built in. */
+      else
+        {
+          const char *barename = apr_pstrndup(pool, propname, colon - 
propname);
+          davname->ns = apr_pstrcat(pool, SVN_DAV_PROP_NS_EXTENSIBLE,
+                                    svn_path_uri_encode(barename, pool),
+                                    (char *)NULL);
+          davname->name = apr_pstrdup(pool, colon + 1);
+        }
     }
+
+  /* Otherwise, we distinguish only between "svn:*" and everything else. */
   else
     {
-      *repos_propname = NULL;
+      if (strncmp(propname, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
+        {
+          davname->ns = SVN_DAV_PROP_NS_SVN;
+          davname->name = apr_pstrdup(pool, propname + 4);
+        }
+      else
+        {
+          davname->ns = SVN_DAV_PROP_NS_CUSTOM;
+          davname->name = apr_pstrdup(pool, propname);
+        }
     }
+
+  return davname;
 }
 
 
@@ -100,7 +184,7 @@ get_value(dav_db *db, const dav_prop_nam
   svn_error_t *serr;
 
   /* get the repos-local name */
-  get_repos_propname(db, name, &propname);
+  propname = davname_to_propname(db, name);
 
   if (propname == NULL)
     {
@@ -172,7 +256,7 @@ save_value(dav_db *db, const dav_prop_na
   const dav_resource *resource = db->resource;
 
   /* get the repos-local name */
-  get_repos_propname(db, name, &propname);
+  propname = davname_to_propname(db, name);
 
   if (propname == NULL)
     {
@@ -360,7 +444,7 @@ db_output_value(dav_db *db,
                 apr_text_header *phdr,
                 int *found)
 {
-  const char *prefix;
+  const char *prefix = "", *xmlns_attr = "";
   const char *s;
   svn_string_t *propval;
   dav_error *err;
@@ -375,14 +459,25 @@ db_output_value(dav_db *db,
     return NULL;
 
   if (strcmp(name->ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
-    prefix = "C:";
-  else
-    prefix = "S:";
+    {
+      prefix = "C:";
+    }
+  else if (strcmp(name->ns, SVN_DAV_PROP_NS_SVN) == 0)
+    {
+      prefix = "S:";
+    }
+  else if (strncmp(name->ns, SVN_DAV_PROP_NS_EXTENSIBLE,
+                   sizeof(SVN_DAV_PROP_NS_EXTENSIBLE) - 1) == 0)
+    {
+      prefix = "";
+      xmlns_attr = apr_pstrcat(pool, " xmlns=\"", name->ns, "\"", (char 
*)NULL);
+    }
 
   if (propval->len == 0)
     {
       /* empty value. add an empty elem. */
-      s = apr_psprintf(pool, "<%s%s/>" DEBUG_CR, prefix, name->name);
+      s = apr_psprintf(pool, "<%s%s%s/>" DEBUG_CR,
+                       prefix, name->name, xmlns_attr);
       apr_text_append(pool, phdr, s);
     }
   else
@@ -407,7 +502,8 @@ db_output_value(dav_db *db,
           xml_safe = xmlval->data;
         }
 
-      s = apr_psprintf(pool, "<%s%s%s>", prefix, name->name, encoding);
+      s = apr_psprintf(pool, "<%s%s%s%s>",
+                       prefix, name->name, encoding, xmlns_attr);
       apr_text_append(pool, phdr, s);
 
       /* the value is in our pool which means it has the right lifetime. */
@@ -540,7 +636,7 @@ db_remove(dav_db *db, const dav_prop_nam
   const char *propname;
 
   /* get the repos-local name */
-  get_repos_propname(db, name, &propname);
+  propname = davname_to_propname(db, name);
 
   /* ### non-svn props aren't in our repos, so punt for now */
   if (propname == NULL)
@@ -588,7 +684,7 @@ db_exists(dav_db *db, const dav_prop_nam
   int retval;
 
   /* get the repos-local name */
-  get_repos_propname(db, name, &propname);
+  propname = davname_to_propname(db, name);
 
   /* ### non-svn props aren't in our repos */
   if (propname == NULL)
@@ -627,21 +723,16 @@ static void get_name(dav_db *db, dav_pro
   else
     {
       const void *name;
+      apr_ssize_t namelen;
+      dav_prop_name *dav_name;
 
-      apr_hash_this(db->hi, &name, NULL, NULL);
-
-#define PREFIX_LEN (sizeof(SVN_PROP_PREFIX) - 1)
-      if (strncmp(name, SVN_PROP_PREFIX, PREFIX_LEN) == 0)
-#undef PREFIX_LEN
-        {
-          pname->ns = SVN_DAV_PROP_NS_SVN;
-          pname->name = (const char *)name + 4;
-        }
-      else
-        {
-          pname->ns = SVN_DAV_PROP_NS_CUSTOM;
-          pname->name = name;
-        }
+      apr_hash_this(db->hi, &name, &namelen, NULL);
+      dav_name = propname_to_davname(
+                     name, namelen,
+                     db->resource->info->repos->use_ext_prop_ns,
+                     db->resource->pool);
+      pname->ns = dav_name->ns;
+      pname->name = dav_name->name;
     }
 }
 

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c 
(original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c Mon Dec 
24 02:59:18 2012
@@ -42,6 +42,7 @@
 #include "mod_dav_svn.h"
 
 #include "private/svn_fspath.h"
+#include "private/svn_subr_private.h"
 
 #include "dav_svn.h"
 #include "mod_authz_svn.h"
@@ -88,11 +89,11 @@ typedef struct dir_conf_t {
   enum conf_flag autoversioning;     /* whether autoversioning is active */
   enum conf_flag bulk_updates;       /* whether bulk updates are allowed */
   enum conf_flag v2_protocol;        /* whether HTTP v2 is advertised */
-  enum conf_flag ephemeral_txnprops; /* advertise ephemeral txnprop support? */
   enum path_authz_conf path_authz_method; /* how GET subrequests are handled */
   enum conf_flag list_parentpath;    /* whether to allow GET of parentpath */
   const char *root_dir;              /* our top-level directory */
   const char *master_uri;            /* URI to the master SVN repos */
+  svn_version_t *master_version;     /* version of master server */
   const char *activities_db;         /* path to activities database(s) */
   enum conf_flag txdelta_cache;      /* whether to enable txdelta caching */
   enum conf_flag fulltext_cache;     /* whether to enable fulltext caching */
@@ -197,7 +198,6 @@ create_dir_config(apr_pool_t *p, char *d
     conf->root_dir = svn_urlpath__canonicalize(dir, p);
   conf->bulk_updates = CONF_FLAG_ON;
   conf->v2_protocol = CONF_FLAG_ON;
-  conf->ephemeral_txnprops = CONF_FLAG_ON;
   conf->hooks_env = NULL;
 
   return conf;
@@ -216,6 +216,7 @@ merge_dir_config(apr_pool_t *p, void *ba
 
   newconf->fs_path = INHERIT_VALUE(parent, child, fs_path);
   newconf->master_uri = INHERIT_VALUE(parent, child, master_uri);
+  newconf->master_version = INHERIT_VALUE(parent, child, master_version);
   newconf->activities_db = INHERIT_VALUE(parent, child, activities_db);
   newconf->repo_name = INHERIT_VALUE(parent, child, repo_name);
   newconf->xslt_uri = INHERIT_VALUE(parent, child, xslt_uri);
@@ -223,8 +224,6 @@ merge_dir_config(apr_pool_t *p, void *ba
   newconf->autoversioning = INHERIT_VALUE(parent, child, autoversioning);
   newconf->bulk_updates = INHERIT_VALUE(parent, child, bulk_updates);
   newconf->v2_protocol = INHERIT_VALUE(parent, child, v2_protocol);
-  newconf->ephemeral_txnprops = INHERIT_VALUE(parent, child,
-                                              ephemeral_txnprops);
   newconf->path_authz_method = INHERIT_VALUE(parent, child, path_authz_method);
   newconf->list_parentpath = INHERIT_VALUE(parent, child, list_parentpath);
   newconf->txdelta_cache = INHERIT_VALUE(parent, child, txdelta_cache);
@@ -286,6 +285,25 @@ SVNMasterURI_cmd(cmd_parms *cmd, void *c
 
 
 static const char *
+SVNMasterVersion_cmd(cmd_parms *cmd, void *config, const char *arg1)
+{
+  dir_conf_t *conf = config;
+  svn_error_t *err;
+  svn_version_t *version;
+
+  err = svn_version__parse_version_string(&version, arg1, cmd->pool);
+  if (err)
+    {
+      svn_error_clear(err);
+      return "Malformed master server version string.";
+    }
+  
+  conf->master_version = version;
+  return NULL;
+}
+
+
+static const char *
 SVNActivitiesDB_cmd(cmd_parms *cmd, void *config, const char *arg1)
 {
   dir_conf_t *conf = config;
@@ -350,20 +368,6 @@ SVNAdvertiseV2Protocol_cmd(cmd_parms *cm
 
 
 static const char *
-SVNAdvertiseEphemeralTXNProps_cmd(cmd_parms *cmd, void *config, int arg)
-{
-  dir_conf_t *conf = config;
-
-  if (arg)
-    conf->ephemeral_txnprops = CONF_FLAG_ON;
-  else
-    conf->ephemeral_txnprops = CONF_FLAG_OFF;
-
-  return NULL;
-}
-
-
-static const char *
 SVNPathAuthz_cmd(cmd_parms *cmd, void *config, const char *arg1)
 {
   dir_conf_t *conf = config;
@@ -673,6 +677,16 @@ dav_svn__get_master_uri(request_rec *r)
 }
 
 
+svn_version_t *
+dav_svn__get_master_version(request_rec *r)
+{
+  dir_conf_t *conf;
+
+  conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
+  return conf->master_uri ? conf->master_version : NULL;
+}
+
+
 const char *
 dav_svn__get_xslt_uri(request_rec *r)
 {
@@ -770,22 +784,54 @@ dav_svn__get_bulk_updates_flag(request_r
 
 
 svn_boolean_t
-dav_svn__get_v2_protocol_flag(request_rec *r)
+dav_svn__check_httpv2_support(request_rec *r)
 {
   dir_conf_t *conf;
+  svn_boolean_t available;
 
   conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
-  return conf->v2_protocol == CONF_FLAG_ON;
+  available = conf->v2_protocol == CONF_FLAG_ON;
+
+  /* If our configuration says that HTTPv2 is available, but we are
+     proxying requests to a master Subversion server which lacks
+     support for HTTPv2, we dumb ourselves down. */
+  if (available)
+    {
+      svn_version_t *version = dav_svn__get_master_version(r);
+      if (version && (! svn_version__at_least(version, 1, 7, 0)))
+        available = FALSE;
+    }
+  return available;
 }
 
 
 svn_boolean_t
-dav_svn__get_ephemeral_txnprops_flag(request_rec *r)
+dav_svn__check_ephemeral_txnprops_support(request_rec *r)
 {
-  dir_conf_t *conf;
+  svn_version_t *version = dav_svn__get_master_version(r);
 
-  conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
-  return conf->ephemeral_txnprops == CONF_FLAG_ON;
+  /* We know this server supports ephemeral txnprops.  But if we're
+     proxying requests to a master server, we need to see if it
+     supports them, too.  */
+  if (version && (! svn_version__at_least(version, 1, 8, 0)))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+svn_boolean_t
+dav_svn__check_prop_ext_ns_support(request_rec *r)
+{
+  svn_version_t *version = dav_svn__get_master_version(r);
+
+  /* We know this server supports extensible property namespaces.  But
+     if we're proxying requests to a master server, we need to see if
+     it supports them, too.  */
+  if (version && (! svn_version__at_least(version, 1, 8, 0)))
+    return FALSE;
+
+  return TRUE;
 }
 
 
@@ -1071,6 +1117,11 @@ static const command_rec cmds[] =
                 "specifies a URI to access a master Subversion repository"),
 
   /* per directory/location */
+  AP_INIT_TAKE1("SVNMasterVersion", SVNMasterVersion_cmd, NULL, ACCESS_CONF,
+                "specifies the Subversion release version of a master "
+                "Subversion server "),
+  
+  /* per directory/location */
   AP_INIT_TAKE1("SVNActivitiesDB", SVNActivitiesDB_cmd, NULL, ACCESS_CONF,
                 "specifies the location in the filesystem in which the "
                 "activities database(s) should be stored"),
@@ -1089,12 +1140,6 @@ static const command_rec cmds[] =
                "Subversion's HTTP protocol (default values is On)."),
 
   /* per directory/location */
-  AP_INIT_FLAG("SVNAdvertiseEphemeralTXNProps",
-               SVNAdvertiseEphemeralTXNProps_cmd, NULL, ACCESS_CONF|RSRC_CONF,
-               "enables server advertising of support for ephemeral "
-               "commit transaction properties (default value is On)."),
-
-  /* per directory/location */
   AP_INIT_FLAG("SVNCacheTextDeltas", SVNCacheTextDeltas_cmd, NULL,
                ACCESS_CONF|RSRC_CONF,
                "speeds up data access to older revisions by caching "

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c Mon Dec 24 
02:59:18 2012
@@ -1502,7 +1502,7 @@ get_parentpath_resource(request_rec *r,
   repos->xslt_uri = dav_svn__get_xslt_uri(r);
   repos->autoversioning = dav_svn__get_autoversioning_flag(r);
   repos->bulk_updates = dav_svn__get_bulk_updates_flag(r);
-  repos->v2_protocol = dav_svn__get_v2_protocol_flag(r);
+  repos->v2_protocol = dav_svn__check_httpv2_support(r);
   repos->base_url = ap_construct_url(r->pool, "", r);
   repos->special_uri = dav_svn__get_special_uri(r);
   repos->username = r->user;
@@ -2082,7 +2082,7 @@ get_resource(request_rec *r,
   repos->bulk_updates = dav_svn__get_bulk_updates_flag(r);
 
   /* Are we advertising HTTP v2 protocol support? */
-  repos->v2_protocol = dav_svn__get_v2_protocol_flag(r);
+  repos->v2_protocol = dav_svn__check_httpv2_support(r);
 
   /* Path to activities database */
   repos->activities_db = dav_svn__get_activities_db(r);
@@ -2143,6 +2143,14 @@ get_resource(request_rec *r,
                              SVN_RA_CAPABILITY_MERGEINFO,
                              APR_HASH_KEY_STRING, capability_yes);
               }
+
+            /* We don't need to report the DAV-specific extensible
+               property XML namespace capability to hook scripts, so
+               we'll just stash it in our repos structure. */
+            if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PROP_EXT_NS, vals))
+              {
+                repos->use_ext_prop_ns = TRUE;
+              }
           }
       }
   }

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c?rev=1425578&r1=1425577&r2=1425578&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c (original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c Mon Dec 24 
02:59:18 2012
@@ -37,7 +37,9 @@
 #include "svn_props.h"
 #include "svn_dav.h"
 #include "svn_base64.h"
+#include "svn_version.h"
 #include "private/svn_repos_private.h"
+#include "private/svn_subr_private.h"
 #include "private/svn_dav_protocol.h"
 #include "private/svn_log.h"
 #include "private/svn_fspath.h"
@@ -195,12 +197,18 @@ get_option(const dav_resource *resource,
 
   /* If we're allowed (by configuration) to do so, advertise support
      for ephemeral transaction properties. */
-  if (dav_svn__get_ephemeral_txnprops_flag(r))
+  if (dav_svn__check_ephemeral_txnprops_support(r))
     {
       apr_table_addn(r->headers_out, "DAV",
                      SVN_DAV_NS_DAV_SVN_EPHEMERAL_TXNPROPS);
     }
 
+  if (dav_svn__check_prop_ext_ns_support(r))
+    {
+      apr_table_addn(r->headers_out, "DAV",
+                     SVN_DAV_NS_DAV_SVN_PROP_EXT_NS);
+    }
+
   if (resource->info->repos->fs)
     {
       svn_error_t *serr;
@@ -246,12 +254,15 @@ get_option(const dav_resource *resource,
       /* The list of Subversion's custom POSTs.  You'll want to keep
          this in sync with the handling of these suckers in
          handle_post_request().  */
-      static const char * posts_list[] = {
-        "create-txn",
-        "create-txn-with-props",
-        NULL
+      int i;
+      svn_version_t *master_version = dav_svn__get_master_version(r);
+      struct posts_versions_t {
+        const char *post_name;
+        svn_version_t min_version;
+      } posts_versions[] = {
+        { "create-txn",             { 1, 7, 0, "" } },
+        { "create-txn-with-props",  { 1, 8, 0, "" } },
       };
-      const char **this_post = posts_list;
 
       apr_table_set(r->headers_out, SVN_DAV_ROOT_URI_HEADER, repos_root_uri);
       apr_table_set(r->headers_out, SVN_DAV_ME_RESOURCE_HEADER,
@@ -277,12 +288,20 @@ get_option(const dav_resource *resource,
                                 dav_svn__get_vtxn_stub(r), (char *)NULL));
 
       /* Report the supported POST types. */
-      while (*this_post)
+      for (i = 0; i < sizeof(posts_versions)/sizeof(posts_versions[0]); ++i)
         {
+          /* If we're proxying to a master server and its version
+             number is declared, we can selectively filter out POST
+             types that it doesn't support. */
+          if (master_version
+              && (! svn_version__at_least(master_version,
+                                          posts_versions[i].min_version.major,
+                                          posts_versions[i].min_version.minor,
+                                          
posts_versions[i].min_version.patch)))
+            continue;
+
           apr_table_addn(r->headers_out, SVN_DAV_SUPPORTED_POSTS_HEADER,
-                         apr_pstrcat(resource->pool, *this_post,
-                                     (char *)NULL));
-          this_post++;
+                         apr_pstrdup(resource->pool, 
posts_versions[i].post_name));
         }
     }
 


Reply via email to