{"action":"created","comment":{"url":"https://api.github.com/repos/keybase/kbfs/pulls/comments/84237814","pull_request_review_id":5023024,"id":84237814,"diff_hunk":"@@ -883,97 +889,144 @@ func (j *tlfJournal) getJournalStatus() (TLFJournalStatus, error) {\n }\n \n func (j *tlfJournal) getJournalStatusWithRange() (\n-\tTLFJournalStatus, []ImmutableBareRootMetadata, bool, error) {\n+\tTLFJournalStatus, []ImmutableBareRootMetadata,\n+\tunflushedPathsMap, bool, error) {\n \tj.journalLock.RLock()\n \tdefer j.journalLock.RUnlock()\n \tjStatus, err := j.getJournalStatusLocked()\n \tif err != nil {\n-\t\treturn TLFJournalStatus{}, nil, false, err\n-\t}\n-\n-\tif jStatus.RevisionEnd == MetadataRevisionUninitialized {\n-\t\treturn jStatus, nil, true, nil\n+\t\treturn TLFJournalStatus{}, nil, nil, false, err\n \t}\n \n-\tstop := jStatus.RevisionEnd\n \tcomplete := true\n-\tif stop > jStatus.RevisionStart+1000 {\n-\t\tstop = jStatus.RevisionStart + 1000\n-\t\tcomplete = false\n-\t}\n+\tvar ibrmds []ImmutableBareRootMetadata\n+\tunflushedPaths := j.unflushedPaths.getUnflushedPaths()\n+\tif unflushedPaths == nil &&\n+\t\tjStatus.RevisionEnd != MetadataRevisionUninitialized {\n+\t\tstop := jStatus.RevisionEnd\n+\t\tif stop > jStatus.RevisionStart+1000 {\n+\t\t\tstop = jStatus.RevisionStart + 1000\n+\t\t\tcomplete = false\n+\t\t}\n \n-\tibrmds, err := j.mdJournal.getRange(\n-\t\tjStatus.RevisionStart, stop)\n-\tif err != nil {\n-\t\treturn TLFJournalStatus{}, nil, false, err\n+\t\t// It would be nice to avoid getting this range if we are not\n+\t\t// the initializer, but at this point we don't know if we'll\n+\t\t// need to initialize or not.\n+\t\tibrmds, err = j.mdJournal.getRange(jStatus.RevisionStart, stop)\n+\t\tif err != nil {\n+\t\t\treturn TLFJournalStatus{}, nil, nil, false, err\n+\t\t}\n \t}\n-\treturn jStatus, ibrmds, complete, nil\n+\n+\treturn jStatus, ibrmds, unflushedPaths, complete, nil\n }\n \n-func (j *tlfJournal) getJournalStatusWithPaths(ctx context.Context,\n-\tcpp chainsPathPopulator) (TLFJournalStatus, error) {\n-\tjStatus, ibrmds, complete, err := j.getJournalStatusWithRange()\n-\tif err != nil {\n-\t\treturn TLFJournalStatus{}, err\n-\t}\n+func (j *tlfJournal) batchConvertImmutables(ctx context.Context,\n+\tibrmds []ImmutableBareRootMetadata) ([]ImmutableRootMetadata, error) {\n+\tirmds := make([]ImmutableRootMetadata, 0, len(ibrmds))\n+\tif len(ibrmds) > 0 {\n+\t\tibrmdBareHandle, err := ibrmds[0].MakeBareTlfHandle(nil)\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n \n-\tif len(ibrmds) == 0 {\n-\t\treturn jStatus, nil\n-\t}\n+\t\thandle, err := MakeTlfHandle(\n+\t\t\tctx, ibrmdBareHandle, j.config.usernameGetter())\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n \n-\tibrmdBareHandle, err := ibrmds[0].MakeBareTlfHandle(nil)\n-\tif err != nil {\n-\t\treturn TLFJournalStatus{}, err\n-\t}\n+\t\tfor _, ibrmd := range ibrmds {\n+\t\t\tirmd, err := j.convertImmutableBareRMDToIRMD(ctx, ibrmd, handle)\n+\t\t\tif err != nil {\n+\t\t\t\treturn nil, err\n+\t\t\t}\n \n-\tirmds := make([]ImmutableRootMetadata, 0, len(ibrmds))\n-\thandle, err := MakeTlfHandle(\n-\t\tctx, ibrmdBareHandle, j.config.usernameGetter())\n-\tif err != nil {\n-\t\treturn TLFJournalStatus{}, err\n+\t\t\tirmds = append(irmds, irmd)\n+\t\t}\n \t}\n \n-\tfor _, ibrmd := range ibrmds {\n-\t\tirmd, err := j.convertImmutableBareRMDToIRMD(ctx, ibrmd, handle)\n+\treturn irmds, nil\n+}\n+\n+func (j *tlfJournal) getJournalStatusWithPaths(ctx context.Context,\n+\tcpp chainsPathPopulator) (jStatus TLFJournalStatus, err error) {\n+\t// This loop is limited only by the lifetime of `ctx`.\n+\tvar unflushedPaths unflushedPathsMap\n+\tvar complete bool\n+\tfor {\n+\t\tvar ibrmds []ImmutableBareRootMetadata\n+\t\tjStatus, ibrmds, unflushedPaths, complete, err =\n+\t\t\tj.getJournalStatusWithRange()\n \t\tif err != nil {\n \t\t\treturn TLFJournalStatus{}, err\n \t\t}\n \n-\t\tirmds = append(irmds, irmd)\n-\t}\n-\n-\t// Make chains over the entire range to get the unflushed files.\n-\t// TODO: cache this chains object and update it when new revisions\n-\t// appear and when revisions are flushed, instead of rebuilding\n-\t// every time.\n-\tchains := newCRChainsEmpty()\n-\tfor _, irmd := range irmds {\n-\t\twinfo := writerInfo{\n-\t\t\tuid:      j.uid,\n-\t\t\tkid:      j.key.KID(),\n-\t\t\trevision: irmd.Revision(),\n-\t\t\t// There won't be any conflicts, so no need for the\n-\t\t\t// username/devicename.\n-\t\t}\n-\t\terr := chains.addOps(j.config.Codec(), irmd.data, winfo,\n-\t\t\tirmd.localTimestamp)\n-\t\tif err != nil {\n-\t\t\treturn TLFJournalStatus{}, nil\n-\t\t}\n-\t}\n-\tchains.mostRecentMD = irmds[len(irmds)-1]\n+\t\t// We need to make or initialize the unflushed paths.\n+\t\tif unflushedPaths == nil {\n+\t\t\tif !complete {\n+\t\t\t\t// Figure out the paths for the truncated MD range,\n+\t\t\t\t// but don't cache it.\n+\t\t\t\tunflushedPaths = make(unflushedPathsMap)\n+\t\t\t\tj.log.CDebugf(ctx, \"Making incomplete unflushed path cache\")\n+\t\t\t\tirmds, err := j.batchConvertImmutables(ctx, ibrmds)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn TLFJournalStatus{}, err\n+\t\t\t\t}\n+\t\t\t\terr = addUnflushedPaths(ctx, j.uid, j.key.KID(),\n+\t\t\t\t\tj.config.Codec(), j.log, irmds, cpp,\n+\t\t\t\t\tunflushedPaths)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn TLFJournalStatus{}, err\n+\t\t\t\t}\n+\t\t\t\tbreak\n+\t\t\t}\n \n-\terr = cpp.populateChainPaths(ctx, j.log, chains, true)\n-\tif err != nil {\n-\t\treturn TLFJournalStatus{}, err\n+\t\t\t// We need to init it ourselves, or wait for someone else\n+\t\t\t// to do it.\n+\t\t\tdoInit, err := j.unflushedPaths.startInitializeOrWait(ctx)\n+\t\t\tif err != nil {\n+\t\t\t\treturn TLFJournalStatus{}, err\n+\t\t\t}\n+\n+\t\t\tif doInit {\n+\t\t\t\tinitSuccess := false\n+\t\t\t\tdefer func() {\n+\t\t\t\t\tif !initSuccess || err != nil {\n+\t\t\t\t\t\tj.unflushedPaths.abortInitialization()\n+\t\t\t\t\t}\n+\t\t\t\t}()\n+\n+\t\t\t\tj.log.CDebugf(ctx, \"Initializing unflushed paths\")\n+\t\t\t\tirmds, err := j.batchConvertImmutables(ctx, ibrmds)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn TLFJournalStatus{}, err\n+\t\t\t\t}\n+\t\t\t\tunflushedPaths, initSuccess, err = j.unflushedPaths.initialize(\n+\t\t\t\t\tctx, j.uid, j.key.KID(), j.config.Codec(), j.log, cpp,\n+\t\t\t\t\tirmds)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn TLFJournalStatus{}, err\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tj.log.CDebugf(ctx, \"Waited for unflushed paths \"+\n+\t\t\t\t\t\"initialization, trying again to get the status\")\n+\t\t\t\tcontinue","path":"libkbfs/tlf_journal.go","position":218,"original_position":218,"commit_id":"713477ff9ba30684f0fbc48f8696a6eab2386284","original_commit_id":"713477ff9ba30684f0fbc48f8696a6eab2386284","user":{"login":"akalin-keybase","id":13270622,"avatar_url":"https://avatars.githubusercontent.com/u/13270622?v=3","gravatar_id":"","url":"https://api.github.com/users/akalin-keybase","html_url":"https://github.com/akalin-keybase","followers_url":"https://api.github.com/users/akalin-keybase/followers","following_url":"https://api.github.com/users/akalin-keybase/following{/other_user}","gists_url":"https://api.github.com/users/akalin-keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/akalin-keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akalin-keybase/subscriptions","organizations_url":"https://api.github.com/users/akalin-keybase/orgs","repos_url":"https://api.github.com/users/akalin-keybase/repos","events_url":"https://api.github.com/users/akalin-keybase/events{/privacy}","received_events_url":"https://api.github.com/users/akalin-keybase/received_events","type":"User","site_admin":false},"body":"let fall through to loop back around?","created_at":"2016-10-20T08:53:21Z","updated_at":"2016-10-20T08:55:07Z","html_url":"https://github.com/keybase/kbfs/pull/422#discussion_r84237814","pull_request_url":"https://api.github.com/repos/keybase/kbfs/pulls/422","_links":{"self":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/comments/84237814"},"html":{"href":"https://github.com/keybase/kbfs/pull/422#discussion_r84237814"},"pull_request":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/422"}}},"pull_request":{"url":"https://api.github.com/repos/keybase/kbfs/pulls/422","id":89117205,"html_url":"https://github.com/keybase/kbfs/pull/422","diff_url":"https://github.com/keybase/kbfs/pull/422.diff","patch_url":"https://github.com/keybase/kbfs/pull/422.patch","issue_url":"https://api.github.com/repos/keybase/kbfs/issues/422","number":422,"state":"open","locked":false,"title":"tlf_journal: cache unflushed paths and update them on puts and flushes","user":{"login":"strib","id":8516691,"avatar_url":"https://avatars.githubusercontent.com/u/8516691?v=3","gravatar_id":"","url":"https://api.github.com/users/strib","html_url":"https://github.com/strib","followers_url":"https://api.github.com/users/strib/followers","following_url":"https://api.github.com/users/strib/following{/other_user}","gists_url":"https://api.github.com/users/strib/gists{/gist_id}","starred_url":"https://api.github.com/users/strib/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strib/subscriptions","organizations_url":"https://api.github.com/users/strib/orgs","repos_url":"https://api.github.com/users/strib/repos","events_url":"https://api.github.com/users/strib/events{/privacy}","received_events_url":"https://api.github.com/users/strib/received_events","type":"User","site_admin":false},"body":"This PR calculates the unflushed paths the first time they are asked for (even if multiple goroutines ask for them concurrently), and then keeps them up-to-date as puts and flushes happen.\r\n\r\nIssue: KBFS-1476\r\nIssue: KBFS-1477","created_at":"2016-10-13T00:15:56Z","updated_at":"2016-10-20T08:55:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"833da670bd2234ad67a765af8626d3fd467ff2e3","assignee":{"login":"akalin-keybase","id":13270622,"avatar_url":"https://avatars.githubusercontent.com/u/13270622?v=3","gravatar_id":"","url":"https://api.github.com/users/akalin-keybase","html_url":"https://github.com/akalin-keybase","followers_url":"https://api.github.com/users/akalin-keybase/followers","following_url":"https://api.github.com/users/akalin-keybase/following{/other_user}","gists_url":"https://api.github.com/users/akalin-keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/akalin-keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akalin-keybase/subscriptions","organizations_url":"https://api.github.com/users/akalin-keybase/orgs","repos_url":"https://api.github.com/users/akalin-keybase/repos","events_url":"https://api.github.com/users/akalin-keybase/events{/privacy}","received_events_url":"https://api.github.com/users/akalin-keybase/received_events","type":"User","site_admin":false},"assignees":[{"login":"akalin-keybase","id":13270622,"avatar_url":"https://avatars.githubusercontent.com/u/13270622?v=3","gravatar_id":"","url":"https://api.github.com/users/akalin-keybase","html_url":"https://github.com/akalin-keybase","followers_url":"https://api.github.com/users/akalin-keybase/followers","following_url":"https://api.github.com/users/akalin-keybase/following{/other_user}","gists_url":"https://api.github.com/users/akalin-keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/akalin-keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akalin-keybase/subscriptions","organizations_url":"https://api.github.com/users/akalin-keybase/orgs","repos_url":"https://api.github.com/users/akalin-keybase/repos","events_url":"https://api.github.com/users/akalin-keybase/events{/privacy}","received_events_url":"https://api.github.com/users/akalin-keybase/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/keybase/kbfs/pulls/422/commits","review_comments_url":"https://api.github.com/repos/keybase/kbfs/pulls/422/comments","review_comment_url":"https://api.github.com/repos/keybase/kbfs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/keybase/kbfs/issues/422/comments","statuses_url":"https://api.github.com/repos/keybase/kbfs/statuses/713477ff9ba30684f0fbc48f8696a6eab2386284","head":{"label":"keybase:strib/KBFS-1476-KBFS-1477-journal-cache-unflushed-paths","ref":"strib/KBFS-1476-KBFS-1477-journal-cache-unflushed-paths","sha":"713477ff9ba30684f0fbc48f8696a6eab2386284","user":{"login":"keybase","id":5400834,"avatar_url":"https://avatars.githubusercontent.com/u/5400834?v=3","gravatar_id":"","url":"https://api.github.com/users/keybase","html_url":"https://github.com/keybase","followers_url":"https://api.github.com/users/keybase/followers","following_url":"https://api.github.com/users/keybase/following{/other_user}","gists_url":"https://api.github.com/users/keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keybase/subscriptions","organizations_url":"https://api.github.com/users/keybase/orgs","repos_url":"https://api.github.com/users/keybase/repos","events_url":"https://api.github.com/users/keybase/events{/privacy}","received_events_url":"https://api.github.com/users/keybase/received_events","type":"Organization","site_admin":false},"repo":{"id":59787605,"name":"kbfs","full_name":"keybase/kbfs","owner":{"login":"keybase","id":5400834,"avatar_url":"https://avatars.githubusercontent.com/u/5400834?v=3","gravatar_id":"","url":"https://api.github.com/users/keybase","html_url":"https://github.com/keybase","followers_url":"https://api.github.com/users/keybase/followers","following_url":"https://api.github.com/users/keybase/following{/other_user}","gists_url":"https://api.github.com/users/keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keybase/subscriptions","organizations_url":"https://api.github.com/users/keybase/orgs","repos_url":"https://api.github.com/users/keybase/repos","events_url":"https://api.github.com/users/keybase/events{/privacy}","received_events_url":"https://api.github.com/users/keybase/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/keybase/kbfs","description":"Keybase Filesystem (KBFS)","fork":false,"url":"https://api.github.com/repos/keybase/kbfs","forks_url":"https://api.github.com/repos/keybase/kbfs/forks","keys_url":"https://api.github.com/repos/keybase/kbfs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/keybase/kbfs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/keybase/kbfs/teams","hooks_url":"https://api.github.com/repos/keybase/kbfs/hooks","issue_events_url":"https://api.github.com/repos/keybase/kbfs/issues/events{/number}","events_url":"https://api.github.com/repos/keybase/kbfs/events","assignees_url":"https://api.github.com/repos/keybase/kbfs/assignees{/user}","branches_url":"https://api.github.com/repos/keybase/kbfs/branches{/branch}","tags_url":"https://api.github.com/repos/keybase/kbfs/tags","blobs_url":"https://api.github.com/repos/keybase/kbfs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/keybase/kbfs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/keybase/kbfs/git/refs{/sha}","trees_url":"https://api.github.com/repos/keybase/kbfs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/keybase/kbfs/statuses/{sha}","languages_url":"https://api.github.com/repos/keybase/kbfs/languages","stargazers_url":"https://api.github.com/repos/keybase/kbfs/stargazers","contributors_url":"https://api.github.com/repos/keybase/kbfs/contributors","subscribers_url":"https://api.github.com/repos/keybase/kbfs/subscribers","subscription_url":"https://api.github.com/repos/keybase/kbfs/subscription","commits_url":"https://api.github.com/repos/keybase/kbfs/commits{/sha}","git_commits_url":"https://api.github.com/repos/keybase/kbfs/git/commits{/sha}","comments_url":"https://api.github.com/repos/keybase/kbfs/comments{/number}","issue_comment_url":"https://api.github.com/repos/keybase/kbfs/issues/comments{/number}","contents_url":"https://api.github.com/repos/keybase/kbfs/contents/{+path}","compare_url":"https://api.github.com/repos/keybase/kbfs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/keybase/kbfs/merges","archive_url":"https://api.github.com/repos/keybase/kbfs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/keybase/kbfs/downloads","issues_url":"https://api.github.com/repos/keybase/kbfs/issues{/number}","pulls_url":"https://api.github.com/repos/keybase/kbfs/pulls{/number}","milestones_url":"https://api.github.com/repos/keybase/kbfs/milestones{/number}","notifications_url":"https://api.github.com/repos/keybase/kbfs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/keybase/kbfs/labels{/name}","releases_url":"https://api.github.com/repos/keybase/kbfs/releases{/id}","deployments_url":"https://api.github.com/repos/keybase/kbfs/deployments","created_at":"2016-05-26T22:37:42Z","updated_at":"2016-10-20T07:35:01Z","pushed_at":"2016-10-20T05:41:12Z","git_url":"git://github.com/keybase/kbfs.git","ssh_url":"git@github.com:keybase/kbfs.git","clone_url":"https://github.com/keybase/kbfs.git","svn_url":"https://github.com/keybase/kbfs","homepage":"https://keybase.io/docs/kbfs","size":36233,"stargazers_count":213,"watchers_count":213,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":23,"mirror_url":null,"open_issues_count":22,"forks":23,"open_issues":22,"watchers":213,"default_branch":"master"}},"base":{"label":"keybase:master","ref":"master","sha":"d40224372acc251632215cd82617a63dea0d0158","user":{"login":"keybase","id":5400834,"avatar_url":"https://avatars.githubusercontent.com/u/5400834?v=3","gravatar_id":"","url":"https://api.github.com/users/keybase","html_url":"https://github.com/keybase","followers_url":"https://api.github.com/users/keybase/followers","following_url":"https://api.github.com/users/keybase/following{/other_user}","gists_url":"https://api.github.com/users/keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keybase/subscriptions","organizations_url":"https://api.github.com/users/keybase/orgs","repos_url":"https://api.github.com/users/keybase/repos","events_url":"https://api.github.com/users/keybase/events{/privacy}","received_events_url":"https://api.github.com/users/keybase/received_events","type":"Organization","site_admin":false},"repo":{"id":59787605,"name":"kbfs","full_name":"keybase/kbfs","owner":{"login":"keybase","id":5400834,"avatar_url":"https://avatars.githubusercontent.com/u/5400834?v=3","gravatar_id":"","url":"https://api.github.com/users/keybase","html_url":"https://github.com/keybase","followers_url":"https://api.github.com/users/keybase/followers","following_url":"https://api.github.com/users/keybase/following{/other_user}","gists_url":"https://api.github.com/users/keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keybase/subscriptions","organizations_url":"https://api.github.com/users/keybase/orgs","repos_url":"https://api.github.com/users/keybase/repos","events_url":"https://api.github.com/users/keybase/events{/privacy}","received_events_url":"https://api.github.com/users/keybase/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/keybase/kbfs","description":"Keybase Filesystem (KBFS)","fork":false,"url":"https://api.github.com/repos/keybase/kbfs","forks_url":"https://api.github.com/repos/keybase/kbfs/forks","keys_url":"https://api.github.com/repos/keybase/kbfs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/keybase/kbfs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/keybase/kbfs/teams","hooks_url":"https://api.github.com/repos/keybase/kbfs/hooks","issue_events_url":"https://api.github.com/repos/keybase/kbfs/issues/events{/number}","events_url":"https://api.github.com/repos/keybase/kbfs/events","assignees_url":"https://api.github.com/repos/keybase/kbfs/assignees{/user}","branches_url":"https://api.github.com/repos/keybase/kbfs/branches{/branch}","tags_url":"https://api.github.com/repos/keybase/kbfs/tags","blobs_url":"https://api.github.com/repos/keybase/kbfs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/keybase/kbfs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/keybase/kbfs/git/refs{/sha}","trees_url":"https://api.github.com/repos/keybase/kbfs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/keybase/kbfs/statuses/{sha}","languages_url":"https://api.github.com/repos/keybase/kbfs/languages","stargazers_url":"https://api.github.com/repos/keybase/kbfs/stargazers","contributors_url":"https://api.github.com/repos/keybase/kbfs/contributors","subscribers_url":"https://api.github.com/repos/keybase/kbfs/subscribers","subscription_url":"https://api.github.com/repos/keybase/kbfs/subscription","commits_url":"https://api.github.com/repos/keybase/kbfs/commits{/sha}","git_commits_url":"https://api.github.com/repos/keybase/kbfs/git/commits{/sha}","comments_url":"https://api.github.com/repos/keybase/kbfs/comments{/number}","issue_comment_url":"https://api.github.com/repos/keybase/kbfs/issues/comments{/number}","contents_url":"https://api.github.com/repos/keybase/kbfs/contents/{+path}","compare_url":"https://api.github.com/repos/keybase/kbfs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/keybase/kbfs/merges","archive_url":"https://api.github.com/repos/keybase/kbfs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/keybase/kbfs/downloads","issues_url":"https://api.github.com/repos/keybase/kbfs/issues{/number}","pulls_url":"https://api.github.com/repos/keybase/kbfs/pulls{/number}","milestones_url":"https://api.github.com/repos/keybase/kbfs/milestones{/number}","notifications_url":"https://api.github.com/repos/keybase/kbfs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/keybase/kbfs/labels{/name}","releases_url":"https://api.github.com/repos/keybase/kbfs/releases{/id}","deployments_url":"https://api.github.com/repos/keybase/kbfs/deployments","created_at":"2016-05-26T22:37:42Z","updated_at":"2016-10-20T07:35:01Z","pushed_at":"2016-10-20T05:41:12Z","git_url":"git://github.com/keybase/kbfs.git","ssh_url":"git@github.com:keybase/kbfs.git","clone_url":"https://github.com/keybase/kbfs.git","svn_url":"https://github.com/keybase/kbfs","homepage":"https://keybase.io/docs/kbfs","size":36233,"stargazers_count":213,"watchers_count":213,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":23,"mirror_url":null,"open_issues_count":22,"forks":23,"open_issues":22,"watchers":213,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/422"},"html":{"href":"https://github.com/keybase/kbfs/pull/422"},"issue":{"href":"https://api.github.com/repos/keybase/kbfs/issues/422"},"comments":{"href":"https://api.github.com/repos/keybase/kbfs/issues/422/comments"},"review_comments":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/422/comments"},"review_comment":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/422/commits"},"statuses":{"href":"https://api.github.com/repos/keybase/kbfs/statuses/713477ff9ba30684f0fbc48f8696a6eab2386284"}}}}
{"actor":{"display_login":"akalin-keybase"}}