{"action":"created","comment":{"url":"https://api.github.com/repos/Netflix/genie/pulls/comments/188106922","pull_request_review_id":120020030,"id":188106922,"diff_hunk":"@@ -0,0 +1,343 @@\n+/*\n+ *\n+ *  Copyright 2018 Netflix, Inc.\n+ *\n+ *     Licensed under the Apache License, Version 2.0 (the \"License\");\n+ *     you may not use this file except in compliance with the License.\n+ *     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+\n+package com.netflix.genie.agent.execution.services.impl;\n+\n+import com.google.common.annotations.VisibleForTesting;\n+import com.google.common.io.Files;\n+import com.netflix.genie.agent.cli.ArgumentDelegates;\n+import com.netflix.genie.agent.execution.exceptions.DownloadException;\n+import com.netflix.genie.agent.execution.locks.Lock;\n+import com.netflix.genie.agent.execution.locks.impl.LockingFactory;\n+import com.netflix.genie.agent.execution.services.FetchingCacheService;\n+import lombok.extern.slf4j.Slf4j;\n+import org.apache.commons.lang3.tuple.Pair;\n+import org.springframework.context.annotation.Lazy;\n+import org.springframework.core.io.Resource;\n+import org.springframework.core.io.ResourceLoader;\n+import org.springframework.stereotype.Component;\n+import org.springframework.stereotype.Service;\n+import org.springframework.util.DigestUtils;\n+import org.springframework.util.FileCopyUtils;\n+import org.springframework.util.FileSystemUtils;\n+\n+import java.io.File;\n+import java.io.FileNotFoundException;\n+import java.io.FileOutputStream;\n+import java.io.IOException;\n+import java.io.InputStream;\n+import java.io.OutputStream;\n+import java.io.RandomAccessFile;\n+import java.net.URI;\n+import java.nio.channels.FileChannel;\n+import java.nio.charset.StandardCharsets;\n+import java.util.Set;\n+import java.util.concurrent.ExecutorService;\n+import java.util.concurrent.Executors;\n+\n+/**\n+ * A file system based cache on local disk that uses URIs as keys and transparently downloads\n+ * missing entries. It uses OS level locks to accomplish the following\n+ * <p>\n+ * Allows multiple agents reading/writing/deleting in the same cache folder\n+ * without corrupting the cache\n+ * Downloads new versions of resources once they are available remotely\n+ * Deletes the old versions of resources once a new version is successfully downloaded\n+ * Recovers from partial downloads of resources in case an agent gets killed in the middle of a download\n+ * or a download fails for any other reason\n+ * <p>\n+ * Does NOT handle concurrency within the same agent (not an issue at the moment)\n+ * <p>\n+ * Cache structure on local disk\n+ * Each resource has a hash to represent it. The version of the resource is the remote last modified\n+ * timestamp. For each resource and version, a lock file is created. Each process takes a lock on\n+ * this file and then downloads the resource to a data.tmp file. Once the download is complete\n+ * data.tmp is atomically moved to data.\n+ * For e.g for a hash value of 6d331abc92bc8244bc5d41e2107f303a and last modified = 1525456404\n+ * cache entries would like the following\n+ * {base_dir}/6d331abc92bc8244bc5d41e2107f303a/1525456404/data\n+ * {base_dir}/6d331abc92bc8244bc5d41e2107f303a/1525456404/lock\n+ * <p>\n+ * Deletion of older versions\n+ *\n+ * @author standon\n+ * @since 4.0.0\n+ */\n+@Service\n+@Lazy\n+@Slf4j\n+@Component\n+class FileSystemFetchingCacheService implements FetchingCacheService {\n+\n+    public static final String LOCK_FILE_NAME = \"lock\";\n+    public static final String DATA_FILE_NAME = \"data\";\n+    public static final String DATA_DOWNLOAD_FILE_NAME = \"data.tmp\";\n+    protected final ResourceLoader resourceLoader;\n+    protected final File cacheDirectory;\n+    protected final LockingFactory lockingFactory;\n+    private final ExecutorService oldResourcesCleanUpService = Executors.newFixedThreadPool(1);\n+\n+\n+    FileSystemFetchingCacheService(\n+        final ResourceLoader resourceLoader,\n+        final ArgumentDelegates.CacheArguments cacheArguments,\n+        final LockingFactory lockingFactory\n+    ) {\n+        this.resourceLoader = resourceLoader;\n+\n+        this.cacheDirectory = cacheArguments.getCacheDirectory();\n+\n+        this.lockingFactory = lockingFactory;\n+\n+        createDirectoryStructureIfNotExists(cacheDirectory);\n+    }\n+\n+    /**\n+     * {@inheritDoc}\n+     */\n+    @Override\n+    public void get(final URI sourceFileUri, final File destinationFile) throws DownloadException, IOException {\n+        lookupOrDownload(sourceFileUri, destinationFile);\n+    }\n+\n+    /**\n+     * {@inheritDoc}\n+     */\n+    @Override\n+    public void get(final Set<Pair<URI, File>> sourceDestinationPairs) throws DownloadException, IOException {\n+        for (final Pair<URI, File> sourceDestinationPair : sourceDestinationPairs) {\n+            get(sourceDestinationPair.getKey(), sourceDestinationPair.getValue());\n+        }\n+    }\n+\n+    protected void lookupOrDownload(\n+        final URI sourceFileUri,\n+        final File destinationFile\n+    ) throws DownloadException, IOException {\n+\n+        final String uriString = sourceFileUri.toASCIIString();\n+\n+        log.info(\"Lookup: {}\", uriString);\n+\n+        // Unique id to store the resource on local disk\n+        final String resourceCacheId = getResourceCacheId(sourceFileUri);\n+\n+        // Get a handle to the resource\n+        final Resource resource = resourceLoader.getResource(uriString);\n+\n+        if (!resource.exists()) {\n+            throw new DownloadException(\"Resource not found: \" + uriString);\n+        }\n+\n+        final long resourceLastModified = resource.lastModified();\n+\n+        //Create the resource version dir in cache if it does not exist\n+        final File cacheResourceVersionDir = getCacheResourceVersionDir(\n+            resourceCacheId,\n+            resourceLastModified\n+        );\n+\n+        createDirectoryStructureIfNotExists(cacheResourceVersionDir);\n+\n+        //Handle to the resource cached locally\n+        final File cachedResourceVersionDataFile = getCacheResourceVersionDataFile(\n+            resourceCacheId,\n+            resourceLastModified\n+        );\n+\n+        try (\n+            final FileChannel lockFileChannel = getLockFileChannel(\n+                resourceCacheId,\n+                resourceLastModified\n+            );\n+            final Lock lock = lockingFactory.getLock(lockFileChannel);\n+        ) {\n+            lock.lock();\n+            if (!cachedResourceVersionDataFile.exists()) {\n+                log.info(\n+                    \"Cache miss: {} (id: {})\",\n+                    uriString,\n+                    resourceCacheId\n+                );\n+\n+                // Download the resource into the cache\n+                final File cachedResourceVersionDownloadFile = getCacheResourceVersionDownloadFile(\n+                    resourceCacheId,\n+                    resourceLastModified\n+                );\n+                try (\n+                    final InputStream in = resource.getInputStream();\n+                    final OutputStream out = new FileOutputStream(cachedResourceVersionDownloadFile)\n+                ) {\n+                    FileCopyUtils.copy(in, out);\n+                    Files.move(cachedResourceVersionDownloadFile, cachedResourceVersionDataFile);\n+                }\n+            } else {\n+                log.info(\n+                    \"Cache hit: {} (id: {})\",\n+                    uriString,\n+                    resourceCacheId\n+                );\n+            }\n+\n+            Files.copy(cachedResourceVersionDataFile, destinationFile);\n+        }\n+\n+        //Clean up any older versions in a different thread\n+        oldResourcesCleanUpService.submit(() -> {\n+            try {\n+                cleanUpOlderResourceVersions(resourceCacheId, resourceLastModified);\n+            } catch (IOException e) {\n+                log.error(\n+                    \"Error cleaning up old resource resourceCacheId - {}, resourceLastModified - {}\",\n+                    resourceCacheId,\n+                    resourceLastModified,\n+                    e\n+                );\n+            }\n+        });\n+    }\n+\n+    private FileChannel getLockFileChannel(","path":"genie-agent/src/main/java/com/netflix/genie/agent/execution/services/impl/FileSystemFetchingCacheService.java","position":216,"original_position":216,"commit_id":"e9e47f1b9d5bd91a1fa578075b5bf25e34cc27f8","original_commit_id":"e9e47f1b9d5bd91a1fa578075b5bf25e34cc27f8","user":{"login":"sumitnetflix","id":37452933,"avatar_url":"https://avatars2.githubusercontent.com/u/37452933?v=4","gravatar_id":"","url":"https://api.github.com/users/sumitnetflix","html_url":"https://github.com/sumitnetflix","followers_url":"https://api.github.com/users/sumitnetflix/followers","following_url":"https://api.github.com/users/sumitnetflix/following{/other_user}","gists_url":"https://api.github.com/users/sumitnetflix/gists{/gist_id}","starred_url":"https://api.github.com/users/sumitnetflix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sumitnetflix/subscriptions","organizations_url":"https://api.github.com/users/sumitnetflix/orgs","repos_url":"https://api.github.com/users/sumitnetflix/repos","events_url":"https://api.github.com/users/sumitnetflix/events{/privacy}","received_events_url":"https://api.github.com/users/sumitnetflix/received_events","type":"User","site_admin":false},"body":"Bad name. Will fix. ","created_at":"2018-05-14T21:38:55Z","updated_at":"2018-05-14T21:38:55Z","html_url":"https://github.com/Netflix/genie/pull/734#discussion_r188106922","pull_request_url":"https://api.github.com/repos/Netflix/genie/pulls/734","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/Netflix/genie/pulls/comments/188106922"},"html":{"href":"https://github.com/Netflix/genie/pull/734#discussion_r188106922"},"pull_request":{"href":"https://api.github.com/repos/Netflix/genie/pulls/734"}},"in_reply_to_id":188040941},"pull_request":{"url":"https://api.github.com/repos/Netflix/genie/pulls/734","id":187596562,"html_url":"https://github.com/Netflix/genie/pull/734","diff_url":"https://github.com/Netflix/genie/pull/734.diff","patch_url":"https://github.com/Netflix/genie/pull/734.patch","issue_url":"https://api.github.com/repos/Netflix/genie/issues/734","number":734,"state":"open","locked":false,"title":"Add caching for downloading dependencies","user":{"login":"sumitnetflix","id":37452933,"avatar_url":"https://avatars2.githubusercontent.com/u/37452933?v=4","gravatar_id":"","url":"https://api.github.com/users/sumitnetflix","html_url":"https://github.com/sumitnetflix","followers_url":"https://api.github.com/users/sumitnetflix/followers","following_url":"https://api.github.com/users/sumitnetflix/following{/other_user}","gists_url":"https://api.github.com/users/sumitnetflix/gists{/gist_id}","starred_url":"https://api.github.com/users/sumitnetflix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sumitnetflix/subscriptions","organizations_url":"https://api.github.com/users/sumitnetflix/orgs","repos_url":"https://api.github.com/users/sumitnetflix/repos","events_url":"https://api.github.com/users/sumitnetflix/events{/privacy}","received_events_url":"https://api.github.com/users/sumitnetflix/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-05-12T00:54:18Z","updated_at":"2018-05-14T21:38:55Z","closed_at":null,"merged_at":null,"merge_commit_sha":"13d6dfa3ea360f37412c9ba80a0cbc2cce30da07","assignee":{"login":"sumitnetflix","id":37452933,"avatar_url":"https://avatars2.githubusercontent.com/u/37452933?v=4","gravatar_id":"","url":"https://api.github.com/users/sumitnetflix","html_url":"https://github.com/sumitnetflix","followers_url":"https://api.github.com/users/sumitnetflix/followers","following_url":"https://api.github.com/users/sumitnetflix/following{/other_user}","gists_url":"https://api.github.com/users/sumitnetflix/gists{/gist_id}","starred_url":"https://api.github.com/users/sumitnetflix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sumitnetflix/subscriptions","organizations_url":"https://api.github.com/users/sumitnetflix/orgs","repos_url":"https://api.github.com/users/sumitnetflix/repos","events_url":"https://api.github.com/users/sumitnetflix/events{/privacy}","received_events_url":"https://api.github.com/users/sumitnetflix/received_events","type":"User","site_admin":false},"assignees":[{"login":"sumitnetflix","id":37452933,"avatar_url":"https://avatars2.githubusercontent.com/u/37452933?v=4","gravatar_id":"","url":"https://api.github.com/users/sumitnetflix","html_url":"https://github.com/sumitnetflix","followers_url":"https://api.github.com/users/sumitnetflix/followers","following_url":"https://api.github.com/users/sumitnetflix/following{/other_user}","gists_url":"https://api.github.com/users/sumitnetflix/gists{/gist_id}","starred_url":"https://api.github.com/users/sumitnetflix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sumitnetflix/subscriptions","organizations_url":"https://api.github.com/users/sumitnetflix/orgs","repos_url":"https://api.github.com/users/sumitnetflix/repos","events_url":"https://api.github.com/users/sumitnetflix/events{/privacy}","received_events_url":"https://api.github.com/users/sumitnetflix/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":44305704,"url":"https://api.github.com/repos/Netflix/genie/labels/feature","name":"feature","color":"84b6eb","default":false}],"milestone":{"url":"https://api.github.com/repos/Netflix/genie/milestones/25","html_url":"https://github.com/Netflix/genie/milestone/25","labels_url":"https://api.github.com/repos/Netflix/genie/milestones/25/labels","id":2778855,"number":25,"title":"4.0.0","description":"","creator":{"login":"tgianos","id":7377597,"avatar_url":"https://avatars0.githubusercontent.com/u/7377597?v=4","gravatar_id":"","url":"https://api.github.com/users/tgianos","html_url":"https://github.com/tgianos","followers_url":"https://api.github.com/users/tgianos/followers","following_url":"https://api.github.com/users/tgianos/following{/other_user}","gists_url":"https://api.github.com/users/tgianos/gists{/gist_id}","starred_url":"https://api.github.com/users/tgianos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tgianos/subscriptions","organizations_url":"https://api.github.com/users/tgianos/orgs","repos_url":"https://api.github.com/users/tgianos/repos","events_url":"https://api.github.com/users/tgianos/events{/privacy}","received_events_url":"https://api.github.com/users/tgianos/received_events","type":"User","site_admin":false},"open_issues":1,"closed_issues":49,"state":"open","created_at":"2017-09-19T20:43:22Z","updated_at":"2018-05-12T00:54:18Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/Netflix/genie/pulls/734/commits","review_comments_url":"https://api.github.com/repos/Netflix/genie/pulls/734/comments","review_comment_url":"https://api.github.com/repos/Netflix/genie/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Netflix/genie/issues/734/comments","statuses_url":"https://api.github.com/repos/Netflix/genie/statuses/e9e47f1b9d5bd91a1fa578075b5bf25e34cc27f8","head":{"label":"sumitnetflix:dependency_caching","ref":"dependency_caching","sha":"e9e47f1b9d5bd91a1fa578075b5bf25e34cc27f8","user":{"login":"sumitnetflix","id":37452933,"avatar_url":"https://avatars2.githubusercontent.com/u/37452933?v=4","gravatar_id":"","url":"https://api.github.com/users/sumitnetflix","html_url":"https://github.com/sumitnetflix","followers_url":"https://api.github.com/users/sumitnetflix/followers","following_url":"https://api.github.com/users/sumitnetflix/following{/other_user}","gists_url":"https://api.github.com/users/sumitnetflix/gists{/gist_id}","starred_url":"https://api.github.com/users/sumitnetflix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sumitnetflix/subscriptions","organizations_url":"https://api.github.com/users/sumitnetflix/orgs","repos_url":"https://api.github.com/users/sumitnetflix/repos","events_url":"https://api.github.com/users/sumitnetflix/events{/privacy}","received_events_url":"https://api.github.com/users/sumitnetflix/received_events","type":"User","site_admin":false},"repo":{"id":125549104,"name":"genie","full_name":"sumitnetflix/genie","owner":{"login":"sumitnetflix","id":37452933,"avatar_url":"https://avatars2.githubusercontent.com/u/37452933?v=4","gravatar_id":"","url":"https://api.github.com/users/sumitnetflix","html_url":"https://github.com/sumitnetflix","followers_url":"https://api.github.com/users/sumitnetflix/followers","following_url":"https://api.github.com/users/sumitnetflix/following{/other_user}","gists_url":"https://api.github.com/users/sumitnetflix/gists{/gist_id}","starred_url":"https://api.github.com/users/sumitnetflix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sumitnetflix/subscriptions","organizations_url":"https://api.github.com/users/sumitnetflix/orgs","repos_url":"https://api.github.com/users/sumitnetflix/repos","events_url":"https://api.github.com/users/sumitnetflix/events{/privacy}","received_events_url":"https://api.github.com/users/sumitnetflix/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sumitnetflix/genie","description":"Distributed Big Data Orchestration Service","fork":true,"url":"https://api.github.com/repos/sumitnetflix/genie","forks_url":"https://api.github.com/repos/sumitnetflix/genie/forks","keys_url":"https://api.github.com/repos/sumitnetflix/genie/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sumitnetflix/genie/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sumitnetflix/genie/teams","hooks_url":"https://api.github.com/repos/sumitnetflix/genie/hooks","issue_events_url":"https://api.github.com/repos/sumitnetflix/genie/issues/events{/number}","events_url":"https://api.github.com/repos/sumitnetflix/genie/events","assignees_url":"https://api.github.com/repos/sumitnetflix/genie/assignees{/user}","branches_url":"https://api.github.com/repos/sumitnetflix/genie/branches{/branch}","tags_url":"https://api.github.com/repos/sumitnetflix/genie/tags","blobs_url":"https://api.github.com/repos/sumitnetflix/genie/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sumitnetflix/genie/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sumitnetflix/genie/git/refs{/sha}","trees_url":"https://api.github.com/repos/sumitnetflix/genie/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sumitnetflix/genie/statuses/{sha}","languages_url":"https://api.github.com/repos/sumitnetflix/genie/languages","stargazers_url":"https://api.github.com/repos/sumitnetflix/genie/stargazers","contributors_url":"https://api.github.com/repos/sumitnetflix/genie/contributors","subscribers_url":"https://api.github.com/repos/sumitnetflix/genie/subscribers","subscription_url":"https://api.github.com/repos/sumitnetflix/genie/subscription","commits_url":"https://api.github.com/repos/sumitnetflix/genie/commits{/sha}","git_commits_url":"https://api.github.com/repos/sumitnetflix/genie/git/commits{/sha}","comments_url":"https://api.github.com/repos/sumitnetflix/genie/comments{/number}","issue_comment_url":"https://api.github.com/repos/sumitnetflix/genie/issues/comments{/number}","contents_url":"https://api.github.com/repos/sumitnetflix/genie/contents/{+path}","compare_url":"https://api.github.com/repos/sumitnetflix/genie/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sumitnetflix/genie/merges","archive_url":"https://api.github.com/repos/sumitnetflix/genie/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sumitnetflix/genie/downloads","issues_url":"https://api.github.com/repos/sumitnetflix/genie/issues{/number}","pulls_url":"https://api.github.com/repos/sumitnetflix/genie/pulls{/number}","milestones_url":"https://api.github.com/repos/sumitnetflix/genie/milestones{/number}","notifications_url":"https://api.github.com/repos/sumitnetflix/genie/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sumitnetflix/genie/labels{/name}","releases_url":"https://api.github.com/repos/sumitnetflix/genie/releases{/id}","deployments_url":"https://api.github.com/repos/sumitnetflix/genie/deployments","created_at":"2018-03-16T17:31:34Z","updated_at":"2018-05-10T21:37:19Z","pushed_at":"2018-05-13T22:22:35Z","git_url":"git://github.com/sumitnetflix/genie.git","ssh_url":"git@github.com:sumitnetflix/genie.git","clone_url":"https://github.com/sumitnetflix/genie.git","svn_url":"https://github.com/sumitnetflix/genie","homepage":"https://netflix.github.io/genie","size":114464,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Netflix:master","ref":"master","sha":"f19b9cb6b125aff7745943264c7d8545453a8700","user":{"login":"Netflix","id":913567,"avatar_url":"https://avatars3.githubusercontent.com/u/913567?v=4","gravatar_id":"","url":"https://api.github.com/users/Netflix","html_url":"https://github.com/Netflix","followers_url":"https://api.github.com/users/Netflix/followers","following_url":"https://api.github.com/users/Netflix/following{/other_user}","gists_url":"https://api.github.com/users/Netflix/gists{/gist_id}","starred_url":"https://api.github.com/users/Netflix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Netflix/subscriptions","organizations_url":"https://api.github.com/users/Netflix/orgs","repos_url":"https://api.github.com/users/Netflix/repos","events_url":"https://api.github.com/users/Netflix/events{/privacy}","received_events_url":"https://api.github.com/users/Netflix/received_events","type":"Organization","site_admin":false},"repo":{"id":10828921,"name":"genie","full_name":"Netflix/genie","owner":{"login":"Netflix","id":913567,"avatar_url":"https://avatars3.githubusercontent.com/u/913567?v=4","gravatar_id":"","url":"https://api.github.com/users/Netflix","html_url":"https://github.com/Netflix","followers_url":"https://api.github.com/users/Netflix/followers","following_url":"https://api.github.com/users/Netflix/following{/other_user}","gists_url":"https://api.github.com/users/Netflix/gists{/gist_id}","starred_url":"https://api.github.com/users/Netflix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Netflix/subscriptions","organizations_url":"https://api.github.com/users/Netflix/orgs","repos_url":"https://api.github.com/users/Netflix/repos","events_url":"https://api.github.com/users/Netflix/events{/privacy}","received_events_url":"https://api.github.com/users/Netflix/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Netflix/genie","description":"Distributed Big Data Orchestration Service","fork":false,"url":"https://api.github.com/repos/Netflix/genie","forks_url":"https://api.github.com/repos/Netflix/genie/forks","keys_url":"https://api.github.com/repos/Netflix/genie/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Netflix/genie/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Netflix/genie/teams","hooks_url":"https://api.github.com/repos/Netflix/genie/hooks","issue_events_url":"https://api.github.com/repos/Netflix/genie/issues/events{/number}","events_url":"https://api.github.com/repos/Netflix/genie/events","assignees_url":"https://api.github.com/repos/Netflix/genie/assignees{/user}","branches_url":"https://api.github.com/repos/Netflix/genie/branches{/branch}","tags_url":"https://api.github.com/repos/Netflix/genie/tags","blobs_url":"https://api.github.com/repos/Netflix/genie/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Netflix/genie/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Netflix/genie/git/refs{/sha}","trees_url":"https://api.github.com/repos/Netflix/genie/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Netflix/genie/statuses/{sha}","languages_url":"https://api.github.com/repos/Netflix/genie/languages","stargazers_url":"https://api.github.com/repos/Netflix/genie/stargazers","contributors_url":"https://api.github.com/repos/Netflix/genie/contributors","subscribers_url":"https://api.github.com/repos/Netflix/genie/subscribers","subscription_url":"https://api.github.com/repos/Netflix/genie/subscription","commits_url":"https://api.github.com/repos/Netflix/genie/commits{/sha}","git_commits_url":"https://api.github.com/repos/Netflix/genie/git/commits{/sha}","comments_url":"https://api.github.com/repos/Netflix/genie/comments{/number}","issue_comment_url":"https://api.github.com/repos/Netflix/genie/issues/comments{/number}","contents_url":"https://api.github.com/repos/Netflix/genie/contents/{+path}","compare_url":"https://api.github.com/repos/Netflix/genie/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Netflix/genie/merges","archive_url":"https://api.github.com/repos/Netflix/genie/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Netflix/genie/downloads","issues_url":"https://api.github.com/repos/Netflix/genie/issues{/number}","pulls_url":"https://api.github.com/repos/Netflix/genie/pulls{/number}","milestones_url":"https://api.github.com/repos/Netflix/genie/milestones{/number}","notifications_url":"https://api.github.com/repos/Netflix/genie/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Netflix/genie/labels{/name}","releases_url":"https://api.github.com/repos/Netflix/genie/releases{/id}","deployments_url":"https://api.github.com/repos/Netflix/genie/deployments","created_at":"2013-06-20T20:35:56Z","updated_at":"2018-05-14T04:34:17Z","pushed_at":"2018-05-14T19:54:41Z","git_url":"git://github.com/Netflix/genie.git","ssh_url":"git@github.com:Netflix/genie.git","clone_url":"https://github.com/Netflix/genie.git","svn_url":"https://github.com/Netflix/genie","homepage":"https://netflix.github.io/genie","size":124524,"stargazers_count":894,"watchers_count":894,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":225,"mirror_url":null,"archived":false,"open_issues_count":2,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":225,"open_issues":2,"watchers":894,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Netflix/genie/pulls/734"},"html":{"href":"https://github.com/Netflix/genie/pull/734"},"issue":{"href":"https://api.github.com/repos/Netflix/genie/issues/734"},"comments":{"href":"https://api.github.com/repos/Netflix/genie/issues/734/comments"},"review_comments":{"href":"https://api.github.com/repos/Netflix/genie/pulls/734/comments"},"review_comment":{"href":"https://api.github.com/repos/Netflix/genie/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Netflix/genie/pulls/734/commits"},"statuses":{"href":"https://api.github.com/repos/Netflix/genie/statuses/e9e47f1b9d5bd91a1fa578075b5bf25e34cc27f8"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"sumitnetflix"}}