{"action":"created","comment":{"url":"https://api.github.com/repos/apache/nifi/pulls/comments/71981046","id":71981046,"diff_hunk":"@@ -0,0 +1,360 @@\n+/*\n+ * Licensed to the Apache Software Foundation (ASF) under one or more\n+ * contributor license agreements.  See the NOTICE file distributed with\n+ * this work for additional information regarding copyright ownership.\n+ * The ASF licenses this file to You under the Apache License, Version 2.0\n+ * (the \"License\"); you may not use this file except in compliance with\n+ * the License.  You may obtain a copy of the License at\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+package org.apache.nifi.processors.standard;\n+\n+import org.apache.commons.io.IOUtils;\n+import org.apache.commons.lang3.StringUtils;\n+import org.apache.nifi.annotation.behavior.InputRequirement;\n+import org.apache.nifi.annotation.behavior.WritesAttribute;\n+import org.apache.nifi.annotation.documentation.CapabilityDescription;\n+import org.apache.nifi.annotation.documentation.Tags;\n+import org.apache.nifi.annotation.lifecycle.OnScheduled;\n+import org.apache.nifi.components.AllowableValue;\n+import org.apache.nifi.components.PropertyDescriptor;\n+import org.apache.nifi.flowfile.FlowFile;\n+import org.apache.nifi.processor.AbstractProcessor;\n+import org.apache.nifi.processor.ProcessContext;\n+import org.apache.nifi.processor.ProcessSession;\n+import org.apache.nifi.processor.ProcessorInitializationContext;\n+import org.apache.nifi.processor.Relationship;\n+import org.apache.nifi.processor.exception.ProcessException;\n+import org.apache.nifi.processor.io.StreamCallback;\n+import org.apache.nifi.processor.util.StandardValidators;\n+import org.json.JSONArray;\n+import org.json.JSONException;\n+import org.json.JSONObject;\n+import org.json.JSONTokener;\n+\n+import java.io.IOException;\n+import java.io.InputStream;\n+import java.io.OutputStream;\n+import java.util.ArrayList;\n+import java.util.Collections;\n+import java.util.HashSet;\n+import java.util.Iterator;\n+import java.util.LinkedHashMap;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.SortedSet;\n+import java.util.TreeSet;\n+\n+@Tags({\"JSON, CSV, convert\"})\n+@InputRequirement(InputRequirement.Requirement.INPUT_REQUIRED)\n+@WritesAttribute(attribute=\"mime.type\", description=\"Sets the mime type to application/csv\")\n+@CapabilityDescription(\"Converts a JSON document to CSV. This processor reads the entire content \" +\n+        \"of incoming FlowFiles into memory in order to perform the conversion. The processor will parse JSON Arrays, JSON Objects \" +\n+        \"and the combination of the two regardless of the level of nesting in the JSON document.\")\n+public class ConvertJSONtoCSV extends AbstractProcessor {\n+    volatile String delimiter;\n+    volatile String removeFields;\n+    volatile String emptyFields = \"\";\n+\n+    public static final AllowableValue INCLUDE_HEADER_TRUE = new AllowableValue(\n+            \"True\", \"True\", \"Creates headers for each JSON file.\");\n+    public static final AllowableValue INCLUDE_HEADER_FALSE = new AllowableValue(\n+            \"False\", \"False\", \"Only parses the JSON fields and does not include headers\");\n+\n+\n+    public static final PropertyDescriptor DELIMITER = new PropertyDescriptor\n+            .Builder().name(\"CSV Delimiter\")\n+            .description(\"Delimiter used for the generated CSV output (Example: , | -)\")\n+            .required(true)\n+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)\n+            .build();\n+\n+    public static final PropertyDescriptor REMOVE_FIELDS = new PropertyDescriptor\n+            .Builder().name(\"Remove JSON Fields/Columns\")\n+            .description(\"Comma delimited list of columns that should be removed when parsing JSON and building the CSV. \" +\n+                    \"This includes all top level and most granular nested fields/columns. By default with nothing specified every field \" +\n+                    \"will be parsed.\")\n+            .required(false)\n+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)\n+            .build();\n+\n+    public static final PropertyDescriptor EMPTY_FIELDS = new PropertyDescriptor\n+            .Builder().name(\"Empty field value\")\n+            .description(\"During denormalization/flattening of the JSON the value that will be substituted for empty fields values \" +\n+                    \"(Example: NULL). Defaults to empty string if not specified.\")\n+            .required(false)\n+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)\n+            .build();\n+\n+    public static final PropertyDescriptor INCLUDE_HEADERS = new PropertyDescriptor\n+            .Builder().name(\"Include Headers\")\n+            .description(\"Whether or not to include headers in the CSV output\")\n+            .required(true)\n+            .allowableValues(INCLUDE_HEADER_TRUE, INCLUDE_HEADER_FALSE)\n+            .defaultValue(INCLUDE_HEADER_TRUE.getValue())\n+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)\n+            .build();\n+\n+    public static final Relationship RELATIONSHIP_SUCCESS = new Relationship.Builder()\n+            .name(\"success\")\n+            .description(\"Successfully parsing the JSON file to CSV \")\n+            .build();\n+\n+    public static final Relationship RELATIONSHIP_FAILURE = new Relationship.Builder()\n+            .name(\"failure\")\n+            .description(\"Failed parsing the JSON file to CSV \")\n+            .build();\n+\n+    private List<PropertyDescriptor> descriptors;\n+\n+    private Set<Relationship> relationships;\n+\n+    @Override\n+    protected void init(final ProcessorInitializationContext context) {\n+        final List<PropertyDescriptor> descriptors = new ArrayList<PropertyDescriptor>();\n+        descriptors.add(DELIMITER);\n+        descriptors.add(REMOVE_FIELDS);\n+        descriptors.add(EMPTY_FIELDS);\n+        descriptors.add(INCLUDE_HEADERS);\n+        this.descriptors = Collections.unmodifiableList(descriptors);\n+\n+        final Set<Relationship> relationships = new HashSet<Relationship>();\n+        relationships.add(RELATIONSHIP_SUCCESS);\n+        relationships.add(RELATIONSHIP_FAILURE);\n+        this.relationships = Collections.unmodifiableSet(relationships);\n+    }\n+\n+    @Override\n+    public Set<Relationship> getRelationships() {\n+\n+        return this.relationships;\n+    }\n+\n+    @Override\n+    public final List<PropertyDescriptor> getSupportedPropertyDescriptors() {\n+\n+        return descriptors;\n+    }\n+\n+    @OnScheduled\n+    public void onScheduled(final ProcessContext context) {\n+\n+        delimiter = context.getProperty(DELIMITER).getValue();\n+        removeFields = context.getProperty(REMOVE_FIELDS).getValue() == null ? \"\" : context.getProperty(REMOVE_FIELDS).getValue();\n+        emptyFields = context.getProperty(EMPTY_FIELDS).getValue();\n+    }\n+\n+    @Override\n+    public void onTrigger(final ProcessContext context, final ProcessSession session) throws ProcessException {\n+        final String includeHeaders = context.getProperty(INCLUDE_HEADERS).getValue();\n+\n+        FlowFile flowFile = session.get();\n+        if ( flowFile == null ) {\n+            return;\n+        }\n+\n+        try {\n+            flowFile = session.write(flowFile, new StreamCallback() {\n+                @Override\n+                public void process(final InputStream inputStream, final OutputStream outputStream) throws IOException {\n+                    List<Map<String, String>> flatJson;\n+                    try {\n+                        flatJson = JSONParser.parseJSON(IOUtils.toString(inputStream, \"UTF-8\"), getRemoveKeySet());\n+                        if (flatJson == null) {\n+                            throw new IOException(\"Unable to parse JSON file. Please check the file contains valid JSON structure\");\n+                        }\n+                    } catch (JSONException ex) {\n+                        throw new JSONException(\"Unable to parse as JSON appears to be malformed: \" + ex);\n+                    }\n+                    outputStream.write(CSVGenerator.generateCSV(flatJson, delimiter, emptyFields, includeHeaders).toString().getBytes());\n+                }\n+            });\n+\n+            session.transfer(flowFile, RELATIONSHIP_SUCCESS);\n+        } catch (ProcessException | JSONException ex) {\n+            getLogger().error(\"Error converting FlowFile to CSV due to {}\", new Object[] {ex.getMessage()}, ex);\n+            session.transfer(flowFile, RELATIONSHIP_FAILURE);\n+        }\n+\n+    }\n+\n+    private Set<String> getRemoveKeySet() {\n+        Set<String> setRemove = new HashSet<>();\n+\n+        final String[] fields = removeFields.split(\",\");\n+        for (String field : fields) {\n+            setRemove.add(field);\n+        }\n+        return setRemove;\n+    }\n+\n+    private static class JSONParser {\n+\n+        private static final Class<?> JSON_OBJECT = JSONObject.class;\n+\n+        private static final Class<?> JSON_ARRAY = JSONArray.class;\n+\n+        private static Set<String> removeKeySet = new HashSet<>();\n+\n+        public static List<Map<String, String>> parseJSON(String json, Set<String> removeKeys) throws JSONException {\n+            List<Map<String, String>> flatJson = null;\n+            removeKeySet = removeKeys;\n+\n+            // we don't know if we are dealing with a JSON object or an array\n+            // not handling this properly causes un-necessary exception to be thrown\n+            // instantiate to a generic object and check what we are dealing with\n+            Object objJSON = new JSONTokener(json).nextValue();\n+\n+            try {\n+                if (objJSON instanceof JSONObject) {\n+                    JSONObject jsonObject = new JSONObject(json);\n+                    flatJson = new ArrayList<Map<String, String>>();\n+                    flatJson.add(parse(jsonObject));\n+                } else if (objJSON instanceof JSONArray) {\n+                    flatJson = handleAsArray(json);\n+                }\n+            } catch (JSONException ex) {\n+                throw new JSONException(\"JSON might be malformed, please check and make sure it is valid JSON format: \" + ex);\n+            }\n+\n+            return flatJson;\n+        }\n+\n+        public static Map<String, String> parse(JSONObject jsonObject) {\n+            Map<String, String> flatJson = new LinkedHashMap<String, String>();\n+            try {\n+                denormalize(jsonObject, flatJson, \"\");\n+            } catch (Exception ex) {\n+                throw ex;\n+            }\n+            return flatJson;\n+        }\n+\n+        public static List<Map<String, String>> parse(JSONArray jsonArray) {\n+            JSONObject jsonObject = null;\n+            List<Map<String, String>> flatJson = new ArrayList<Map<String, String>>();\n+            int length = jsonArray.length();\n+\n+            for (int i = 0; i < length; i++) {\n+                jsonObject = jsonArray.getJSONObject(i);\n+                Map<String, String> stringMap = parse(jsonObject);\n+                flatJson.add(stringMap);\n+            }\n+\n+            return flatJson;\n+        }\n+\n+        private static List<Map<String, String>> handleAsArray(String json) throws JSONException {\n+            List<Map<String, String>> flatJson = null;\n+\n+            try {\n+                JSONArray jsonArray = new JSONArray(json);\n+                flatJson = parse(jsonArray);","path":"nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ConvertJSONtoCSV.java","position":260,"original_position":260,"commit_id":"115894a8dece76f3d29147f9ef7d60b9e72c0750","original_commit_id":"115894a8dece76f3d29147f9ef7d60b9e72c0750","user":{"login":"mattyb149","id":2124747,"avatar_url":"https://avatars.githubusercontent.com/u/2124747?v=3","gravatar_id":"","url":"https://api.github.com/users/mattyb149","html_url":"https://github.com/mattyb149","followers_url":"https://api.github.com/users/mattyb149/followers","following_url":"https://api.github.com/users/mattyb149/following{/other_user}","gists_url":"https://api.github.com/users/mattyb149/gists{/gist_id}","starred_url":"https://api.github.com/users/mattyb149/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mattyb149/subscriptions","organizations_url":"https://api.github.com/users/mattyb149/orgs","repos_url":"https://api.github.com/users/mattyb149/repos","events_url":"https://api.github.com/users/mattyb149/events{/privacy}","received_events_url":"https://api.github.com/users/mattyb149/received_events","type":"User","site_admin":false},"body":"Can this be parallelized somehow? Fork/Join or whatever? Not sure about overhead, just asking :)","created_at":"2016-07-24T02:53:02Z","updated_at":"2016-07-24T02:53:02Z","html_url":"https://github.com/apache/nifi/pull/254#discussion_r71981046","pull_request_url":"https://api.github.com/repos/apache/nifi/pulls/254","_links":{"self":{"href":"https://api.github.com/repos/apache/nifi/pulls/comments/71981046"},"html":{"href":"https://github.com/apache/nifi/pull/254#discussion_r71981046"},"pull_request":{"href":"https://api.github.com/repos/apache/nifi/pulls/254"}}},"pull_request":{"url":"https://api.github.com/repos/apache/nifi/pulls/254","id":61590979,"html_url":"https://github.com/apache/nifi/pull/254","diff_url":"https://github.com/apache/nifi/pull/254.diff","patch_url":"https://github.com/apache/nifi/pull/254.patch","issue_url":"https://api.github.com/repos/apache/nifi/issues/254","number":254,"state":"open","locked":false,"title":"NIFI-1583 Added ConvertJSONtoCSV processor","user":{"login":"acesir","id":5704659,"avatar_url":"https://avatars.githubusercontent.com/u/5704659?v=3","gravatar_id":"","url":"https://api.github.com/users/acesir","html_url":"https://github.com/acesir","followers_url":"https://api.github.com/users/acesir/followers","following_url":"https://api.github.com/users/acesir/following{/other_user}","gists_url":"https://api.github.com/users/acesir/gists{/gist_id}","starred_url":"https://api.github.com/users/acesir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/acesir/subscriptions","organizations_url":"https://api.github.com/users/acesir/orgs","repos_url":"https://api.github.com/users/acesir/repos","events_url":"https://api.github.com/users/acesir/events{/privacy}","received_events_url":"https://api.github.com/users/acesir/received_events","type":"User","site_admin":false},"body":"New functionality to convert complicated multi nested JSON format into\r\ntabular 2 dimensional CSV format","created_at":"2016-03-03T17:02:47Z","updated_at":"2016-07-24T02:53:02Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9d2b270ebdd4ccbe5647bb83faf86857746db1c7","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/apache/nifi/pulls/254/commits","review_comments_url":"https://api.github.com/repos/apache/nifi/pulls/254/comments","review_comment_url":"https://api.github.com/repos/apache/nifi/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/nifi/issues/254/comments","statuses_url":"https://api.github.com/repos/apache/nifi/statuses/115894a8dece76f3d29147f9ef7d60b9e72c0750","head":{"label":"acesir:NIFI-1583","ref":"NIFI-1583","sha":"115894a8dece76f3d29147f9ef7d60b9e72c0750","user":{"login":"acesir","id":5704659,"avatar_url":"https://avatars.githubusercontent.com/u/5704659?v=3","gravatar_id":"","url":"https://api.github.com/users/acesir","html_url":"https://github.com/acesir","followers_url":"https://api.github.com/users/acesir/followers","following_url":"https://api.github.com/users/acesir/following{/other_user}","gists_url":"https://api.github.com/users/acesir/gists{/gist_id}","starred_url":"https://api.github.com/users/acesir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/acesir/subscriptions","organizations_url":"https://api.github.com/users/acesir/orgs","repos_url":"https://api.github.com/users/acesir/repos","events_url":"https://api.github.com/users/acesir/events{/privacy}","received_events_url":"https://api.github.com/users/acesir/received_events","type":"User","site_admin":false},"repo":{"id":53067007,"name":"nifi","full_name":"acesir/nifi","owner":{"login":"acesir","id":5704659,"avatar_url":"https://avatars.githubusercontent.com/u/5704659?v=3","gravatar_id":"","url":"https://api.github.com/users/acesir","html_url":"https://github.com/acesir","followers_url":"https://api.github.com/users/acesir/followers","following_url":"https://api.github.com/users/acesir/following{/other_user}","gists_url":"https://api.github.com/users/acesir/gists{/gist_id}","starred_url":"https://api.github.com/users/acesir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/acesir/subscriptions","organizations_url":"https://api.github.com/users/acesir/orgs","repos_url":"https://api.github.com/users/acesir/repos","events_url":"https://api.github.com/users/acesir/events{/privacy}","received_events_url":"https://api.github.com/users/acesir/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/acesir/nifi","description":"Mirror of Apache NiFi","fork":true,"url":"https://api.github.com/repos/acesir/nifi","forks_url":"https://api.github.com/repos/acesir/nifi/forks","keys_url":"https://api.github.com/repos/acesir/nifi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/acesir/nifi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/acesir/nifi/teams","hooks_url":"https://api.github.com/repos/acesir/nifi/hooks","issue_events_url":"https://api.github.com/repos/acesir/nifi/issues/events{/number}","events_url":"https://api.github.com/repos/acesir/nifi/events","assignees_url":"https://api.github.com/repos/acesir/nifi/assignees{/user}","branches_url":"https://api.github.com/repos/acesir/nifi/branches{/branch}","tags_url":"https://api.github.com/repos/acesir/nifi/tags","blobs_url":"https://api.github.com/repos/acesir/nifi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/acesir/nifi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/acesir/nifi/git/refs{/sha}","trees_url":"https://api.github.com/repos/acesir/nifi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/acesir/nifi/statuses/{sha}","languages_url":"https://api.github.com/repos/acesir/nifi/languages","stargazers_url":"https://api.github.com/repos/acesir/nifi/stargazers","contributors_url":"https://api.github.com/repos/acesir/nifi/contributors","subscribers_url":"https://api.github.com/repos/acesir/nifi/subscribers","subscription_url":"https://api.github.com/repos/acesir/nifi/subscription","commits_url":"https://api.github.com/repos/acesir/nifi/commits{/sha}","git_commits_url":"https://api.github.com/repos/acesir/nifi/git/commits{/sha}","comments_url":"https://api.github.com/repos/acesir/nifi/comments{/number}","issue_comment_url":"https://api.github.com/repos/acesir/nifi/issues/comments{/number}","contents_url":"https://api.github.com/repos/acesir/nifi/contents/{+path}","compare_url":"https://api.github.com/repos/acesir/nifi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/acesir/nifi/merges","archive_url":"https://api.github.com/repos/acesir/nifi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/acesir/nifi/downloads","issues_url":"https://api.github.com/repos/acesir/nifi/issues{/number}","pulls_url":"https://api.github.com/repos/acesir/nifi/pulls{/number}","milestones_url":"https://api.github.com/repos/acesir/nifi/milestones{/number}","notifications_url":"https://api.github.com/repos/acesir/nifi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/acesir/nifi/labels{/name}","releases_url":"https://api.github.com/repos/acesir/nifi/releases{/id}","deployments_url":"https://api.github.com/repos/acesir/nifi/deployments","created_at":"2016-03-03T16:50:25Z","updated_at":"2016-03-03T16:50:37Z","pushed_at":"2016-07-20T15:58:26Z","git_url":"git://github.com/acesir/nifi.git","ssh_url":"git@github.com:acesir/nifi.git","clone_url":"https://github.com/acesir/nifi.git","svn_url":"https://github.com/acesir/nifi","homepage":"","size":51538,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"5999eab43fea5d7efc481182e0af0e2a19f960d4","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":27911088,"name":"nifi","full_name":"apache/nifi","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/nifi","description":"Mirror of Apache NiFi","fork":false,"url":"https://api.github.com/repos/apache/nifi","forks_url":"https://api.github.com/repos/apache/nifi/forks","keys_url":"https://api.github.com/repos/apache/nifi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/nifi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/nifi/teams","hooks_url":"https://api.github.com/repos/apache/nifi/hooks","issue_events_url":"https://api.github.com/repos/apache/nifi/issues/events{/number}","events_url":"https://api.github.com/repos/apache/nifi/events","assignees_url":"https://api.github.com/repos/apache/nifi/assignees{/user}","branches_url":"https://api.github.com/repos/apache/nifi/branches{/branch}","tags_url":"https://api.github.com/repos/apache/nifi/tags","blobs_url":"https://api.github.com/repos/apache/nifi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/nifi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/nifi/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/nifi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/nifi/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/nifi/languages","stargazers_url":"https://api.github.com/repos/apache/nifi/stargazers","contributors_url":"https://api.github.com/repos/apache/nifi/contributors","subscribers_url":"https://api.github.com/repos/apache/nifi/subscribers","subscription_url":"https://api.github.com/repos/apache/nifi/subscription","commits_url":"https://api.github.com/repos/apache/nifi/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/nifi/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/nifi/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/nifi/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/nifi/contents/{+path}","compare_url":"https://api.github.com/repos/apache/nifi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/nifi/merges","archive_url":"https://api.github.com/repos/apache/nifi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/nifi/downloads","issues_url":"https://api.github.com/repos/apache/nifi/issues{/number}","pulls_url":"https://api.github.com/repos/apache/nifi/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/nifi/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/nifi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/nifi/labels{/name}","releases_url":"https://api.github.com/repos/apache/nifi/releases{/id}","deployments_url":"https://api.github.com/repos/apache/nifi/deployments","created_at":"2014-12-12T08:00:05Z","updated_at":"2016-07-23T05:05:48Z","pushed_at":"2016-07-23T19:26:08Z","git_url":"git://github.com/apache/nifi.git","ssh_url":"git@github.com:apache/nifi.git","clone_url":"https://github.com/apache/nifi.git","svn_url":"https://github.com/apache/nifi","homepage":"","size":74518,"stargazers_count":318,"watchers_count":318,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":278,"mirror_url":"git://git.apache.org/nifi.git","open_issues_count":57,"forks":278,"open_issues":57,"watchers":318,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/nifi/pulls/254"},"html":{"href":"https://github.com/apache/nifi/pull/254"},"issue":{"href":"https://api.github.com/repos/apache/nifi/issues/254"},"comments":{"href":"https://api.github.com/repos/apache/nifi/issues/254/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/nifi/pulls/254/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/nifi/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/nifi/pulls/254/commits"},"statuses":{"href":"https://api.github.com/repos/apache/nifi/statuses/115894a8dece76f3d29147f9ef7d60b9e72c0750"}}}}
{"actor":{"display_login":"mattyb149"}}