{"action":"created","comment":{"url":"https://api.github.com/repos/cloudant/java-cloudant/pulls/comments/40649481","id":40649481,"diff_hunk":"@@ -0,0 +1,364 @@\n+//  Copyright (c) 2015 IBM Cloudant. All rights reserved.\n+//\n+//  Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file\n+//  except in compliance with the License. You may obtain a copy of the License at\n+//  http://www.apache.org/licenses/LICENSE-2.0\n+//  Unless required by applicable law or agreed to in writing, software distributed under the\n+//  License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n+//  either express or implied. See the License for the specific language governing permissions\n+//  and limitations under the License.\n+\n+package com.cloudant.http;\n+\n+import org.apache.commons.codec.binary.Base64OutputStream;\n+import org.apache.commons.io.IOUtils;\n+\n+import java.io.ByteArrayInputStream;\n+import java.io.ByteArrayOutputStream;\n+import java.io.IOException;\n+import java.io.InputStream;\n+import java.io.OutputStream;\n+import java.io.UnsupportedEncodingException;\n+import java.net.HttpURLConnection;\n+import java.net.URL;\n+import java.util.HashMap;\n+import java.util.LinkedList;\n+import java.util.List;\n+import java.util.Properties;\n+import java.util.logging.Logger;\n+\n+\n+/**\n+ * Created by tomblench on 23/03/15.\n+ */\n+\n+/**\n+ * <p>\n+ * A wrapper for <code>HttpURLConnection</code>s.\n+ * </p>\n+ *\n+ * <p>\n+ * Provides some convenience methods for making requests and sending/receiving data as streams,\n+ * strings, or byte arrays.\n+ * </p>\n+ *\n+ * <p>\n+ * Typical usage:\n+ * </p>\n+ *\n+ * <pre>\n+ * HttpConnection hc = new HttpConnection(\"POST\", \"application/json\", new URL(\"http://somewhere\"));\n+ * hc.requestProperties.put(\"x-some-header\", \"some-value\");\n+ * hc.setRequestBody(\"{\\\"hello\\\": \\\"world\\\"});\n+ * String result = hc.execute().responseAsString();\n+ * // get the underlying HttpURLConnection if you need to do something a bit more advanced:\n+ * int response = hc.getConnection().getResponseCode();\n+ * hc.disconnect();\n+ * </pre>\n+ *\n+ * <p>\n+ * <b>Important:</b> this class is not thread-safe and <code>HttpConnection</code>s should not be\n+ * shared across threads.\n+ * </p>\n+ *\n+ * @see java.net.HttpURLConnection\n+ */\n+public class HttpConnection  {\n+\n+    private static final Logger logger = Logger.getLogger(HttpConnection.class.getCanonicalName());\n+    private final String requestMethod;\n+    public final URL url;\n+    private final String contentType;\n+\n+    // created in executeInternal\n+    private HttpURLConnection connection;\n+\n+    // set by the various setRequestBody() methods\n+    private InputStream input;\n+    private long inputLength;\n+\n+    public final HashMap<String, String> requestProperties;\n+\n+    private static String userAgent = getUserAgent();\n+\n+    public final List<HttpConnectionRequestInterceptor> requestInterceptors;\n+    public final List<HttpConnectionResponseInterceptor> responseInterceptors;\n+\n+    private int numberOfRetries = 10;\n+\n+\n+    public HttpConnection(String requestMethod,\n+                          URL url,\n+                          String contentType) {\n+        this.requestMethod = requestMethod;\n+        this.url = url;\n+        this.contentType = contentType;\n+        this.requestProperties = new HashMap<String, String>();\n+        this.requestInterceptors = new LinkedList<HttpConnectionRequestInterceptor>();\n+        this.responseInterceptors = new LinkedList<HttpConnectionResponseInterceptor>();\n+    }\n+\n+    /**\n+     * Sets the number of times this request can be retried.\n+     * This method <strong>must</strong> be called before {@link #execute()}\n+     * @param numberOfRetries the number of times this request can be retried.\n+     * @return an {@link HttpConnection} for method chaining \n+     */\n+    public HttpConnection setNumberOfRetries(int numberOfRetries){\n+        this.numberOfRetries = numberOfRetries;\n+        return this;\n+    }\n+\n+    /**\n+     * Set the String of request body data to be sent to the server.\n+     * @param input String of request body data to be sent to the server\n+     * @return an {@link HttpConnection} for method chaining \n+     */\n+    public HttpConnection setRequestBody(final String input) {\n+        try {\n+            this.input = new ByteArrayInputStream(input.getBytes(\"UTF-8\"));\n+            // input is in bytes, not characters\n+            this.inputLength = input.getBytes().length;\n+        } catch (UnsupportedEncodingException e) {\n+            // This should never happen as every implementation of the java platform is required\n+            // to support UTF-8.\n+        }\n+        return this;\n+    }\n+\n+    /**\n+     * Set the byte array of request body data to be sent to the server.\n+     * @param input byte array of request body data to be sent to the server\n+     * @return an {@link HttpConnection} for method chaining \n+     */\n+    public HttpConnection setRequestBody(final byte[] input) {\n+        this.input = new ByteArrayInputStream(input);\n+        this.inputLength = input.length;\n+        return this;\n+    }\n+\n+    /**\n+     * Set the InputStream of request body data to be sent to the server.\n+     * @param input InputStream of request body data to be sent to the server\n+     * @return an {@link HttpConnection} for method chaining \n+     */\n+    public HttpConnection setRequestBody(InputStream input) {\n+        this.input = input;\n+        // -1 signals inputLength unknown\n+        this.inputLength = -1;\n+        return this;\n+    }\n+\n+    /**\n+     * Set the InputStream of request body data, of known length, to be sent to the server.\n+     * @param input InputStream of request body data to be sent to the server\n+     * @param inputLength Length of request body data to be sent to the server, in bytes\n+     * @return an {@link HttpConnection} for method chaining \n+     */\n+    public HttpConnection setRequestBody(InputStream input, long inputLength) {\n+        this.input = input;\n+        this.inputLength = inputLength;\n+        return this;\n+    }\n+\n+    /**\n+     * <p>\n+     * Execute request without returning data from server.\n+     * </p>\n+     * <p>\n+     * Call {@code responseAsString}, {@code responseAsBytes}, or {@code responseAsInputStream}\n+     * after {@code execute} if the response body is required.\n+     * </p>\n+     * @return An {@link HttpConnection} which can be used to obtain the response body\n+     * @throws IOException if there was a problem writing data to the server\n+     */\n+    public HttpConnection execute() throws IOException {\n+            boolean retry = true;\n+            int n = numberOfRetries;\n+            while (retry && n-- > 0) {\n+\n+                System.setProperty(\"http.keepAlive\", \"false\");\n+\n+                connection = (HttpURLConnection) url.openConnection();\n+                for (String key : requestProperties.keySet()) {\n+                    connection.setRequestProperty(key, requestProperties.get(key));\n+                }\n+\n+                connection.setRequestProperty(\"User-Agent\", userAgent);","path":"src/main/java/com/cloudant/http/HttpConnection.java","position":187,"original_position":187,"commit_id":"b261534198c3d931940284838462ccaa7ef3a9e9","original_commit_id":"b261534198c3d931940284838462ccaa7ef3a9e9","user":{"login":"tomblench","id":6302842,"avatar_url":"https://avatars.githubusercontent.com/u/6302842?v=3","gravatar_id":"","url":"https://api.github.com/users/tomblench","html_url":"https://github.com/tomblench","followers_url":"https://api.github.com/users/tomblench/followers","following_url":"https://api.github.com/users/tomblench/following{/other_user}","gists_url":"https://api.github.com/users/tomblench/gists{/gist_id}","starred_url":"https://api.github.com/users/tomblench/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tomblench/subscriptions","organizations_url":"https://api.github.com/users/tomblench/orgs","repos_url":"https://api.github.com/users/tomblench/repos","events_url":"https://api.github.com/users/tomblench/events{/privacy}","received_events_url":"https://api.github.com/users/tomblench/received_events","type":"User","site_admin":false},"body":"Use `CouchDbClient.USER_AGENT`: https://github.com/cloudant/java-cloudant/blob/master/src/main/java/com/cloudant/client/org/lightcouch/CouchDbClient.java#L125","created_at":"2015-09-29T09:09:58Z","updated_at":"2015-09-29T09:09:58Z","html_url":"https://github.com/cloudant/java-cloudant/pull/97#discussion_r40649481","pull_request_url":"https://api.github.com/repos/cloudant/java-cloudant/pulls/97","_links":{"self":{"href":"https://api.github.com/repos/cloudant/java-cloudant/pulls/comments/40649481"},"html":{"href":"https://github.com/cloudant/java-cloudant/pull/97#discussion_r40649481"},"pull_request":{"href":"https://api.github.com/repos/cloudant/java-cloudant/pulls/97"}}},"pull_request":{"url":"https://api.github.com/repos/cloudant/java-cloudant/pulls/97","id":46170565,"html_url":"https://github.com/cloudant/java-cloudant/pull/97","diff_url":"https://github.com/cloudant/java-cloudant/pull/97.diff","patch_url":"https://github.com/cloudant/java-cloudant/pull/97.patch","issue_url":"https://api.github.com/repos/cloudant/java-cloudant/issues/97","number":97,"state":"open","locked":false,"title":"Replace Apache HttpClient with sync-android's com.cloudant.http","user":{"login":"emlaver","id":10552966,"avatar_url":"https://avatars.githubusercontent.com/u/10552966?v=3","gravatar_id":"","url":"https://api.github.com/users/emlaver","html_url":"https://github.com/emlaver","followers_url":"https://api.github.com/users/emlaver/followers","following_url":"https://api.github.com/users/emlaver/following{/other_user}","gists_url":"https://api.github.com/users/emlaver/gists{/gist_id}","starred_url":"https://api.github.com/users/emlaver/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emlaver/subscriptions","organizations_url":"https://api.github.com/users/emlaver/orgs","repos_url":"https://api.github.com/users/emlaver/repos","events_url":"https://api.github.com/users/emlaver/events{/privacy}","received_events_url":"https://api.github.com/users/emlaver/received_events","type":"User","site_admin":false},"body":"*What*\r\nThis is the first part in a series of PRs for replacing the current http dependency of Apache’s `httpclient` with sync-android's `HttpURLConnection`.  Migrating to HttpUrlConnection is required for us to use java-cloudant within sync-android.\r\n\r\n*How*\r\n- Move required classes over from sync’s http package\r\n- Call `org.apache.commons.codec.binary.Base64OutputStream` directly instead of sync-android's `Base64OutputStreamFactory`:\r\n  https://github.com/cloudant/java-cloudant/blob/48522-1-add-http-classes/src/main/java/com/cloudant/http/HttpConnection.java#L193\r\n\r\n- Add required dependencies in build.gradle \r\n\r\n*Tests*\r\nNo tests required.\r\n\r\nFogBugz: 48522\r\n\r\nreviewer @ricellis ","created_at":"2015-09-28T15:26:23Z","updated_at":"2015-09-29T09:09:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1488a2edef7bdb8595e97a96c4b2c7858c751929","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/cloudant/java-cloudant/pulls/97/commits","review_comments_url":"https://api.github.com/repos/cloudant/java-cloudant/pulls/97/comments","review_comment_url":"https://api.github.com/repos/cloudant/java-cloudant/pulls/comments{/number}","comments_url":"https://api.github.com/repos/cloudant/java-cloudant/issues/97/comments","statuses_url":"https://api.github.com/repos/cloudant/java-cloudant/statuses/b261534198c3d931940284838462ccaa7ef3a9e9","head":{"label":"cloudant:48522-1-add-http-classes","ref":"48522-1-add-http-classes","sha":"b261534198c3d931940284838462ccaa7ef3a9e9","user":{"login":"cloudant","id":44642,"avatar_url":"https://avatars.githubusercontent.com/u/44642?v=3","gravatar_id":"","url":"https://api.github.com/users/cloudant","html_url":"https://github.com/cloudant","followers_url":"https://api.github.com/users/cloudant/followers","following_url":"https://api.github.com/users/cloudant/following{/other_user}","gists_url":"https://api.github.com/users/cloudant/gists{/gist_id}","starred_url":"https://api.github.com/users/cloudant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cloudant/subscriptions","organizations_url":"https://api.github.com/users/cloudant/orgs","repos_url":"https://api.github.com/users/cloudant/repos","events_url":"https://api.github.com/users/cloudant/events{/privacy}","received_events_url":"https://api.github.com/users/cloudant/received_events","type":"Organization","site_admin":false},"repo":{"id":22873328,"name":"java-cloudant","full_name":"cloudant/java-cloudant","owner":{"login":"cloudant","id":44642,"avatar_url":"https://avatars.githubusercontent.com/u/44642?v=3","gravatar_id":"","url":"https://api.github.com/users/cloudant","html_url":"https://github.com/cloudant","followers_url":"https://api.github.com/users/cloudant/followers","following_url":"https://api.github.com/users/cloudant/following{/other_user}","gists_url":"https://api.github.com/users/cloudant/gists{/gist_id}","starred_url":"https://api.github.com/users/cloudant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cloudant/subscriptions","organizations_url":"https://api.github.com/users/cloudant/orgs","repos_url":"https://api.github.com/users/cloudant/repos","events_url":"https://api.github.com/users/cloudant/events{/privacy}","received_events_url":"https://api.github.com/users/cloudant/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/cloudant/java-cloudant","description":"A Java client for Cloudant","fork":false,"url":"https://api.github.com/repos/cloudant/java-cloudant","forks_url":"https://api.github.com/repos/cloudant/java-cloudant/forks","keys_url":"https://api.github.com/repos/cloudant/java-cloudant/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cloudant/java-cloudant/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cloudant/java-cloudant/teams","hooks_url":"https://api.github.com/repos/cloudant/java-cloudant/hooks","issue_events_url":"https://api.github.com/repos/cloudant/java-cloudant/issues/events{/number}","events_url":"https://api.github.com/repos/cloudant/java-cloudant/events","assignees_url":"https://api.github.com/repos/cloudant/java-cloudant/assignees{/user}","branches_url":"https://api.github.com/repos/cloudant/java-cloudant/branches{/branch}","tags_url":"https://api.github.com/repos/cloudant/java-cloudant/tags","blobs_url":"https://api.github.com/repos/cloudant/java-cloudant/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cloudant/java-cloudant/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cloudant/java-cloudant/git/refs{/sha}","trees_url":"https://api.github.com/repos/cloudant/java-cloudant/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cloudant/java-cloudant/statuses/{sha}","languages_url":"https://api.github.com/repos/cloudant/java-cloudant/languages","stargazers_url":"https://api.github.com/repos/cloudant/java-cloudant/stargazers","contributors_url":"https://api.github.com/repos/cloudant/java-cloudant/contributors","subscribers_url":"https://api.github.com/repos/cloudant/java-cloudant/subscribers","subscription_url":"https://api.github.com/repos/cloudant/java-cloudant/subscription","commits_url":"https://api.github.com/repos/cloudant/java-cloudant/commits{/sha}","git_commits_url":"https://api.github.com/repos/cloudant/java-cloudant/git/commits{/sha}","comments_url":"https://api.github.com/repos/cloudant/java-cloudant/comments{/number}","issue_comment_url":"https://api.github.com/repos/cloudant/java-cloudant/issues/comments{/number}","contents_url":"https://api.github.com/repos/cloudant/java-cloudant/contents/{+path}","compare_url":"https://api.github.com/repos/cloudant/java-cloudant/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cloudant/java-cloudant/merges","archive_url":"https://api.github.com/repos/cloudant/java-cloudant/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cloudant/java-cloudant/downloads","issues_url":"https://api.github.com/repos/cloudant/java-cloudant/issues{/number}","pulls_url":"https://api.github.com/repos/cloudant/java-cloudant/pulls{/number}","milestones_url":"https://api.github.com/repos/cloudant/java-cloudant/milestones{/number}","notifications_url":"https://api.github.com/repos/cloudant/java-cloudant/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cloudant/java-cloudant/labels{/name}","releases_url":"https://api.github.com/repos/cloudant/java-cloudant/releases{/id}","created_at":"2014-08-12T10:19:56Z","updated_at":"2015-08-29T22:23:01Z","pushed_at":"2015-09-28T18:30:54Z","git_url":"git://github.com/cloudant/java-cloudant.git","ssh_url":"git@github.com:cloudant/java-cloudant.git","clone_url":"https://github.com/cloudant/java-cloudant.git","svn_url":"https://github.com/cloudant/java-cloudant","homepage":null,"size":4203,"stargazers_count":14,"watchers_count":14,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"open_issues_count":8,"forks":16,"open_issues":8,"watchers":14,"default_branch":"master"}},"base":{"label":"cloudant:feature-http-replacement","ref":"feature-http-replacement","sha":"39996502fb59599e2978ecc408fa9f045b1af323","user":{"login":"cloudant","id":44642,"avatar_url":"https://avatars.githubusercontent.com/u/44642?v=3","gravatar_id":"","url":"https://api.github.com/users/cloudant","html_url":"https://github.com/cloudant","followers_url":"https://api.github.com/users/cloudant/followers","following_url":"https://api.github.com/users/cloudant/following{/other_user}","gists_url":"https://api.github.com/users/cloudant/gists{/gist_id}","starred_url":"https://api.github.com/users/cloudant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cloudant/subscriptions","organizations_url":"https://api.github.com/users/cloudant/orgs","repos_url":"https://api.github.com/users/cloudant/repos","events_url":"https://api.github.com/users/cloudant/events{/privacy}","received_events_url":"https://api.github.com/users/cloudant/received_events","type":"Organization","site_admin":false},"repo":{"id":22873328,"name":"java-cloudant","full_name":"cloudant/java-cloudant","owner":{"login":"cloudant","id":44642,"avatar_url":"https://avatars.githubusercontent.com/u/44642?v=3","gravatar_id":"","url":"https://api.github.com/users/cloudant","html_url":"https://github.com/cloudant","followers_url":"https://api.github.com/users/cloudant/followers","following_url":"https://api.github.com/users/cloudant/following{/other_user}","gists_url":"https://api.github.com/users/cloudant/gists{/gist_id}","starred_url":"https://api.github.com/users/cloudant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cloudant/subscriptions","organizations_url":"https://api.github.com/users/cloudant/orgs","repos_url":"https://api.github.com/users/cloudant/repos","events_url":"https://api.github.com/users/cloudant/events{/privacy}","received_events_url":"https://api.github.com/users/cloudant/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/cloudant/java-cloudant","description":"A Java client for Cloudant","fork":false,"url":"https://api.github.com/repos/cloudant/java-cloudant","forks_url":"https://api.github.com/repos/cloudant/java-cloudant/forks","keys_url":"https://api.github.com/repos/cloudant/java-cloudant/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cloudant/java-cloudant/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cloudant/java-cloudant/teams","hooks_url":"https://api.github.com/repos/cloudant/java-cloudant/hooks","issue_events_url":"https://api.github.com/repos/cloudant/java-cloudant/issues/events{/number}","events_url":"https://api.github.com/repos/cloudant/java-cloudant/events","assignees_url":"https://api.github.com/repos/cloudant/java-cloudant/assignees{/user}","branches_url":"https://api.github.com/repos/cloudant/java-cloudant/branches{/branch}","tags_url":"https://api.github.com/repos/cloudant/java-cloudant/tags","blobs_url":"https://api.github.com/repos/cloudant/java-cloudant/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cloudant/java-cloudant/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cloudant/java-cloudant/git/refs{/sha}","trees_url":"https://api.github.com/repos/cloudant/java-cloudant/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cloudant/java-cloudant/statuses/{sha}","languages_url":"https://api.github.com/repos/cloudant/java-cloudant/languages","stargazers_url":"https://api.github.com/repos/cloudant/java-cloudant/stargazers","contributors_url":"https://api.github.com/repos/cloudant/java-cloudant/contributors","subscribers_url":"https://api.github.com/repos/cloudant/java-cloudant/subscribers","subscription_url":"https://api.github.com/repos/cloudant/java-cloudant/subscription","commits_url":"https://api.github.com/repos/cloudant/java-cloudant/commits{/sha}","git_commits_url":"https://api.github.com/repos/cloudant/java-cloudant/git/commits{/sha}","comments_url":"https://api.github.com/repos/cloudant/java-cloudant/comments{/number}","issue_comment_url":"https://api.github.com/repos/cloudant/java-cloudant/issues/comments{/number}","contents_url":"https://api.github.com/repos/cloudant/java-cloudant/contents/{+path}","compare_url":"https://api.github.com/repos/cloudant/java-cloudant/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cloudant/java-cloudant/merges","archive_url":"https://api.github.com/repos/cloudant/java-cloudant/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cloudant/java-cloudant/downloads","issues_url":"https://api.github.com/repos/cloudant/java-cloudant/issues{/number}","pulls_url":"https://api.github.com/repos/cloudant/java-cloudant/pulls{/number}","milestones_url":"https://api.github.com/repos/cloudant/java-cloudant/milestones{/number}","notifications_url":"https://api.github.com/repos/cloudant/java-cloudant/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cloudant/java-cloudant/labels{/name}","releases_url":"https://api.github.com/repos/cloudant/java-cloudant/releases{/id}","created_at":"2014-08-12T10:19:56Z","updated_at":"2015-08-29T22:23:01Z","pushed_at":"2015-09-28T18:30:54Z","git_url":"git://github.com/cloudant/java-cloudant.git","ssh_url":"git@github.com:cloudant/java-cloudant.git","clone_url":"https://github.com/cloudant/java-cloudant.git","svn_url":"https://github.com/cloudant/java-cloudant","homepage":null,"size":4203,"stargazers_count":14,"watchers_count":14,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"open_issues_count":8,"forks":16,"open_issues":8,"watchers":14,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/cloudant/java-cloudant/pulls/97"},"html":{"href":"https://github.com/cloudant/java-cloudant/pull/97"},"issue":{"href":"https://api.github.com/repos/cloudant/java-cloudant/issues/97"},"comments":{"href":"https://api.github.com/repos/cloudant/java-cloudant/issues/97/comments"},"review_comments":{"href":"https://api.github.com/repos/cloudant/java-cloudant/pulls/97/comments"},"review_comment":{"href":"https://api.github.com/repos/cloudant/java-cloudant/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/cloudant/java-cloudant/pulls/97/commits"},"statuses":{"href":"https://api.github.com/repos/cloudant/java-cloudant/statuses/b261534198c3d931940284838462ccaa7ef3a9e9"}}}}