{"action":"created","comment":{"url":"https://api.github.com/repos/Originate/exosphere/pulls/comments/124934721","pull_request_review_id":47275966,"id":124934721,"diff_hunk":"@@ -0,0 +1,749 @@\n+/*\n+ *\n+ * Copyright 2016, Google Inc.\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are\n+ * met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ * notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above\n+ * copyright notice, this list of conditions and the following disclaimer\n+ * in the documentation and/or other materials provided with the\n+ * distribution.\n+ *     * Neither the name of Google Inc. nor the names of its\n+ * contributors may be used to endorse or promote products derived from\n+ * this software without specific prior written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ *\n+ */\n+\n+package grpc\n+\n+import (\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"math/rand\"\n+\t\"net\"\n+\t\"sync\"\n+\t\"time\"\n+\n+\t\"golang.org/x/net/context\"\n+\t\"google.golang.org/grpc/codes\"\n+\tlbpb \"google.golang.org/grpc/grpclb/grpc_lb_v1\"\n+\t\"google.golang.org/grpc/grpclog\"\n+\t\"google.golang.org/grpc/metadata\"\n+\t\"google.golang.org/grpc/naming\"\n+)\n+\n+// Client API for LoadBalancer service.\n+// Mostly copied from generated pb.go file.\n+// To avoid circular dependency.\n+type loadBalancerClient struct {\n+\tcc *ClientConn\n+}\n+\n+func (c *loadBalancerClient) BalanceLoad(ctx context.Context, opts ...CallOption) (*balanceLoadClientStream, error) {\n+\tdesc := &StreamDesc{\n+\t\tStreamName:    \"BalanceLoad\",\n+\t\tServerStreams: true,\n+\t\tClientStreams: true,\n+\t}\n+\tstream, err := NewClientStream(ctx, desc, c.cc, \"/grpc.lb.v1.LoadBalancer/BalanceLoad\", opts...)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tx := &balanceLoadClientStream{stream}\n+\treturn x, nil\n+}\n+\n+type balanceLoadClientStream struct {\n+\tClientStream\n+}\n+\n+func (x *balanceLoadClientStream) Send(m *lbpb.LoadBalanceRequest) error {\n+\treturn x.ClientStream.SendMsg(m)\n+}\n+\n+func (x *balanceLoadClientStream) Recv() (*lbpb.LoadBalanceResponse, error) {\n+\tm := new(lbpb.LoadBalanceResponse)\n+\tif err := x.ClientStream.RecvMsg(m); err != nil {\n+\t\treturn nil, err\n+\t}\n+\treturn m, nil\n+}\n+\n+// AddressType indicates the address type returned by name resolution.\n+type AddressType uint8\n+\n+const (\n+\t// Backend indicates the server is a backend server.\n+\tBackend AddressType = iota\n+\t// GRPCLB indicates the server is a grpclb load balancer.\n+\tGRPCLB\n+)\n+\n+// AddrMetadataGRPCLB contains the information the name resolution for grpclb should provide. The\n+// name resolver used by grpclb balancer is required to provide this type of metadata in\n+// its address updates.\n+type AddrMetadataGRPCLB struct {\n+\t// AddrType is the type of server (grpc load balancer or backend).\n+\tAddrType AddressType\n+\t// ServerName is the name of the grpc load balancer. Used for authentication.\n+\tServerName string\n+}\n+\n+// NewGRPCLBBalancer creates a grpclb load balancer.\n+func NewGRPCLBBalancer(r naming.Resolver) Balancer {\n+\treturn &balancer{\n+\t\tr: r,\n+\t}\n+}\n+\n+type remoteBalancerInfo struct {\n+\taddr string\n+\t// the server name used for authentication with the remote LB server.\n+\tname string\n+}\n+\n+// grpclbAddrInfo consists of the information of a backend server.\n+type grpclbAddrInfo struct {\n+\taddr      Address\n+\tconnected bool\n+\t// dropForRateLimiting indicates whether this particular request should be\n+\t// dropped by the client for rate limiting.\n+\tdropForRateLimiting bool\n+\t// dropForLoadBalancing indicates whether this particular request should be\n+\t// dropped by the client for load balancing.\n+\tdropForLoadBalancing bool\n+}\n+\n+type balancer struct {\n+\tr        naming.Resolver\n+\ttarget   string\n+\tmu       sync.Mutex\n+\tseq      int // a sequence number to make sure addrCh does not get stale addresses.\n+\tw        naming.Watcher\n+\taddrCh   chan []Address\n+\trbs      []remoteBalancerInfo\n+\taddrs    []*grpclbAddrInfo\n+\tnext     int\n+\twaitCh   chan struct{}\n+\tdone     bool\n+\texpTimer *time.Timer\n+\trand     *rand.Rand\n+\n+\tclientStats lbpb.ClientStats\n+}\n+\n+func (b *balancer) watchAddrUpdates(w naming.Watcher, ch chan []remoteBalancerInfo) error {\n+\tupdates, err := w.Next()\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tb.mu.Lock()\n+\tdefer b.mu.Unlock()\n+\tif b.done {\n+\t\treturn ErrClientConnClosing\n+\t}\n+\tfor _, update := range updates {\n+\t\tswitch update.Op {\n+\t\tcase naming.Add:\n+\t\t\tvar exist bool\n+\t\t\tfor _, v := range b.rbs {\n+\t\t\t\t// TODO: Is the same addr with different server name a different balancer?\n+\t\t\t\tif update.Addr == v.addr {\n+\t\t\t\t\texist = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif exist {\n+\t\t\t\tcontinue\n+\t\t\t}\n+\t\t\tmd, ok := update.Metadata.(*AddrMetadataGRPCLB)\n+\t\t\tif !ok {\n+\t\t\t\t// TODO: Revisit the handling here and may introduce some fallback mechanism.\n+\t\t\t\tgrpclog.Printf(\"The name resolution contains unexpected metadata %v\", update.Metadata)\n+\t\t\t\tcontinue\n+\t\t\t}\n+\t\t\tswitch md.AddrType {\n+\t\t\tcase Backend:\n+\t\t\t\t// TODO: Revisit the handling here and may introduce some fallback mechanism.\n+\t\t\t\tgrpclog.Printf(\"The name resolution does not give grpclb addresses\")\n+\t\t\t\tcontinue\n+\t\t\tcase GRPCLB:\n+\t\t\t\tb.rbs = append(b.rbs, remoteBalancerInfo{\n+\t\t\t\t\taddr: update.Addr,\n+\t\t\t\t\tname: md.ServerName,\n+\t\t\t\t})\n+\t\t\tdefault:\n+\t\t\t\tgrpclog.Printf(\"Received unknow address type %d\", md.AddrType)\n+\t\t\t\tcontinue\n+\t\t\t}\n+\t\tcase naming.Delete:\n+\t\t\tfor i, v := range b.rbs {\n+\t\t\t\tif update.Addr == v.addr {\n+\t\t\t\t\tcopy(b.rbs[i:], b.rbs[i+1:])\n+\t\t\t\t\tb.rbs = b.rbs[:len(b.rbs)-1]\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\tdefault:\n+\t\t\tgrpclog.Println(\"Unknown update.Op \", update.Op)\n+\t\t}\n+\t}\n+\t// TODO: Fall back to the basic round-robin load balancing if the resulting address is\n+\t// not a load balancer.\n+\tselect {\n+\tcase <-ch:\n+\tdefault:\n+\t}\n+\tch <- b.rbs\n+\treturn nil\n+}\n+\n+func (b *balancer) serverListExpire(seq int) {\n+\tb.mu.Lock()\n+\tdefer b.mu.Unlock()\n+\t// TODO: gRPC interanls do not clear the connections when the server list is stale.\n+\t// This means RPCs will keep using the existing server list until b receives new\n+\t// server list even though the list is expired. Revisit this behavior later.\n+\tif b.done || seq < b.seq {\n+\t\treturn\n+\t}\n+\tb.next = 0\n+\tb.addrs = nil\n+\t// Ask grpc internals to close all the corresponding connections.\n+\tb.addrCh <- nil\n+}\n+\n+func convertDuration(d *lbpb.Duration) time.Duration {\n+\tif d == nil {\n+\t\treturn 0\n+\t}\n+\treturn time.Duration(d.Seconds)*time.Second + time.Duration(d.Nanos)*time.Nanosecond\n+}\n+\n+func (b *balancer) processServerList(l *lbpb.ServerList, seq int) {\n+\tif l == nil {\n+\t\treturn\n+\t}\n+\tservers := l.GetServers()\n+\texpiration := convertDuration(l.GetExpirationInterval())\n+\tvar (\n+\t\tsl    []*grpclbAddrInfo\n+\t\taddrs []Address\n+\t)\n+\tfor _, s := range servers {\n+\t\tmd := metadata.Pairs(\"lb-token\", s.LoadBalanceToken)\n+\t\taddr := Address{\n+\t\t\tAddr:     fmt.Sprintf(\"%s:%d\", net.IP(s.IpAddress), s.Port),\n+\t\t\tMetadata: &md,\n+\t\t}\n+\t\tsl = append(sl, &grpclbAddrInfo{\n+\t\t\taddr:                 addr,\n+\t\t\tdropForRateLimiting:  s.DropForRateLimiting,\n+\t\t\tdropForLoadBalancing: s.DropForLoadBalancing,\n+\t\t})\n+\t\taddrs = append(addrs, addr)\n+\t}\n+\tb.mu.Lock()\n+\tdefer b.mu.Unlock()\n+\tif b.done || seq < b.seq {\n+\t\treturn\n+\t}\n+\tif len(sl) > 0 {\n+\t\t// reset b.next to 0 when replacing the server list.\n+\t\tb.next = 0\n+\t\tb.addrs = sl\n+\t\tb.addrCh <- addrs\n+\t\tif b.expTimer != nil {\n+\t\t\tb.expTimer.Stop()\n+\t\t\tb.expTimer = nil\n+\t\t}\n+\t\tif expiration > 0 {\n+\t\t\tb.expTimer = time.AfterFunc(expiration, func() {\n+\t\t\t\tb.serverListExpire(seq)\n+\t\t\t})\n+\t\t}\n+\t}\n+\treturn\n+}\n+\n+func (b *balancer) sendLoadReport(s *balanceLoadClientStream, interval time.Duration, done <-chan struct{}) {\n+\tticker := time.NewTicker(interval)\n+\tdefer ticker.Stop()\n+\tfor {\n+\t\tselect {\n+\t\tcase <-ticker.C:\n+\t\tcase <-done:\n+\t\t\treturn\n+\t\t}\n+\t\tb.mu.Lock()\n+\t\tstats := b.clientStats\n+\t\tb.clientStats = lbpb.ClientStats{} // Clear the stats.\n+\t\tb.mu.Unlock()\n+\t\tt := time.Now()\n+\t\tstats.Timestamp = &lbpb.Timestamp{\n+\t\t\tSeconds: t.Unix(),\n+\t\t\tNanos:   int32(t.Nanosecond()),\n+\t\t}\n+\t\tif err := s.Send(&lbpb.LoadBalanceRequest{\n+\t\t\tLoadBalanceRequestType: &lbpb.LoadBalanceRequest_ClientStats{\n+\t\t\t\tClientStats: &stats,\n+\t\t\t},\n+\t\t}); err != nil {\n+\t\t\treturn\n+\t\t}\n+\t}\n+}\n+\n+func (b *balancer) callRemoteBalancer(lbc *loadBalancerClient, seq int) (retry bool) {\n+\tctx, cancel := context.WithCancel(context.Background())\n+\tdefer cancel()\n+\tstream, err := lbc.BalanceLoad(ctx)\n+\tif err != nil {\n+\t\tgrpclog.Printf(\"Failed to perform RPC to the remote balancer %v\", err)\n+\t\treturn\n+\t}\n+\tb.mu.Lock()\n+\tif b.done {\n+\t\tb.mu.Unlock()\n+\t\treturn\n+\t}\n+\tb.mu.Unlock()\n+\tinitReq := &lbpb.LoadBalanceRequest{\n+\t\tLoadBalanceRequestType: &lbpb.LoadBalanceRequest_InitialRequest{\n+\t\t\tInitialRequest: &lbpb.InitialLoadBalanceRequest{\n+\t\t\t\tName: b.target,\n+\t\t\t},\n+\t\t},\n+\t}\n+\tif err := stream.Send(initReq); err != nil {\n+\t\t// TODO: backoff on retry?\n+\t\treturn true\n+\t}\n+\treply, err := stream.Recv()\n+\tif err != nil {\n+\t\t// TODO: backoff on retry?","path":"vendor/github.com/moby/moby/vendor/google.golang.org/grpc/grpclb.go","position":341,"original_position":341,"commit_id":"d3a939ccc3d1770389cdc60bf01df9794a367966","original_commit_id":"d3a939ccc3d1770389cdc60bf01df9794a367966","user":{"login":"tododrop-bot","id":18539233,"avatar_url":"https://avatars0.githubusercontent.com/u/18539233?v=3","gravatar_id":"","url":"https://api.github.com/users/tododrop-bot","html_url":"https://github.com/tododrop-bot","followers_url":"https://api.github.com/users/tododrop-bot/followers","following_url":"https://api.github.com/users/tododrop-bot/following{/other_user}","gists_url":"https://api.github.com/users/tododrop-bot/gists{/gist_id}","starred_url":"https://api.github.com/users/tododrop-bot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tododrop-bot/subscriptions","organizations_url":"https://api.github.com/users/tododrop-bot/orgs","repos_url":"https://api.github.com/users/tododrop-bot/repos","events_url":"https://api.github.com/users/tododrop-bot/events{/privacy}","received_events_url":"https://api.github.com/users/tododrop-bot/received_events","type":"User","site_admin":false},"body":"[![Fix](http://tododrop.com/todo/220/fix/image?token=%242a%2410%24NGTdKtK0Uodaq0xdKmpHo.AhltROkZh2X.y5kBCHOy%2FU80cGwgmmq)](http://tododrop.com/todo/220/fix) [![Issue](http://tododrop.com/todo/220/issue/image?token=%242a%2410%24NGTdKtK0Uodaq0xdKmpHo.AhltROkZh2X.y5kBCHOy%2FU80cGwgmmq)](http://tododrop.com/todo/220/issue) [![Ignore](http://tododrop.com/todo/220/ignore/image?token=%242a%2410%24NGTdKtK0Uodaq0xdKmpHo.AhltROkZh2X.y5kBCHOy%2FU80cGwgmmq)](http://tododrop.com/todo/220/ignore)","created_at":"2017-06-29T23:22:30Z","updated_at":"2017-06-29T23:22:30Z","html_url":"https://github.com/Originate/exosphere/pull/303#discussion_r124934721","pull_request_url":"https://api.github.com/repos/Originate/exosphere/pulls/303","_links":{"self":{"href":"https://api.github.com/repos/Originate/exosphere/pulls/comments/124934721"},"html":{"href":"https://github.com/Originate/exosphere/pull/303#discussion_r124934721"},"pull_request":{"href":"https://api.github.com/repos/Originate/exosphere/pulls/303"}}},"pull_request":{"url":"https://api.github.com/repos/Originate/exosphere/pulls/303","id":127996390,"html_url":"https://github.com/Originate/exosphere/pull/303","diff_url":"https://github.com/Originate/exosphere/pull/303.diff","patch_url":"https://github.com/Originate/exosphere/pull/303.patch","issue_url":"https://api.github.com/repos/Originate/exosphere/issues/303","number":303,"state":"open","locked":false,"title":"Mc add go project structure","user":{"login":"mcharawi","id":5560805,"avatar_url":"https://avatars3.githubusercontent.com/u/5560805?v=3","gravatar_id":"","url":"https://api.github.com/users/mcharawi","html_url":"https://github.com/mcharawi","followers_url":"https://api.github.com/users/mcharawi/followers","following_url":"https://api.github.com/users/mcharawi/following{/other_user}","gists_url":"https://api.github.com/users/mcharawi/gists{/gist_id}","starred_url":"https://api.github.com/users/mcharawi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mcharawi/subscriptions","organizations_url":"https://api.github.com/users/mcharawi/orgs","repos_url":"https://api.github.com/users/mcharawi/repos","events_url":"https://api.github.com/users/mcharawi/events{/privacy}","received_events_url":"https://api.github.com/users/mcharawi/received_events","type":"User","site_admin":false},"body":"\r\n","created_at":"2017-06-28T19:03:42Z","updated_at":"2017-06-29T23:22:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":"468c51b1289c1eb3702f78f9fda035ac44ff0558","assignee":null,"assignees":[],"requested_reviewers":[{"login":"charlierudolph","id":1676758,"avatar_url":"https://avatars1.githubusercontent.com/u/1676758?v=3","gravatar_id":"","url":"https://api.github.com/users/charlierudolph","html_url":"https://github.com/charlierudolph","followers_url":"https://api.github.com/users/charlierudolph/followers","following_url":"https://api.github.com/users/charlierudolph/following{/other_user}","gists_url":"https://api.github.com/users/charlierudolph/gists{/gist_id}","starred_url":"https://api.github.com/users/charlierudolph/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/charlierudolph/subscriptions","organizations_url":"https://api.github.com/users/charlierudolph/orgs","repos_url":"https://api.github.com/users/charlierudolph/repos","events_url":"https://api.github.com/users/charlierudolph/events{/privacy}","received_events_url":"https://api.github.com/users/charlierudolph/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/Originate/exosphere/pulls/303/commits","review_comments_url":"https://api.github.com/repos/Originate/exosphere/pulls/303/comments","review_comment_url":"https://api.github.com/repos/Originate/exosphere/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Originate/exosphere/issues/303/comments","statuses_url":"https://api.github.com/repos/Originate/exosphere/statuses/d3a939ccc3d1770389cdc60bf01df9794a367966","head":{"label":"Originate:mc-add-go-project-structure","ref":"mc-add-go-project-structure","sha":"d3a939ccc3d1770389cdc60bf01df9794a367966","user":{"login":"Originate","id":1627168,"avatar_url":"https://avatars0.githubusercontent.com/u/1627168?v=3","gravatar_id":"","url":"https://api.github.com/users/Originate","html_url":"https://github.com/Originate","followers_url":"https://api.github.com/users/Originate/followers","following_url":"https://api.github.com/users/Originate/following{/other_user}","gists_url":"https://api.github.com/users/Originate/gists{/gist_id}","starred_url":"https://api.github.com/users/Originate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Originate/subscriptions","organizations_url":"https://api.github.com/users/Originate/orgs","repos_url":"https://api.github.com/users/Originate/repos","events_url":"https://api.github.com/users/Originate/events{/privacy}","received_events_url":"https://api.github.com/users/Originate/received_events","type":"Organization","site_admin":false},"repo":{"id":75137299,"name":"exosphere","full_name":"Originate/exosphere","owner":{"login":"Originate","id":1627168,"avatar_url":"https://avatars0.githubusercontent.com/u/1627168?v=3","gravatar_id":"","url":"https://api.github.com/users/Originate","html_url":"https://github.com/Originate","followers_url":"https://api.github.com/users/Originate/followers","following_url":"https://api.github.com/users/Originate/following{/other_user}","gists_url":"https://api.github.com/users/Originate/gists{/gist_id}","starred_url":"https://api.github.com/users/Originate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Originate/subscriptions","organizations_url":"https://api.github.com/users/Originate/orgs","repos_url":"https://api.github.com/users/Originate/repos","events_url":"https://api.github.com/users/Originate/events{/privacy}","received_events_url":"https://api.github.com/users/Originate/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Originate/exosphere","description":"A modern cloud-based micro-service framework","fork":false,"url":"https://api.github.com/repos/Originate/exosphere","forks_url":"https://api.github.com/repos/Originate/exosphere/forks","keys_url":"https://api.github.com/repos/Originate/exosphere/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Originate/exosphere/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Originate/exosphere/teams","hooks_url":"https://api.github.com/repos/Originate/exosphere/hooks","issue_events_url":"https://api.github.com/repos/Originate/exosphere/issues/events{/number}","events_url":"https://api.github.com/repos/Originate/exosphere/events","assignees_url":"https://api.github.com/repos/Originate/exosphere/assignees{/user}","branches_url":"https://api.github.com/repos/Originate/exosphere/branches{/branch}","tags_url":"https://api.github.com/repos/Originate/exosphere/tags","blobs_url":"https://api.github.com/repos/Originate/exosphere/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Originate/exosphere/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Originate/exosphere/git/refs{/sha}","trees_url":"https://api.github.com/repos/Originate/exosphere/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Originate/exosphere/statuses/{sha}","languages_url":"https://api.github.com/repos/Originate/exosphere/languages","stargazers_url":"https://api.github.com/repos/Originate/exosphere/stargazers","contributors_url":"https://api.github.com/repos/Originate/exosphere/contributors","subscribers_url":"https://api.github.com/repos/Originate/exosphere/subscribers","subscription_url":"https://api.github.com/repos/Originate/exosphere/subscription","commits_url":"https://api.github.com/repos/Originate/exosphere/commits{/sha}","git_commits_url":"https://api.github.com/repos/Originate/exosphere/git/commits{/sha}","comments_url":"https://api.github.com/repos/Originate/exosphere/comments{/number}","issue_comment_url":"https://api.github.com/repos/Originate/exosphere/issues/comments{/number}","contents_url":"https://api.github.com/repos/Originate/exosphere/contents/{+path}","compare_url":"https://api.github.com/repos/Originate/exosphere/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Originate/exosphere/merges","archive_url":"https://api.github.com/repos/Originate/exosphere/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Originate/exosphere/downloads","issues_url":"https://api.github.com/repos/Originate/exosphere/issues{/number}","pulls_url":"https://api.github.com/repos/Originate/exosphere/pulls{/number}","milestones_url":"https://api.github.com/repos/Originate/exosphere/milestones{/number}","notifications_url":"https://api.github.com/repos/Originate/exosphere/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Originate/exosphere/labels{/name}","releases_url":"https://api.github.com/repos/Originate/exosphere/releases{/id}","deployments_url":"https://api.github.com/repos/Originate/exosphere/deployments","created_at":"2016-11-30T01:09:58Z","updated_at":"2017-06-02T04:07:19Z","pushed_at":"2017-06-29T23:22:18Z","git_url":"git://github.com/Originate/exosphere.git","ssh_url":"git@github.com:Originate/exosphere.git","clone_url":"https://github.com/Originate/exosphere.git","svn_url":"https://github.com/Originate/exosphere","homepage":null,"size":30576,"stargazers_count":5,"watchers_count":5,"language":"LiveScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":4,"forks":3,"open_issues":4,"watchers":5,"default_branch":"master"}},"base":{"label":"Originate:master","ref":"master","sha":"b2ecf5a5e03a79f4c597362b2373b42d1e9ed737","user":{"login":"Originate","id":1627168,"avatar_url":"https://avatars0.githubusercontent.com/u/1627168?v=3","gravatar_id":"","url":"https://api.github.com/users/Originate","html_url":"https://github.com/Originate","followers_url":"https://api.github.com/users/Originate/followers","following_url":"https://api.github.com/users/Originate/following{/other_user}","gists_url":"https://api.github.com/users/Originate/gists{/gist_id}","starred_url":"https://api.github.com/users/Originate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Originate/subscriptions","organizations_url":"https://api.github.com/users/Originate/orgs","repos_url":"https://api.github.com/users/Originate/repos","events_url":"https://api.github.com/users/Originate/events{/privacy}","received_events_url":"https://api.github.com/users/Originate/received_events","type":"Organization","site_admin":false},"repo":{"id":75137299,"name":"exosphere","full_name":"Originate/exosphere","owner":{"login":"Originate","id":1627168,"avatar_url":"https://avatars0.githubusercontent.com/u/1627168?v=3","gravatar_id":"","url":"https://api.github.com/users/Originate","html_url":"https://github.com/Originate","followers_url":"https://api.github.com/users/Originate/followers","following_url":"https://api.github.com/users/Originate/following{/other_user}","gists_url":"https://api.github.com/users/Originate/gists{/gist_id}","starred_url":"https://api.github.com/users/Originate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Originate/subscriptions","organizations_url":"https://api.github.com/users/Originate/orgs","repos_url":"https://api.github.com/users/Originate/repos","events_url":"https://api.github.com/users/Originate/events{/privacy}","received_events_url":"https://api.github.com/users/Originate/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Originate/exosphere","description":"A modern cloud-based micro-service framework","fork":false,"url":"https://api.github.com/repos/Originate/exosphere","forks_url":"https://api.github.com/repos/Originate/exosphere/forks","keys_url":"https://api.github.com/repos/Originate/exosphere/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Originate/exosphere/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Originate/exosphere/teams","hooks_url":"https://api.github.com/repos/Originate/exosphere/hooks","issue_events_url":"https://api.github.com/repos/Originate/exosphere/issues/events{/number}","events_url":"https://api.github.com/repos/Originate/exosphere/events","assignees_url":"https://api.github.com/repos/Originate/exosphere/assignees{/user}","branches_url":"https://api.github.com/repos/Originate/exosphere/branches{/branch}","tags_url":"https://api.github.com/repos/Originate/exosphere/tags","blobs_url":"https://api.github.com/repos/Originate/exosphere/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Originate/exosphere/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Originate/exosphere/git/refs{/sha}","trees_url":"https://api.github.com/repos/Originate/exosphere/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Originate/exosphere/statuses/{sha}","languages_url":"https://api.github.com/repos/Originate/exosphere/languages","stargazers_url":"https://api.github.com/repos/Originate/exosphere/stargazers","contributors_url":"https://api.github.com/repos/Originate/exosphere/contributors","subscribers_url":"https://api.github.com/repos/Originate/exosphere/subscribers","subscription_url":"https://api.github.com/repos/Originate/exosphere/subscription","commits_url":"https://api.github.com/repos/Originate/exosphere/commits{/sha}","git_commits_url":"https://api.github.com/repos/Originate/exosphere/git/commits{/sha}","comments_url":"https://api.github.com/repos/Originate/exosphere/comments{/number}","issue_comment_url":"https://api.github.com/repos/Originate/exosphere/issues/comments{/number}","contents_url":"https://api.github.com/repos/Originate/exosphere/contents/{+path}","compare_url":"https://api.github.com/repos/Originate/exosphere/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Originate/exosphere/merges","archive_url":"https://api.github.com/repos/Originate/exosphere/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Originate/exosphere/downloads","issues_url":"https://api.github.com/repos/Originate/exosphere/issues{/number}","pulls_url":"https://api.github.com/repos/Originate/exosphere/pulls{/number}","milestones_url":"https://api.github.com/repos/Originate/exosphere/milestones{/number}","notifications_url":"https://api.github.com/repos/Originate/exosphere/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Originate/exosphere/labels{/name}","releases_url":"https://api.github.com/repos/Originate/exosphere/releases{/id}","deployments_url":"https://api.github.com/repos/Originate/exosphere/deployments","created_at":"2016-11-30T01:09:58Z","updated_at":"2017-06-02T04:07:19Z","pushed_at":"2017-06-29T23:22:18Z","git_url":"git://github.com/Originate/exosphere.git","ssh_url":"git@github.com:Originate/exosphere.git","clone_url":"https://github.com/Originate/exosphere.git","svn_url":"https://github.com/Originate/exosphere","homepage":null,"size":30576,"stargazers_count":5,"watchers_count":5,"language":"LiveScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":4,"forks":3,"open_issues":4,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Originate/exosphere/pulls/303"},"html":{"href":"https://github.com/Originate/exosphere/pull/303"},"issue":{"href":"https://api.github.com/repos/Originate/exosphere/issues/303"},"comments":{"href":"https://api.github.com/repos/Originate/exosphere/issues/303/comments"},"review_comments":{"href":"https://api.github.com/repos/Originate/exosphere/pulls/303/comments"},"review_comment":{"href":"https://api.github.com/repos/Originate/exosphere/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Originate/exosphere/pulls/303/commits"},"statuses":{"href":"https://api.github.com/repos/Originate/exosphere/statuses/d3a939ccc3d1770389cdc60bf01df9794a367966"}}}}
{"actor":{"display_login":"tododrop-bot"}}