{"action":"created","comment":{"url":"https://api.github.com/repos/keybase/kbfs/pulls/comments/193922171","pull_request_review_id":126996559,"id":193922171,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5MzkyMjE3MQ==","diff_hunk":"@@ -0,0 +1,296 @@\n+// Copyright 2018 Keybase Inc. All rights reserved.\n+// Use of this source code is governed by a BSD\n+// license that can be found in the LICENSE file.\n+\n+package libkbfs\n+\n+import (\n+\t\"context\"\n+\t\"time\"\n+\n+\t\"github.com/keybase/client/go/libkb\"\n+\t\"github.com/keybase/client/go/logger\"\n+\t\"github.com/keybase/client/go/protocol/chat1\"\n+\t\"github.com/keybase/client/go/protocol/keybase1\"\n+\t\"github.com/keybase/go-framed-msgpack-rpc/rpc\"\n+\t\"github.com/keybase/kbfs/tlf\"\n+\t\"github.com/pkg/errors\"\n+)\n+\n+// ChatRPC is an RPC based implementation for chat.\n+type ChatRPC struct {\n+\tconfig   Config\n+\tlog      logger.Logger\n+\tdeferLog logger.Logger\n+\tclient   chat1.LocalInterface\n+}\n+\n+var _ rpc.ConnectionHandler = (*ChatRPC)(nil)\n+\n+// NewChatRPC constructs a new RPC based chat implementation.\n+func NewChatRPC(config Config, kbCtx Context) *ChatRPC {\n+\tlog := config.MakeLogger(\"\")\n+\tdeferLog := log.CloneWithAddedDepth(1)\n+\tc := &ChatRPC{\n+\t\tlog:      log,\n+\t\tdeferLog: deferLog,\n+\t\tconfig:   config,\n+\t}\n+\tconn := NewSharedKeybaseConnection(kbCtx, config, c)\n+\tc.client = chat1.LocalClient{Cli: conn.GetClient()}\n+\treturn c\n+}\n+\n+// HandlerName implements the ConnectionHandler interface.\n+func (ChatRPC) HandlerName() string {\n+\treturn \"Chat\"\n+}\n+\n+// OnConnect implements the ConnectionHandler interface.\n+func (c *ChatRPC) OnConnect(ctx context.Context, conn *rpc.Connection,\n+\t_ rpc.GenericClient, server *rpc.Server) error {\n+\tc.config.KBFSOps().PushConnectionStatusChange(KeybaseServiceName, nil)\n+\treturn nil\n+}\n+\n+// OnConnectError implements the ConnectionHandler interface.\n+func (c *ChatRPC) OnConnectError(err error, wait time.Duration) {\n+\tc.log.Warning(\"Chat: connection error: %q; retrying in %s\",\n+\t\terr, wait)\n+\tc.config.KBFSOps().PushConnectionStatusChange(KeybaseServiceName, err)\n+}\n+\n+// OnDoCommandError implements the ConnectionHandler interface.\n+func (c *ChatRPC) OnDoCommandError(err error, wait time.Duration) {\n+\tc.log.Warning(\"Chat: docommand error: %q; retrying in %s\",\n+\t\terr, wait)\n+\tc.config.KBFSOps().PushConnectionStatusChange(KeybaseServiceName, err)\n+}\n+\n+// OnDisconnected implements the ConnectionHandler interface.\n+func (c *ChatRPC) OnDisconnected(_ context.Context,\n+\tstatus rpc.DisconnectStatus) {\n+\tif status == rpc.StartingNonFirstConnection {\n+\t\tc.log.Warning(\"Chat is disconnected\")\n+\t\tc.config.KBFSOps().PushConnectionStatusChange(\n+\t\t\tKeybaseServiceName, errDisconnected{})\n+\t}\n+}\n+\n+// ShouldRetry implements the ConnectionHandler interface.\n+func (c *ChatRPC) ShouldRetry(_ string, _ error) bool {\n+\treturn false\n+}\n+\n+// ShouldRetryOnConnect implements the ConnectionHandler interface.\n+func (c *ChatRPC) ShouldRetryOnConnect(err error) bool {\n+\t_, inputCanceled := err.(libkb.InputCanceledError)\n+\treturn !inputCanceled\n+}\n+\n+var _ Chat = (*ChatRPC)(nil)\n+\n+// Chat notes (will remove/rework these once the implementation is complete):\n+//\n+// When sending:\n+//   * chat1.NewConversationLocal\n+//   * chat1.PostTestNonblock\n+//     * ClientPrev can be 0.  Can outbox ID be nil?\n+\n+// Gathering recent notifications:\n+//   * chat1.GetInboxAndUnboxLocal (pagination not needed)\n+//     * But we'd need inbox grouping to get this exactly right.\n+\n+// Reading each conversation:\n+//   * Get list of all channels/writers in the conversation\n+//     * chat1.GetTLFConversationsLocal can give us the list of channels,\n+//       which corresponds to the set of users who have actually written.\n+//       (There might be a lot of team members who haven't written, so\n+//       probably best to avoid iterating through everyone.).\n+//     * Always look up your own channel though, so the GUI can show your\n+//       own last edits if desired.\n+//   * Read each channel until getting N updates for each writer\n+//     * chat1.GetThreadLocal with pagination\n+//     * No prev filled in on next pagination to go backward\n+//   * How to reconcile renames, etc across channels?\n+//     * It's hard to know if a long-ago writer updated a file, and\n+//       later it was renamed by a prolific writer who made N more updates\n+//       afterward.\n+//     * For performance reasons, we probably just need to show the old\n+//       update under the old file name.  Should be rare enough that\n+//       it doesn't matter.\n+\n+// Getting real-time updates:\n+//   * New kbfs-edits activity push notifications on notify-router\n+//   * Mike will make ticket to auto-join non-chat channels,\n+//     so they show up in `GetInboxAndUnboxLocal`.\n+//   * Spot-edit the local edit history on each new push notification.\n+\n+// One layer over the service RPC connection that takes all needed\n+// arguments (including topic type, etc), and passes it pretty\n+// directly to the RPC.\n+\n+// Another, per-TLF layer to remember the resolved conversation ID and\n+// send/read kbfs-edits messages.  It should also interface with the\n+// local journal to show the unflushed journal data as part of the\n+// updates.\n+\n+// Finally an inbox layer that can read the server inbox, and also\n+// checks the journal status, to return the top set of conversations\n+// at any given time.  Maybe it also subscribes to inbox notifications\n+// of some kind.\n+\n+func membersTypeFromTlfType(tlfType tlf.Type) chat1.ConversationMembersType {\n+\tif tlfType == tlf.SingleTeam {\n+\t\treturn chat1.ConversationMembersType_TEAM\n+\t}\n+\treturn chat1.ConversationMembersType_IMPTEAMNATIVE\n+}\n+\n+// GetConversationID implements the Chat interface.\n+func (c *ChatRPC) GetConversationID(\n+\tctx context.Context, tlfName tlf.CanonicalName, tlfType tlf.Type,\n+\tchannelName string, chatType chat1.TopicType) (\n+\tchat1.ConversationID, error) {\n+\t// Try creating the conversation to get back the ID -- it's a\n+\t// no-op if the conversation already exists.\n+\tvis := keybase1.TLFVisibility_PRIVATE\n+\tif tlfType == tlf.Public {\n+\t\tvis = keybase1.TLFVisibility_PUBLIC\n+\t}\n+\n+\targ := chat1.NewConversationLocalArg{\n+\t\tTlfName:          string(tlfName),\n+\t\tTopicType:        chatType,\n+\t\tTlfVisibility:    vis,\n+\t\tMembersType:      membersTypeFromTlfType(tlfType),\n+\t\tIdentifyBehavior: keybase1.TLFIdentifyBehavior_CHAT_CLI,\n+\t}\n+\tres, err := c.client.NewConversationLocal(ctx, arg)","path":"libkbfs/chat_rpc.go","position":169,"original_position":169,"commit_id":"5e6c07b304dfb88255c37d07d03a6a6e3b540d40","original_commit_id":"5e6c07b304dfb88255c37d07d03a6a6e3b540d40","user":{"login":"songgao","id":255797,"node_id":"MDQ6VXNlcjI1NTc5Nw==","avatar_url":"https://avatars3.githubusercontent.com/u/255797?v=4","gravatar_id":"","url":"https://api.github.com/users/songgao","html_url":"https://github.com/songgao","followers_url":"https://api.github.com/users/songgao/followers","following_url":"https://api.github.com/users/songgao/following{/other_user}","gists_url":"https://api.github.com/users/songgao/gists{/gist_id}","starred_url":"https://api.github.com/users/songgao/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/songgao/subscriptions","organizations_url":"https://api.github.com/users/songgao/orgs","repos_url":"https://api.github.com/users/songgao/repos","events_url":"https://api.github.com/users/songgao/events{/privacy}","received_events_url":"https://api.github.com/users/songgao/received_events","type":"User","site_admin":false},"body":"Does this return existing conversation if we already created it before?","created_at":"2018-06-08T00:05:32Z","updated_at":"2018-06-08T00:18:44Z","html_url":"https://github.com/keybase/kbfs/pull/1600#discussion_r193922171","pull_request_url":"https://api.github.com/repos/keybase/kbfs/pulls/1600","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/comments/193922171"},"html":{"href":"https://github.com/keybase/kbfs/pull/1600#discussion_r193922171"},"pull_request":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/1600"}}},"pull_request":{"url":"https://api.github.com/repos/keybase/kbfs/pulls/1600","id":192493782,"node_id":"MDExOlB1bGxSZXF1ZXN0MTkyNDkzNzgy","html_url":"https://github.com/keybase/kbfs/pull/1600","diff_url":"https://github.com/keybase/kbfs/pull/1600.diff","patch_url":"https://github.com/keybase/kbfs/pull/1600.patch","issue_url":"https://api.github.com/repos/keybase/kbfs/issues/1600","number":1600,"state":"open","locked":false,"title":"libkbfs: add a chat interface and an initial RPC implementation","user":{"login":"strib","id":8516691,"node_id":"MDQ6VXNlcjg1MTY2OTE=","avatar_url":"https://avatars0.githubusercontent.com/u/8516691?v=4","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 is untested, but it's also unused.  Plumbing it through will require a bit more work, plus a client<->kbfs commit dance, so I thought we should get this piece reviewed first so the PR doesn't get too unwieldy.\r\n\r\nIssue: KBFS-2993","created_at":"2018-06-04T18:41:14Z","updated_at":"2018-06-08T00:18:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e703d8ae5092cb813c92f22e3fc71e1947fee0eb","assignee":null,"assignees":[],"requested_reviewers":[{"login":"jzila","id":59594,"node_id":"MDQ6VXNlcjU5NTk0","avatar_url":"https://avatars1.githubusercontent.com/u/59594?v=4","gravatar_id":"","url":"https://api.github.com/users/jzila","html_url":"https://github.com/jzila","followers_url":"https://api.github.com/users/jzila/followers","following_url":"https://api.github.com/users/jzila/following{/other_user}","gists_url":"https://api.github.com/users/jzila/gists{/gist_id}","starred_url":"https://api.github.com/users/jzila/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jzila/subscriptions","organizations_url":"https://api.github.com/users/jzila/orgs","repos_url":"https://api.github.com/users/jzila/repos","events_url":"https://api.github.com/users/jzila/events{/privacy}","received_events_url":"https://api.github.com/users/jzila/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/keybase/kbfs/pulls/1600/commits","review_comments_url":"https://api.github.com/repos/keybase/kbfs/pulls/1600/comments","review_comment_url":"https://api.github.com/repos/keybase/kbfs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/keybase/kbfs/issues/1600/comments","statuses_url":"https://api.github.com/repos/keybase/kbfs/statuses/5e6c07b304dfb88255c37d07d03a6a6e3b540d40","head":{"label":"keybase:strib/KBFS-2993-chat-interface","ref":"strib/KBFS-2993-chat-interface","sha":"5e6c07b304dfb88255c37d07d03a6a6e3b540d40","user":{"login":"keybase","id":5400834,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU0MDA4MzQ=","avatar_url":"https://avatars2.githubusercontent.com/u/5400834?v=4","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,"node_id":"MDEwOlJlcG9zaXRvcnk1OTc4NzYwNQ==","name":"kbfs","full_name":"keybase/kbfs","owner":{"login":"keybase","id":5400834,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU0MDA4MzQ=","avatar_url":"https://avatars2.githubusercontent.com/u/5400834?v=4","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":"2018-06-07T18:35:21Z","pushed_at":"2018-06-07T23:59:47Z","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":50133,"stargazers_count":976,"watchers_count":976,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":90,"mirror_url":null,"archived":false,"open_issues_count":57,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause","node_id":"MDc6TGljZW5zZTU="},"forks":90,"open_issues":57,"watchers":976,"default_branch":"master"}},"base":{"label":"keybase:master","ref":"master","sha":"b6f51542213203d97829810a254c4b4ac6a78bcc","user":{"login":"keybase","id":5400834,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU0MDA4MzQ=","avatar_url":"https://avatars2.githubusercontent.com/u/5400834?v=4","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,"node_id":"MDEwOlJlcG9zaXRvcnk1OTc4NzYwNQ==","name":"kbfs","full_name":"keybase/kbfs","owner":{"login":"keybase","id":5400834,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU0MDA4MzQ=","avatar_url":"https://avatars2.githubusercontent.com/u/5400834?v=4","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":"2018-06-07T18:35:21Z","pushed_at":"2018-06-07T23:59:47Z","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":50133,"stargazers_count":976,"watchers_count":976,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":90,"mirror_url":null,"archived":false,"open_issues_count":57,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause","node_id":"MDc6TGljZW5zZTU="},"forks":90,"open_issues":57,"watchers":976,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/1600"},"html":{"href":"https://github.com/keybase/kbfs/pull/1600"},"issue":{"href":"https://api.github.com/repos/keybase/kbfs/issues/1600"},"comments":{"href":"https://api.github.com/repos/keybase/kbfs/issues/1600/comments"},"review_comments":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/1600/comments"},"review_comment":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/keybase/kbfs/pulls/1600/commits"},"statuses":{"href":"https://api.github.com/repos/keybase/kbfs/statuses/5e6c07b304dfb88255c37d07d03a6a6e3b540d40"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"songgao"}}