{"action":"created","comment":{"url":"https://api.github.com/repos/apache/nifi/pulls/comments/43745297","id":43745297,"diff_hunk":"@@ -0,0 +1,378 @@\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+\n+package org.apache.nifi.processors.standard;\n+\n+import org.apache.nifi.annotation.behavior.TriggerSerially;\n+import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;\n+import org.apache.nifi.annotation.behavior.WritesAttribute;\n+import org.apache.nifi.annotation.behavior.WritesAttributes;\n+import org.apache.nifi.annotation.documentation.CapabilityDescription;\n+import org.apache.nifi.annotation.documentation.SeeAlso;\n+import org.apache.nifi.annotation.documentation.Tags;\n+import org.apache.nifi.annotation.lifecycle.OnScheduled;\n+import org.apache.nifi.components.PropertyDescriptor;\n+import org.apache.nifi.flowfile.attributes.CoreAttributes;\n+import org.apache.nifi.processor.DataUnit;\n+import org.apache.nifi.processor.ProcessContext;\n+import org.apache.nifi.processor.ProcessorInitializationContext;\n+import org.apache.nifi.processor.Relationship;\n+import org.apache.nifi.processor.util.StandardValidators;\n+import org.apache.nifi.processors.standard.util.FileInfo;\n+\n+import java.io.File;\n+import java.io.FileFilter;\n+import java.io.IOException;\n+import java.nio.file.FileStore;\n+import java.nio.file.Files;\n+import java.nio.file.Path;\n+import java.nio.file.Paths;\n+import java.nio.file.attribute.BasicFileAttributeView;\n+import java.nio.file.attribute.BasicFileAttributes;\n+import java.nio.file.attribute.FileOwnerAttributeView;\n+import java.nio.file.attribute.PosixFileAttributeView;\n+import java.nio.file.attribute.PosixFilePermissions;\n+import java.text.DateFormat;\n+import java.text.SimpleDateFormat;\n+import java.util.ArrayList;\n+import java.util.Collections;\n+import java.util.Date;\n+import java.util.HashMap;\n+import java.util.HashSet;\n+import java.util.Iterator;\n+import java.util.List;\n+import java.util.Locale;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.concurrent.TimeUnit;\n+import java.util.concurrent.atomic.AtomicReference;\n+import java.util.regex.Pattern;\n+\n+@TriggerSerially\n+@TriggerWhenEmpty\n+@Tags({\"file\", \"get\", \"list\", \"ingest\", \"source\", \"filesystem\"})\n+@CapabilityDescription(\"Retrieves a listing of files from the local filesystem. For each file that is listed, \" +\n+        \"creates a FlowFile that represents the file so that it can be fetched in conjunction with ListFile. This \" +\n+        \"Processor is designed to run on Primary Node only in a cluster. If the primary node changes, the new \" +\n+        \"Primary Node will pick up where the previous node left off without duplicating all of the data. Unlike \" +\n+        \"GetFile, this Processor does not delete any data from the local filesystem.\")\n+@WritesAttributes({\n+        @WritesAttribute(attribute=\"filename\", description=\"The name of the file that was read from filesystem.\"),\n+        @WritesAttribute(attribute=\"path\", description=\"The path is set to the absolute path of the file's directory \" +\n+                \"on filesystem. For example, if the Directory property is set to /tmp, then files picked up from \" +\n+                \"/tmp will have the path attribute set to \\\"./\\\". If the Recurse Subdirectories property is set to \" +\n+                \"true and a file is picked up from /tmp/abc/1/2/3, then the path attribute will be set to \" +\n+                \"\\\"/tmp/abc/1/2/3\\\".\"),\n+        @WritesAttribute(attribute=\"fs.owner\", description=\"The user that owns the file in filesystem\"),\n+        @WritesAttribute(attribute=\"fs.group\", description=\"The group that owns the file in filesystem\"),\n+        @WritesAttribute(attribute=\"fs.lastModified\", description=\"The timestamp of when the file in filesystem was \" +\n+                \"last modified, as milliseconds since midnight Jan 1, 1970 UTC\"),\n+        @WritesAttribute(attribute=\"fs.length\", description=\"The number of bytes in the file in filesystem\"),\n+        @WritesAttribute(attribute=\"fs.permissions\", description=\"The permissions for the file in filesystem. This \" +\n+                \"is formatted as 3 characters for the owner, 3 for the group, and 3 for other users. For example \" +\n+                \"rw-rw-r--\")\n+})\n+@SeeAlso({GetFile.class, PutFile.class})\n+public class ListFile extends AbstractListProcessor<FileInfo> {\n+\n+    public static final PropertyDescriptor DIRECTORY = new PropertyDescriptor.Builder()\n+            .name(\"Input Directory\")\n+            .description(\"The input directory from which files to pull files\")\n+            .required(true)\n+            .addValidator(StandardValidators.createDirectoryExistsValidator(true, false))\n+            .expressionLanguageSupported(true)\n+            .build();\n+\n+    public static final PropertyDescriptor RECURSE = new PropertyDescriptor.Builder()\n+            .name(\"Recurse Subdirectories\")\n+            .description(\"Indicates whether to list files from subdirectories of the directory\")\n+            .required(true)\n+            .allowableValues(\"true\", \"false\")\n+            .defaultValue(\"true\")\n+            .build();\n+\n+    public static final PropertyDescriptor FILE_FILTER = new PropertyDescriptor.Builder()\n+            .name(\"File Filter\")\n+            .description(\"Only files whose names match the given regular expression will be picked up\")\n+            .required(true)\n+            .defaultValue(\"[^\\\\.].*\")\n+            .addValidator(StandardValidators.REGULAR_EXPRESSION_VALIDATOR)\n+            .build();\n+\n+    public static final PropertyDescriptor PATH_FILTER = new PropertyDescriptor.Builder()\n+            .name(\"Path Filter\")\n+            .description(\"When \" + RECURSE.getName() + \" is true, then only subdirectories whose path matches the given regular expression will be scanned\")\n+            .required(false)\n+            .addValidator(StandardValidators.REGULAR_EXPRESSION_VALIDATOR)\n+            .build();\n+\n+\n+    public static final PropertyDescriptor MIN_AGE = new PropertyDescriptor.Builder()\n+            .name(\"Minimum File Age\")\n+            .description(\"The minimum age that a file must be in order to be pulled; any file younger than this amount of time (according to last modification date) will be ignored\")\n+            .required(true)\n+            .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR)\n+            .defaultValue(\"0 sec\")\n+            .build();\n+\n+    public static final PropertyDescriptor MAX_AGE = new PropertyDescriptor.Builder()\n+            .name(\"Maximum File Age\")\n+            .description(\"The maximum age that a file must be in order to be pulled; any file older than this amount of time (according to last modification date) will be ignored\")\n+            .required(false)\n+            .addValidator(StandardValidators.createTimePeriodValidator(100, TimeUnit.MILLISECONDS, Long.MAX_VALUE, TimeUnit.NANOSECONDS))\n+            .build();\n+\n+    public static final PropertyDescriptor MIN_SIZE = new PropertyDescriptor.Builder()\n+            .name(\"Minimum File Size\")\n+            .description(\"The minimum size that a file must be in order to be pulled\")\n+            .required(true)\n+            .addValidator(StandardValidators.DATA_SIZE_VALIDATOR)\n+            .defaultValue(\"0 B\")\n+            .build();\n+\n+    public static final PropertyDescriptor MAX_SIZE = new PropertyDescriptor.Builder()\n+            .name(\"Maximum File Size\")\n+            .description(\"The maximum size that a file can be in order to be pulled\")\n+            .required(false)\n+            .addValidator(StandardValidators.DATA_SIZE_VALIDATOR)\n+            .build();\n+\n+    public static final PropertyDescriptor IGNORE_HIDDEN_FILES = new PropertyDescriptor.Builder()\n+            .name(\"Ignore Hidden Files\")\n+            .description(\"Indicates whether or not hidden files should be ignored\")\n+            .allowableValues(\"true\", \"false\")\n+            .defaultValue(\"true\")\n+            .required(true)\n+            .build();\n+\n+    private List<PropertyDescriptor> properties;\n+    private Set<Relationship> relationships;\n+    private final AtomicReference<FileFilter> fileFilterRef = new AtomicReference<>();\n+\n+    public static final String FILE_CREATION_TIME_ATTRIBUTE = \"file.creationTime\";\n+    public static final String FILE_LAST_MODIFY_TIME_ATTRIBUTE = \"file.lastModifiedTime\";\n+    public static final String FILE_LAST_ACCESS_TIME_ATTRIBUTE = \"file.lastAccessTime\";\n+    public static final String FILE_SIZE_ATTRIBUTE = \"file.size\";\n+    public static final String FILE_OWNER_ATTRIBUTE = \"file.owner\";\n+    public static final String FILE_GROUP_ATTRIBUTE = \"file.group\";\n+    public static final String FILE_PERMISSIONS_ATTRIBUTE = \"file.permissions\";\n+    public static final String FILE_MODIFY_DATE_ATTR_FORMAT = \"yyyy-MM-dd'T'HH:mm:ssZ\";\n+\n+    @Override\n+    protected void init(final ProcessorInitializationContext context) {\n+        final List<PropertyDescriptor> properties = new ArrayList<>();\n+        properties.add(DIRECTORY);\n+        properties.add(RECURSE);\n+        properties.add(FILE_FILTER);\n+        properties.add(PATH_FILTER);\n+        properties.add(MIN_AGE);\n+        properties.add(MAX_AGE);\n+        properties.add(MIN_SIZE);\n+        properties.add(MAX_SIZE);\n+        properties.add(IGNORE_HIDDEN_FILES);\n+        this.properties = Collections.unmodifiableList(properties);\n+\n+        final Set<Relationship> relationships = new HashSet<>();\n+        relationships.add(REL_SUCCESS);\n+        this.relationships = Collections.unmodifiableSet(relationships);\n+    }\n+\n+    @Override\n+    protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {\n+        return properties;\n+    }\n+\n+    @Override\n+    public Set<Relationship> getRelationships() {\n+        return relationships;\n+    }\n+\n+    @OnScheduled\n+    public void onScheduled(final ProcessContext context) {\n+        fileFilterRef.set(createFileFilter(context));\n+    }\n+\n+    @Override\n+    protected Map<String, String> createAttributes(final FileInfo fileInfo, final ProcessContext context) {\n+        final Map<String, String> attributes = new HashMap<>();\n+\n+        final String fullPath = fileInfo.getFullPathFileName();\n+        final File file = new File(fullPath);\n+        final Path filePath = file.toPath();\n+        final Path directoryPath = new File(getPath(context)).toPath();\n+\n+        final Path relativePath = directoryPath.relativize(filePath.getParent());\n+        String relativePathString = relativePath.toString() + \"/\";\n+        if (relativePathString.isEmpty()) {\n+            relativePathString = \"./\";\n+        }\n+        final Path absPath = filePath.toAbsolutePath();\n+        final String absPathString = absPath.getParent().toString() + \"/\";\n+\n+        attributes.put(CoreAttributes.PATH.key(), relativePathString);\n+        attributes.put(CoreAttributes.FILENAME.key(), fileInfo.getFileName());\n+        attributes.put(CoreAttributes.ABSOLUTE_PATH.key(), absPathString);\n+\n+        try {\n+            FileStore store = Files.getFileStore(filePath);\n+            if (store.supportsFileAttributeView(\"basic\")) {\n+                try {\n+                    final DateFormat formatter = new SimpleDateFormat(FILE_MODIFY_DATE_ATTR_FORMAT, Locale.US);\n+                    BasicFileAttributeView view = Files.getFileAttributeView(filePath, BasicFileAttributeView.class);\n+                    BasicFileAttributes attrs = view.readAttributes();\n+                    attributes.put(FILE_SIZE_ATTRIBUTE, Long.toString(attrs.size()));\n+                    attributes.put(FILE_LAST_MODIFY_TIME_ATTRIBUTE, formatter.format(new Date(attrs.lastModifiedTime().toMillis())));\n+                    attributes.put(FILE_CREATION_TIME_ATTRIBUTE, formatter.format(new Date(attrs.creationTime().toMillis())));\n+                    attributes.put(FILE_LAST_ACCESS_TIME_ATTRIBUTE, formatter.format(new Date(attrs.lastAccessTime().toMillis())));\n+                } catch (Exception ignore) {\n+                } // allow other attributes if these fail\n+            }\n+            if (store.supportsFileAttributeView(\"owner\")) {\n+                try {\n+                    FileOwnerAttributeView view = Files.getFileAttributeView(filePath, FileOwnerAttributeView.class);\n+                    attributes.put(FILE_OWNER_ATTRIBUTE, view.getOwner().getName());\n+                } catch (Exception ignore) {\n+                } // allow other attributes if these fail\n+            }\n+            if (store.supportsFileAttributeView(\"posix\")) {\n+                try {\n+                    PosixFileAttributeView view = Files.getFileAttributeView(filePath, PosixFileAttributeView.class);\n+                    attributes.put(FILE_PERMISSIONS_ATTRIBUTE, PosixFilePermissions.toString(view.readAttributes().permissions()));\n+                    attributes.put(FILE_GROUP_ATTRIBUTE, view.readAttributes().group().getName());\n+                } catch (Exception ignore) {\n+                } // allow other attributes if these fail\n+            }\n+        } catch (IOException ioe) {\n+            // well then this FlowFile gets none of these attributes\n+        }\n+\n+        return attributes;\n+    }\n+\n+    @Override\n+    protected String getPath(final ProcessContext context) {\n+        return context.getProperty(DIRECTORY).evaluateAttributeExpressions().getValue();\n+    }\n+\n+    @Override\n+    protected List<FileInfo> performListing(final ProcessContext context, final Long minTimestamp) throws IOException {\n+        final File path = new File(getPath(context));\n+        final Boolean recurse = context.getProperty(RECURSE).asBoolean();\n+        return scanDirectory(path, fileFilterRef.get(), recurse, minTimestamp);\n+    }\n+\n+    @Override\n+    protected boolean isListingResetNecessary(final PropertyDescriptor property) {\n+        return DIRECTORY.equals(property)\n+                || RECURSE.equals(property)\n+                || FILE_FILTER.equals(property)\n+                || PATH_FILTER.equals(property)\n+                || MIN_AGE.equals(property)\n+                || MAX_AGE.equals(property)\n+                || MIN_SIZE.equals(property)\n+                || MAX_SIZE.equals(property)\n+                || IGNORE_HIDDEN_FILES.equals(property);\n+    }\n+\n+    private List<FileInfo> scanDirectory(final File path, final FileFilter filter, final Boolean recurse,\n+                                         final Long minTimestamp) throws IOException {\n+        final List<FileInfo> listing = new ArrayList<>();\n+        File[] files = path.listFiles();\n+        if (files != null) {\n+            for (File file : files) {\n+                if (file.isDirectory()) {\n+                    if (recurse) {\n+                        listing.addAll(scanDirectory(file, filter, true, minTimestamp));\n+                    }\n+                } else {\n+                    if (filter.accept(file)) {\n+                        listing.add(new FileInfo.Builder()\n+                                .directory(file.isDirectory())\n+                                .filename(file.getName())\n+                                .fullPathFileName(file.getAbsolutePath())\n+                                .lastModifiedTime(file.lastModified())\n+                                .build());\n+                    }\n+                }\n+            }\n+        }\n+        if (minTimestamp == null) {\n+            return listing;\n+        }\n+\n+        final Iterator<FileInfo> itr = listing.iterator();\n+        while (itr.hasNext()) {\n+            final FileInfo next = itr.next();\n+            if (next.getLastModifiedTime() < minTimestamp) {\n+                itr.remove();\n+            }\n+        }\n+\n+        return listing;\n+    }\n+\n+    private FileFilter createFileFilter(final ProcessContext context) {\n+        final long minSize = context.getProperty(MIN_SIZE).asDataSize(DataUnit.B).longValue();\n+        final Double maxSize = context.getProperty(MAX_SIZE).asDataSize(DataUnit.B);\n+        final long minAge = context.getProperty(MIN_AGE).asTimePeriod(TimeUnit.MILLISECONDS);\n+        final Long maxAge = context.getProperty(MAX_AGE).asTimePeriod(TimeUnit.MILLISECONDS);\n+        final boolean ignoreHidden = context.getProperty(IGNORE_HIDDEN_FILES).asBoolean();\n+        final Pattern filePattern = Pattern.compile(context.getProperty(FILE_FILTER).getValue());\n+        final String indir = context.getProperty(DIRECTORY).evaluateAttributeExpressions().getValue();\n+        final boolean recurseDirs = context.getProperty(RECURSE).asBoolean();\n+        final String pathPatternStr = context.getProperty(PATH_FILTER).getValue();\n+        final Pattern pathPattern = (!recurseDirs || pathPatternStr == null) ? null : Pattern.compile(pathPatternStr);\n+\n+        return new FileFilter() {\n+            @Override\n+            public boolean accept(final File file) {\n+                if (minSize > file.length()) {\n+                    return false;\n+                }\n+                if (maxSize != null && maxSize < file.length()) {\n+                    return false;\n+                }\n+                final long fileAge = System.currentTimeMillis() - file.lastModified();\n+                if (minAge > fileAge) {\n+                    return false;\n+                }\n+                if (maxAge != null && maxAge < fileAge) {\n+                    return false;\n+                }\n+                if (ignoreHidden && file.isHidden()) {\n+                    return false;\n+                }\n+                if (pathPattern != null) {\n+                    Path reldir = Paths.get(indir).relativize(file.toPath()).getParent();\n+                    System.out.println(\"reldir=\" + reldir + \" pathPatternStr=\" + pathPatternStr + \" file=\" + file.getName());","path":"nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFile.java","position":361,"original_position":361,"commit_id":"526306a0e87054bf839ec525af6d6063df290bb6","original_commit_id":"526306a0e87054bf839ec525af6d6063df290bb6","user":{"login":"jskora","id":181587,"avatar_url":"https://avatars.githubusercontent.com/u/181587?v=3","gravatar_id":"","url":"https://api.github.com/users/jskora","html_url":"https://github.com/jskora","followers_url":"https://api.github.com/users/jskora/followers","following_url":"https://api.github.com/users/jskora/following{/other_user}","gists_url":"https://api.github.com/users/jskora/gists{/gist_id}","starred_url":"https://api.github.com/users/jskora/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jskora/subscriptions","organizations_url":"https://api.github.com/users/jskora/orgs","repos_url":"https://api.github.com/users/jskora/repos","events_url":"https://api.github.com/users/jskora/events{/privacy}","received_events_url":"https://api.github.com/users/jskora/received_events","type":"User","site_admin":false},"body":"Yep.  Will do.","created_at":"2015-11-03T13:14:49Z","updated_at":"2015-11-03T13:14:49Z","html_url":"https://github.com/apache/nifi/pull/113#discussion_r43745297","pull_request_url":"https://api.github.com/repos/apache/nifi/pulls/113","_links":{"self":{"href":"https://api.github.com/repos/apache/nifi/pulls/comments/43745297"},"html":{"href":"https://github.com/apache/nifi/pull/113#discussion_r43745297"},"pull_request":{"href":"https://api.github.com/repos/apache/nifi/pulls/113"}}},"pull_request":{"url":"https://api.github.com/repos/apache/nifi/pulls/113","id":49542970,"html_url":"https://github.com/apache/nifi/pull/113","diff_url":"https://github.com/apache/nifi/pull/113.diff","patch_url":"https://github.com/apache/nifi/pull/113.patch","issue_url":"https://api.github.com/repos/apache/nifi/issues/113","number":113,"state":"open","locked":false,"title":"Nifi 631","user":{"login":"jskora","id":181587,"avatar_url":"https://avatars.githubusercontent.com/u/181587?v=3","gravatar_id":"","url":"https://api.github.com/users/jskora","html_url":"https://github.com/jskora","followers_url":"https://api.github.com/users/jskora/followers","following_url":"https://api.github.com/users/jskora/following{/other_user}","gists_url":"https://api.github.com/users/jskora/gists{/gist_id}","starred_url":"https://api.github.com/users/jskora/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jskora/subscriptions","organizations_url":"https://api.github.com/users/jskora/orgs","repos_url":"https://api.github.com/users/jskora/repos","events_url":"https://api.github.com/users/jskora/events{/privacy}","received_events_url":"https://api.github.com/users/jskora/received_events","type":"User","site_admin":false},"body":"ListFile based on AbstractListProcessor.  Properties and attribute handling modeled on GetFile.  Unit test coverage is 96% .","created_at":"2015-11-03T11:10:44Z","updated_at":"2015-11-03T13:14:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4a54a4c02a1bf83d45bbd73fd3e39f2f6d9fe091","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/nifi/pulls/113/commits","review_comments_url":"https://api.github.com/repos/apache/nifi/pulls/113/comments","review_comment_url":"https://api.github.com/repos/apache/nifi/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/nifi/issues/113/comments","statuses_url":"https://api.github.com/repos/apache/nifi/statuses/526306a0e87054bf839ec525af6d6063df290bb6","head":{"label":"jskora:NIFI-631","ref":"NIFI-631","sha":"526306a0e87054bf839ec525af6d6063df290bb6","user":{"login":"jskora","id":181587,"avatar_url":"https://avatars.githubusercontent.com/u/181587?v=3","gravatar_id":"","url":"https://api.github.com/users/jskora","html_url":"https://github.com/jskora","followers_url":"https://api.github.com/users/jskora/followers","following_url":"https://api.github.com/users/jskora/following{/other_user}","gists_url":"https://api.github.com/users/jskora/gists{/gist_id}","starred_url":"https://api.github.com/users/jskora/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jskora/subscriptions","organizations_url":"https://api.github.com/users/jskora/orgs","repos_url":"https://api.github.com/users/jskora/repos","events_url":"https://api.github.com/users/jskora/events{/privacy}","received_events_url":"https://api.github.com/users/jskora/received_events","type":"User","site_admin":false},"repo":{"id":45012567,"name":"nifi","full_name":"jskora/nifi","owner":{"login":"jskora","id":181587,"avatar_url":"https://avatars.githubusercontent.com/u/181587?v=3","gravatar_id":"","url":"https://api.github.com/users/jskora","html_url":"https://github.com/jskora","followers_url":"https://api.github.com/users/jskora/followers","following_url":"https://api.github.com/users/jskora/following{/other_user}","gists_url":"https://api.github.com/users/jskora/gists{/gist_id}","starred_url":"https://api.github.com/users/jskora/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jskora/subscriptions","organizations_url":"https://api.github.com/users/jskora/orgs","repos_url":"https://api.github.com/users/jskora/repos","events_url":"https://api.github.com/users/jskora/events{/privacy}","received_events_url":"https://api.github.com/users/jskora/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jskora/nifi","description":"Mirror of Apache NiFi","fork":true,"url":"https://api.github.com/repos/jskora/nifi","forks_url":"https://api.github.com/repos/jskora/nifi/forks","keys_url":"https://api.github.com/repos/jskora/nifi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jskora/nifi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jskora/nifi/teams","hooks_url":"https://api.github.com/repos/jskora/nifi/hooks","issue_events_url":"https://api.github.com/repos/jskora/nifi/issues/events{/number}","events_url":"https://api.github.com/repos/jskora/nifi/events","assignees_url":"https://api.github.com/repos/jskora/nifi/assignees{/user}","branches_url":"https://api.github.com/repos/jskora/nifi/branches{/branch}","tags_url":"https://api.github.com/repos/jskora/nifi/tags","blobs_url":"https://api.github.com/repos/jskora/nifi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jskora/nifi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jskora/nifi/git/refs{/sha}","trees_url":"https://api.github.com/repos/jskora/nifi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jskora/nifi/statuses/{sha}","languages_url":"https://api.github.com/repos/jskora/nifi/languages","stargazers_url":"https://api.github.com/repos/jskora/nifi/stargazers","contributors_url":"https://api.github.com/repos/jskora/nifi/contributors","subscribers_url":"https://api.github.com/repos/jskora/nifi/subscribers","subscription_url":"https://api.github.com/repos/jskora/nifi/subscription","commits_url":"https://api.github.com/repos/jskora/nifi/commits{/sha}","git_commits_url":"https://api.github.com/repos/jskora/nifi/git/commits{/sha}","comments_url":"https://api.github.com/repos/jskora/nifi/comments{/number}","issue_comment_url":"https://api.github.com/repos/jskora/nifi/issues/comments{/number}","contents_url":"https://api.github.com/repos/jskora/nifi/contents/{+path}","compare_url":"https://api.github.com/repos/jskora/nifi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jskora/nifi/merges","archive_url":"https://api.github.com/repos/jskora/nifi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jskora/nifi/downloads","issues_url":"https://api.github.com/repos/jskora/nifi/issues{/number}","pulls_url":"https://api.github.com/repos/jskora/nifi/pulls{/number}","milestones_url":"https://api.github.com/repos/jskora/nifi/milestones{/number}","notifications_url":"https://api.github.com/repos/jskora/nifi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jskora/nifi/labels{/name}","releases_url":"https://api.github.com/repos/jskora/nifi/releases{/id}","created_at":"2015-10-27T02:46:40Z","updated_at":"2015-10-27T02:46:50Z","pushed_at":"2015-11-03T10:59:05Z","git_url":"git://github.com/jskora/nifi.git","ssh_url":"git@github.com:jskora/nifi.git","clone_url":"https://github.com/jskora/nifi.git","svn_url":"https://github.com/jskora/nifi","homepage":"","size":33833,"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":"dbf0c7893fef964bfbb3a4c039c756396587ce12","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}","created_at":"2014-12-12T08:00:05Z","updated_at":"2015-10-31T13:24:46Z","pushed_at":"2015-11-03T11:10:44Z","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":94917,"stargazers_count":156,"watchers_count":156,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":125,"mirror_url":"git://git.apache.org/incubator-nifi.git","open_issues_count":8,"forks":125,"open_issues":8,"watchers":156,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/nifi/pulls/113"},"html":{"href":"https://github.com/apache/nifi/pull/113"},"issue":{"href":"https://api.github.com/repos/apache/nifi/issues/113"},"comments":{"href":"https://api.github.com/repos/apache/nifi/issues/113/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/nifi/pulls/113/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/nifi/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/nifi/pulls/113/commits"},"statuses":{"href":"https://api.github.com/repos/apache/nifi/statuses/526306a0e87054bf839ec525af6d6063df290bb6"}}}}