{"action":"created","comment":{"url":"https://api.github.com/repos/dedis/cothority/pulls/comments/77803915","id":77803915,"diff_hunk":"@@ -0,0 +1,395 @@\n+package network\n+\n+import (\n+\t\"bytes\"\n+\t\"encoding/binary\"\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"net\"\n+\t\"strings\"\n+\t\"sync\"\n+\t\"time\"\n+\n+\t\"github.com/dedis/cothority/log\"\n+)\n+\n+// NewTCPRouter returns a fresh Router using TCPHost as the underlying Host.\n+func NewTCPRouter(sid *ServerIdentity) (*Router, error) {\n+\th, err := NewTCPHost(sid.Address)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\treturn NewRouter(sid, h), nil\n+}\n+\n+// TCPConn is the underlying implementation of\n+// Conn using plain Tcp.\n+type TCPConn struct {\n+\t// The name of the endpoint we are connected to.\n+\tendpoint Address\n+\n+\t// The connection used\n+\tconn net.Conn\n+\n+\t// closed indicator\n+\tclosed    bool\n+\tclosedMut sync.Mutex\n+\t// So we only handle one receiving packet at a time\n+\treceiveMutex sync.Mutex\n+\t// So we only handle one sending packet at a time\n+\tsendMutex sync.Mutex\n+\n+\tcounterSafe\n+}\n+\n+// NewTCPConn will open a TCPConn to the given address.\n+func NewTCPConn(addr Address) (*TCPConn, error) {\n+\tvar err error\n+\tvar conn net.Conn\n+\tnetAddr := addr.NetworkAddress()\n+\tfor i := 0; i < MaxRetryConnect; i++ {\n+\t\tconn, err = net.Dial(\"tcp\", netAddr)\n+\t\tif err != nil {\n+\t\t\ttime.Sleep(WaitRetry)\n+\t\t} else {\n+\t\t\tbreak\n+\t\t}\n+\t\ttime.Sleep(WaitRetry)\n+\t}\n+\tif conn == nil {\n+\t\treturn nil, fmt.Errorf(\"Could not connect to %s: %s\", addr, err)\n+\t}\n+\tc := TCPConn{\n+\t\tendpoint: addr,\n+\t\tconn:     conn,\n+\t}\n+\treturn &c, err\n+}\n+\n+// Receive calls the receive routine to get the bytes from the connection then\n+// it tries to decode the buffer. Returns the Packet with the Msg field decoded\n+// or EmptyApplicationPacket and an error if something wrong occured.\n+func (c *TCPConn) Receive() (nm Packet, e error) {\n+\tdefer func() {\n+\t\tif err := recover(); err != nil {\n+\t\t\te = fmt.Errorf(\"Error Received message: %v\", err)\n+\t\t\tnm = EmptyApplicationPacket\n+\t\t}\n+\t}()\n+\n+\tvar am Packet\n+\tbuff, err := c.receiveRaw()\n+\tif err != nil {\n+\t\treturn EmptyApplicationPacket, err\n+\t}\n+\n+\terr = am.UnmarshalBinary(buff)\n+\tif err != nil {\n+\t\treturn EmptyApplicationPacket, fmt.Errorf(\"Error unmarshaling message type %s: %s\", am.MsgType.String(), err.Error())\n+\t}\n+\tam.From = c.Remote()\n+\treturn am, nil\n+}\n+\n+// receiveRaw is responsible for getting first the size of the message, then the\n+// whole message. It returns the raw message as slice of bytes.\n+func (c *TCPConn) receiveRaw() ([]byte, error) {\n+\tc.receiveMutex.Lock()\n+\tdefer c.receiveMutex.Unlock()\n+\t// First read the size\n+\tvar total Size\n+\tif err := binary.Read(c.conn, globalOrder, &total); err != nil {\n+\t\treturn nil, handleError(err)\n+\t}\n+\tb := make([]byte, total)\n+\tvar read Size\n+\tvar buffer bytes.Buffer\n+\tfor read < total {\n+\t\t// read the size of the next packet\n+\t\tn, err := c.conn.Read(b)\n+\t\t// if error then quit\n+\t\tif err != nil {\n+\n+\t\t\treturn nil, handleError(err)\n+\t\t}\n+\t\t// put it in the longterm buffer\n+\t\tif _, err := buffer.Write(b[:n]); err != nil {\n+\t\t\tlog.Error(\"Couldn't write to buffer:\", err)\n+\t\t}\n+\t\tread += Size(n)\n+\t\tb = b[n:]\n+\t}\n+\n+\t// set the size read\n+\tc.updateRx(uint64(read))\n+\treturn buffer.Bytes(), nil\n+}\n+\n+// Send will convert the NetworkMessage into an ApplicationMessage\n+// and send it with send()\n+// Returns an error if anything was wrong\n+func (c *TCPConn) Send(obj Body) error {\n+\tc.sendMutex.Lock()\n+\tdefer c.sendMutex.Unlock()\n+\tam, err := NewNetworkPacket(obj)\n+\tif err != nil {\n+\t\treturn fmt.Errorf(\"Error converting packet: %v\\n\", err)\n+\t}\n+\tlog.Lvlf5(\"Message SEND => %+v\", am)\n+\tvar b []byte\n+\tb, err = am.MarshalBinary()\n+\tif err != nil {\n+\t\treturn fmt.Errorf(\"Error marshaling  message: %s\", err.Error())\n+\t}\n+\treturn c.sendRaw(b)\n+}\n+\n+// sendRaw takes care of sending this slice of bytes FULLY to the connection\n+func (c *TCPConn) sendRaw(b []byte) error {\n+\t// First write the size\n+\tpacketSize := Size(len(b))\n+\tif err := binary.Write(c.conn, globalOrder, packetSize); err != nil {\n+\t\treturn err\n+\t}\n+\t// Then send everything through the connection\n+\t// Send chunk by chunk\n+\tlog.Lvl5(\"Sending from\", c.conn.LocalAddr(), \"to\", c.conn.RemoteAddr())\n+\tvar sent Size\n+\tfor sent < packetSize {\n+\t\tn, err := c.conn.Write(b[sent:])\n+\t\tif err != nil {\n+\t\t\treturn handleError(err)\n+\t\t}\n+\t\tsent += Size(n)\n+\t}\n+\t// update stats on the connection\n+\tc.updateTx(uint64(packetSize))\n+\treturn nil\n+}\n+\n+// Remote returns the name of the peer at the end point of\n+// the connection\n+func (c *TCPConn) Remote() Address {\n+\treturn c.endpoint\n+}\n+\n+// Local returns the local address and port\n+func (c *TCPConn) Local() Address {\n+\treturn NewTCPAddress(c.conn.LocalAddr().String())\n+}\n+\n+// Type implements the Conn interface\n+func (c *TCPConn) Type() ConnType {\n+\treturn PlainTCP\n+}\n+\n+// Close ... closes the connection\n+func (c *TCPConn) Close() error {\n+\tc.closedMut.Lock()\n+\tdefer c.closedMut.Unlock()\n+\tif c.closed == true {\n+\t\treturn ErrClosed\n+\t}\n+\terr := c.conn.Close()\n+\tc.closed = true\n+\tif err != nil {\n+\t\treturn handleError(err)\n+\t}\n+\treturn nil\n+}\n+\n+// handleError produces the higher layer error depending on the type\n+// so user of the package can know what is the cause of the problem\n+func handleError(err error) error {\n+\n+\tif strings.Contains(err.Error(), \"use of closed\") || strings.Contains(err.Error(), \"broken pipe\") {\n+\t\treturn ErrClosed\n+\t} else if strings.Contains(err.Error(), \"canceled\") {\n+\t\treturn ErrCanceled\n+\t} else if err == io.EOF || strings.Contains(err.Error(), \"EOF\") {\n+\t\treturn ErrEOF\n+\t}\n+\n+\tnetErr, ok := err.(net.Error)\n+\tif !ok {\n+\t\treturn ErrUnknown\n+\t}\n+\tif netErr.Temporary() {\n+\t\treturn ErrTemp\n+\t} else if netErr.Timeout() {\n+\t\treturn ErrTimeout\n+\t}\n+\treturn ErrUnknown\n+}\n+\n+// TCPListener is the underlying implementation of\n+// Host using Tcp as a communication channel\n+type TCPListener struct {\n+\t// the underlying golang/net listener\n+\tlistener net.Listener\n+\t// the close channel used to indicate to the listener we want to quit\n+\tquit chan bool\n+\t// quitListener is a channel to indicate to the closing function that the\n+\t// listener has actually really quit\n+\tquitListener  chan bool\n+\tlisteningLock sync.Mutex\n+\tlistening     bool\n+\n+\t// closed is used to tell the listen routine to return immediatly if a\n+\t// Stop() have been made (concurrency into place here)\n+\tclosed bool\n+\n+\t// listening addr (actual). Useful for listening on :0 port\n+\taddr net.Addr\n+}\n+\n+// NewTCPListener returns a Listener. This function tries to bind to the given\n+// address already.It returns the listener and an error if one occured during\n+// the binding. A subsequent call to Address() will give the real listening\n+// address (useful if you set it to port :0).\n+func NewTCPListener(addr Address) (*TCPListener, error) {\n+\tt := &TCPListener{\n+\t\tquit:         make(chan bool),\n+\t\tquitListener: make(chan bool),\n+\t}\n+\tglobal, _ := GlobalBind(addr.NetworkAddress())\n+\tfor i := 0; i < MaxRetryConnect; i++ {\n+\t\tln, err := net.Listen(\"tcp\", global)\n+\t\tif err == nil {\n+\t\t\tt.listener = ln\n+\t\t\tbreak\n+\t\t} else if i == MaxRetryConnect-1 {\n+\t\t\treturn nil, errors.New(\"Error opening listener: \" + err.Error())\n+\t\t}\n+\t\ttime.Sleep(WaitRetry)\n+\t}\n+\tt.addr = t.listener.Addr()\n+\treturn t, nil\n+}\n+\n+// Listen implements the Listener interface\n+func (t *TCPListener) Listen(fn func(Conn)) error {\n+\treceiver := func(tc *TCPConn) {\n+\t\tgo fn(tc)\n+\t}\n+\treturn t.listen(receiver)\n+}\n+\n+// listen is the private function that takes a function that takes a TCPConn.\n+// That way we can control what to do of the TCPConn before returning it to the\n+// function given by the user. fn is called in the same routine.\n+func (t *TCPListener) listen(fn func(*TCPConn)) error {\n+\tt.listeningLock.Lock()\n+\tif t.closed == true {\n+\t\tt.listeningLock.Unlock()\n+\t\treturn nil\n+\t}\n+\tt.listening = true\n+\tt.listeningLock.Unlock()\n+\tfor {\n+\t\tconn, err := t.listener.Accept()\n+\t\tif err != nil {\n+\t\t\tselect {\n+\t\t\tcase <-t.quit:\n+\t\t\t\tt.quitListener <- true\n+\t\t\t\treturn nil\n+\t\t\tdefault:\n+\t\t\t}\n+\t\t\tcontinue\n+\t\t}\n+\t\tc := TCPConn{\n+\t\t\tendpoint: NewTCPAddress(conn.RemoteAddr().String()),\n+\t\t\tconn:     conn,\n+\t\t}\n+\t\tfn(&c)\n+\t}\n+}\n+\n+// Stop will stop the listener. It is a blocking call.\n+func (t *TCPListener) Stop() error {\n+\t// lets see if we launched a listening routing\n+\tt.listeningLock.Lock()\n+\tdefer t.listeningLock.Unlock()\n+\n+\tclose(t.quit)\n+\n+\tif t.listener != nil {\n+\t\tif err := t.listener.Close(); err != nil {\n+\t\t\tif handleError(err) != ErrClosed {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t}\n+\t}\n+\tvar stop bool\n+\tif t.listening {\n+\t\tfor !stop {\n+\t\t\tselect {\n+\t\t\tcase <-t.quitListener:\n+\t\t\t\tstop = true\n+\t\t\tcase <-time.After(time.Millisecond * 50):\n+\t\t\t\tcontinue\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tt.quit = make(chan bool)\n+\tt.listening = false\n+\tt.closed = true\n+\treturn nil\n+}\n+\n+// Address implements the Listener interface\n+func (t *TCPListener) Address() Address {\n+\tt.listeningLock.Lock()\n+\tdefer t.listeningLock.Unlock()\n+\treturn NewAddress(PlainTCP, t.addr.String())\n+}\n+\n+// Listening implements the Listener interface\n+func (t *TCPListener) Listening() bool {\n+\tt.listeningLock.Lock()\n+\tdefer t.listeningLock.Unlock()\n+\treturn t.listening\n+}\n+\n+// TCPHost implements the Host interface using TCP connections.\n+type TCPHost struct {\n+\taddr Address","path":"network/tcp.go","position":358,"original_position":358,"commit_id":"9409f62e6ca6255295274e323be4a2b987497ac5","original_commit_id":"9409f62e6ca6255295274e323be4a2b987497ac5","user":{"login":"ineiti","id":1545067,"avatar_url":"https://avatars.githubusercontent.com/u/1545067?v=3","gravatar_id":"","url":"https://api.github.com/users/ineiti","html_url":"https://github.com/ineiti","followers_url":"https://api.github.com/users/ineiti/followers","following_url":"https://api.github.com/users/ineiti/following{/other_user}","gists_url":"https://api.github.com/users/ineiti/gists{/gist_id}","starred_url":"https://api.github.com/users/ineiti/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ineiti/subscriptions","organizations_url":"https://api.github.com/users/ineiti/orgs","repos_url":"https://api.github.com/users/ineiti/repos","events_url":"https://api.github.com/users/ineiti/events{/privacy}","received_events_url":"https://api.github.com/users/ineiti/received_events","type":"User","site_admin":false},"body":";) Let it be then.","created_at":"2016-09-07T11:26:21Z","updated_at":"2016-09-07T11:26:21Z","html_url":"https://github.com/dedis/cothority/pull/569#discussion_r77803915","pull_request_url":"https://api.github.com/repos/dedis/cothority/pulls/569","_links":{"self":{"href":"https://api.github.com/repos/dedis/cothority/pulls/comments/77803915"},"html":{"href":"https://github.com/dedis/cothority/pull/569#discussion_r77803915"},"pull_request":{"href":"https://api.github.com/repos/dedis/cothority/pulls/569"}}},"pull_request":{"url":"https://api.github.com/repos/dedis/cothority/pulls/569","id":83769388,"html_url":"https://github.com/dedis/cothority/pull/569","diff_url":"https://github.com/dedis/cothority/pull/569.diff","patch_url":"https://github.com/dedis/cothority/pull/569.patch","issue_url":"https://api.github.com/repos/dedis/cothority/issues/569","number":569,"state":"open","locked":false,"title":"[3/7] Refactor network - TCP layer","user":{"login":"nikkolasg","id":2564747,"avatar_url":"https://avatars.githubusercontent.com/u/2564747?v=3","gravatar_id":"","url":"https://api.github.com/users/nikkolasg","html_url":"https://github.com/nikkolasg","followers_url":"https://api.github.com/users/nikkolasg/followers","following_url":"https://api.github.com/users/nikkolasg/following{/other_user}","gists_url":"https://api.github.com/users/nikkolasg/gists{/gist_id}","starred_url":"https://api.github.com/users/nikkolasg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikkolasg/subscriptions","organizations_url":"https://api.github.com/users/nikkolasg/orgs","repos_url":"https://api.github.com/users/nikkolasg/repos","events_url":"https://api.github.com/users/nikkolasg/events{/privacy}","received_events_url":"https://api.github.com/users/nikkolasg/received_events","type":"User","site_admin":false},"body":"This implements the TCP part of the network package, defining all interfaces in `network.go`. It is like the previous PR but using TCP connections.","created_at":"2016-09-02T09:16:33Z","updated_at":"2016-09-07T11:26:21Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a94f20d88d1de984863cc34b1a240c7446437ba2","assignee":{"login":"nikkolasg","id":2564747,"avatar_url":"https://avatars.githubusercontent.com/u/2564747?v=3","gravatar_id":"","url":"https://api.github.com/users/nikkolasg","html_url":"https://github.com/nikkolasg","followers_url":"https://api.github.com/users/nikkolasg/followers","following_url":"https://api.github.com/users/nikkolasg/following{/other_user}","gists_url":"https://api.github.com/users/nikkolasg/gists{/gist_id}","starred_url":"https://api.github.com/users/nikkolasg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikkolasg/subscriptions","organizations_url":"https://api.github.com/users/nikkolasg/orgs","repos_url":"https://api.github.com/users/nikkolasg/repos","events_url":"https://api.github.com/users/nikkolasg/events{/privacy}","received_events_url":"https://api.github.com/users/nikkolasg/received_events","type":"User","site_admin":false},"assignees":[{"login":"nikkolasg","id":2564747,"avatar_url":"https://avatars.githubusercontent.com/u/2564747?v=3","gravatar_id":"","url":"https://api.github.com/users/nikkolasg","html_url":"https://github.com/nikkolasg","followers_url":"https://api.github.com/users/nikkolasg/followers","following_url":"https://api.github.com/users/nikkolasg/following{/other_user}","gists_url":"https://api.github.com/users/nikkolasg/gists{/gist_id}","starred_url":"https://api.github.com/users/nikkolasg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikkolasg/subscriptions","organizations_url":"https://api.github.com/users/nikkolasg/orgs","repos_url":"https://api.github.com/users/nikkolasg/repos","events_url":"https://api.github.com/users/nikkolasg/events{/privacy}","received_events_url":"https://api.github.com/users/nikkolasg/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/dedis/cothority/pulls/569/commits","review_comments_url":"https://api.github.com/repos/dedis/cothority/pulls/569/comments","review_comment_url":"https://api.github.com/repos/dedis/cothority/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dedis/cothority/issues/569/comments","statuses_url":"https://api.github.com/repos/dedis/cothority/statuses/9409f62e6ca6255295274e323be4a2b987497ac5","head":{"label":"dedis:refactor_network_tcp","ref":"refactor_network_tcp","sha":"9409f62e6ca6255295274e323be4a2b987497ac5","user":{"login":"dedis","id":3638331,"avatar_url":"https://avatars.githubusercontent.com/u/3638331?v=3","gravatar_id":"","url":"https://api.github.com/users/dedis","html_url":"https://github.com/dedis","followers_url":"https://api.github.com/users/dedis/followers","following_url":"https://api.github.com/users/dedis/following{/other_user}","gists_url":"https://api.github.com/users/dedis/gists{/gist_id}","starred_url":"https://api.github.com/users/dedis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dedis/subscriptions","organizations_url":"https://api.github.com/users/dedis/orgs","repos_url":"https://api.github.com/users/dedis/repos","events_url":"https://api.github.com/users/dedis/events{/privacy}","received_events_url":"https://api.github.com/users/dedis/received_events","type":"Organization","site_admin":false},"repo":{"id":41791684,"name":"cothority","full_name":"dedis/cothority","owner":{"login":"dedis","id":3638331,"avatar_url":"https://avatars.githubusercontent.com/u/3638331?v=3","gravatar_id":"","url":"https://api.github.com/users/dedis","html_url":"https://github.com/dedis","followers_url":"https://api.github.com/users/dedis/followers","following_url":"https://api.github.com/users/dedis/following{/other_user}","gists_url":"https://api.github.com/users/dedis/gists{/gist_id}","starred_url":"https://api.github.com/users/dedis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dedis/subscriptions","organizations_url":"https://api.github.com/users/dedis/orgs","repos_url":"https://api.github.com/users/dedis/repos","events_url":"https://api.github.com/users/dedis/events{/privacy}","received_events_url":"https://api.github.com/users/dedis/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dedis/cothority","description":"Scalable collective authority prototype","fork":false,"url":"https://api.github.com/repos/dedis/cothority","forks_url":"https://api.github.com/repos/dedis/cothority/forks","keys_url":"https://api.github.com/repos/dedis/cothority/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dedis/cothority/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dedis/cothority/teams","hooks_url":"https://api.github.com/repos/dedis/cothority/hooks","issue_events_url":"https://api.github.com/repos/dedis/cothority/issues/events{/number}","events_url":"https://api.github.com/repos/dedis/cothority/events","assignees_url":"https://api.github.com/repos/dedis/cothority/assignees{/user}","branches_url":"https://api.github.com/repos/dedis/cothority/branches{/branch}","tags_url":"https://api.github.com/repos/dedis/cothority/tags","blobs_url":"https://api.github.com/repos/dedis/cothority/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dedis/cothority/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dedis/cothority/git/refs{/sha}","trees_url":"https://api.github.com/repos/dedis/cothority/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dedis/cothority/statuses/{sha}","languages_url":"https://api.github.com/repos/dedis/cothority/languages","stargazers_url":"https://api.github.com/repos/dedis/cothority/stargazers","contributors_url":"https://api.github.com/repos/dedis/cothority/contributors","subscribers_url":"https://api.github.com/repos/dedis/cothority/subscribers","subscription_url":"https://api.github.com/repos/dedis/cothority/subscription","commits_url":"https://api.github.com/repos/dedis/cothority/commits{/sha}","git_commits_url":"https://api.github.com/repos/dedis/cothority/git/commits{/sha}","comments_url":"https://api.github.com/repos/dedis/cothority/comments{/number}","issue_comment_url":"https://api.github.com/repos/dedis/cothority/issues/comments{/number}","contents_url":"https://api.github.com/repos/dedis/cothority/contents/{+path}","compare_url":"https://api.github.com/repos/dedis/cothority/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dedis/cothority/merges","archive_url":"https://api.github.com/repos/dedis/cothority/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dedis/cothority/downloads","issues_url":"https://api.github.com/repos/dedis/cothority/issues{/number}","pulls_url":"https://api.github.com/repos/dedis/cothority/pulls{/number}","milestones_url":"https://api.github.com/repos/dedis/cothority/milestones{/number}","notifications_url":"https://api.github.com/repos/dedis/cothority/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dedis/cothority/labels{/name}","releases_url":"https://api.github.com/repos/dedis/cothority/releases{/id}","deployments_url":"https://api.github.com/repos/dedis/cothority/deployments","created_at":"2015-09-02T09:13:57Z","updated_at":"2016-08-29T00:58:40Z","pushed_at":"2016-09-07T09:36:11Z","git_url":"git://github.com/dedis/cothority.git","ssh_url":"git@github.com:dedis/cothority.git","clone_url":"https://github.com/dedis/cothority.git","svn_url":"https://github.com/dedis/cothority","homepage":"","size":70544,"stargazers_count":113,"watchers_count":113,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11,"mirror_url":null,"open_issues_count":102,"forks":11,"open_issues":102,"watchers":113,"default_branch":"master"}},"base":{"label":"dedis:refactor_mocking_local","ref":"refactor_mocking_local","sha":"a3cad4415c9c910fe0e8a8a5358d018f0689e023","user":{"login":"dedis","id":3638331,"avatar_url":"https://avatars.githubusercontent.com/u/3638331?v=3","gravatar_id":"","url":"https://api.github.com/users/dedis","html_url":"https://github.com/dedis","followers_url":"https://api.github.com/users/dedis/followers","following_url":"https://api.github.com/users/dedis/following{/other_user}","gists_url":"https://api.github.com/users/dedis/gists{/gist_id}","starred_url":"https://api.github.com/users/dedis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dedis/subscriptions","organizations_url":"https://api.github.com/users/dedis/orgs","repos_url":"https://api.github.com/users/dedis/repos","events_url":"https://api.github.com/users/dedis/events{/privacy}","received_events_url":"https://api.github.com/users/dedis/received_events","type":"Organization","site_admin":false},"repo":{"id":41791684,"name":"cothority","full_name":"dedis/cothority","owner":{"login":"dedis","id":3638331,"avatar_url":"https://avatars.githubusercontent.com/u/3638331?v=3","gravatar_id":"","url":"https://api.github.com/users/dedis","html_url":"https://github.com/dedis","followers_url":"https://api.github.com/users/dedis/followers","following_url":"https://api.github.com/users/dedis/following{/other_user}","gists_url":"https://api.github.com/users/dedis/gists{/gist_id}","starred_url":"https://api.github.com/users/dedis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dedis/subscriptions","organizations_url":"https://api.github.com/users/dedis/orgs","repos_url":"https://api.github.com/users/dedis/repos","events_url":"https://api.github.com/users/dedis/events{/privacy}","received_events_url":"https://api.github.com/users/dedis/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dedis/cothority","description":"Scalable collective authority prototype","fork":false,"url":"https://api.github.com/repos/dedis/cothority","forks_url":"https://api.github.com/repos/dedis/cothority/forks","keys_url":"https://api.github.com/repos/dedis/cothority/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dedis/cothority/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dedis/cothority/teams","hooks_url":"https://api.github.com/repos/dedis/cothority/hooks","issue_events_url":"https://api.github.com/repos/dedis/cothority/issues/events{/number}","events_url":"https://api.github.com/repos/dedis/cothority/events","assignees_url":"https://api.github.com/repos/dedis/cothority/assignees{/user}","branches_url":"https://api.github.com/repos/dedis/cothority/branches{/branch}","tags_url":"https://api.github.com/repos/dedis/cothority/tags","blobs_url":"https://api.github.com/repos/dedis/cothority/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dedis/cothority/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dedis/cothority/git/refs{/sha}","trees_url":"https://api.github.com/repos/dedis/cothority/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dedis/cothority/statuses/{sha}","languages_url":"https://api.github.com/repos/dedis/cothority/languages","stargazers_url":"https://api.github.com/repos/dedis/cothority/stargazers","contributors_url":"https://api.github.com/repos/dedis/cothority/contributors","subscribers_url":"https://api.github.com/repos/dedis/cothority/subscribers","subscription_url":"https://api.github.com/repos/dedis/cothority/subscription","commits_url":"https://api.github.com/repos/dedis/cothority/commits{/sha}","git_commits_url":"https://api.github.com/repos/dedis/cothority/git/commits{/sha}","comments_url":"https://api.github.com/repos/dedis/cothority/comments{/number}","issue_comment_url":"https://api.github.com/repos/dedis/cothority/issues/comments{/number}","contents_url":"https://api.github.com/repos/dedis/cothority/contents/{+path}","compare_url":"https://api.github.com/repos/dedis/cothority/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dedis/cothority/merges","archive_url":"https://api.github.com/repos/dedis/cothority/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dedis/cothority/downloads","issues_url":"https://api.github.com/repos/dedis/cothority/issues{/number}","pulls_url":"https://api.github.com/repos/dedis/cothority/pulls{/number}","milestones_url":"https://api.github.com/repos/dedis/cothority/milestones{/number}","notifications_url":"https://api.github.com/repos/dedis/cothority/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dedis/cothority/labels{/name}","releases_url":"https://api.github.com/repos/dedis/cothority/releases{/id}","deployments_url":"https://api.github.com/repos/dedis/cothority/deployments","created_at":"2015-09-02T09:13:57Z","updated_at":"2016-08-29T00:58:40Z","pushed_at":"2016-09-07T09:36:11Z","git_url":"git://github.com/dedis/cothority.git","ssh_url":"git@github.com:dedis/cothority.git","clone_url":"https://github.com/dedis/cothority.git","svn_url":"https://github.com/dedis/cothority","homepage":"","size":70544,"stargazers_count":113,"watchers_count":113,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11,"mirror_url":null,"open_issues_count":102,"forks":11,"open_issues":102,"watchers":113,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dedis/cothority/pulls/569"},"html":{"href":"https://github.com/dedis/cothority/pull/569"},"issue":{"href":"https://api.github.com/repos/dedis/cothority/issues/569"},"comments":{"href":"https://api.github.com/repos/dedis/cothority/issues/569/comments"},"review_comments":{"href":"https://api.github.com/repos/dedis/cothority/pulls/569/comments"},"review_comment":{"href":"https://api.github.com/repos/dedis/cothority/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dedis/cothority/pulls/569/commits"},"statuses":{"href":"https://api.github.com/repos/dedis/cothority/statuses/9409f62e6ca6255295274e323be4a2b987497ac5"}}}}
{"actor":{"display_login":"ineiti"}}