{"action":"created","comment":{"url":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/comments/87247758","pull_request_review_id":7865982,"id":87247758,"diff_hunk":"@@ -1,121 +1,167 @@\n package lorawan\n \n-import \"github.com/TheThingsNetwork/ttn/api\"\n+import (\n+\t\"github.com/TheThingsNetwork/ttn/api\"\n+\t\"github.com/TheThingsNetwork/ttn/utils/errors\"\n+)\n \n // Validate implements the api.Validator interface\n-func (m *DeviceIdentifier) Validate() bool {\n+func (m *DeviceIdentifier) Validate() error {\n \tif m.AppEui == nil || m.AppEui.IsEmpty() {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"AppEui\", \"can not be empty\")\n \t}\n \tif m.DevEui == nil || m.DevEui.IsEmpty() {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"DevEui\", \"can not be empty\")\n \t}\n-\treturn true\n+\treturn nil\n }\n \n // Validate implements the api.Validator interface\n-func (m *Device) Validate() bool {\n+func (m *Device) Validate() error {\n \tif m.AppEui == nil || m.AppEui.IsEmpty() {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"AppEui\", \"can not be empty\")\n \t}\n \tif m.DevEui == nil || m.DevEui.IsEmpty() {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"DevEui\", \"can not be empty\")\n \t}\n-\tif m.AppId == \"\" || !api.ValidID(m.AppId) {\n-\t\treturn false\n+\tif err := api.NotEmptyAndValidId(m.AppId, \"AppId\"); err != nil {\n+\t\treturn err\n \t}\n-\tif m.DevId == \"\" || !api.ValidID(m.DevId) {\n-\t\treturn false\n+\tif err := api.NotEmptyAndValidId(m.DevId, \"DevId\"); err != nil {\n+\t\treturn err\n \t}\n-\treturn true\n+\treturn nil\n }\n \n // Validate implements the api.Validator interface\n-func (m *Metadata) Validate() bool {\n+func (m *Metadata) Validate() error {\n \tswitch m.Modulation {\n \tcase Modulation_LORA:\n \t\tif m.DataRate == \"\" {\n-\t\t\treturn false\n+\t\t\treturn errors.NewErrInvalidArgument(\"DataRate\", \"can not be empty\")\n \t\t}\n \tcase Modulation_FSK:\n \t\tif m.BitRate == 0 {\n-\t\t\treturn false\n+\t\t\treturn errors.NewErrInvalidArgument(\"BitRate\", \"can not be empty\")\n \t\t}\n \t}\n \tif m.CodingRate == \"\" {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"CodingRate\", \"can not be empty\")\n \t}\n-\treturn true\n+\treturn nil\n }\n \n // Validate implements the api.Validator interface\n-func (m *TxConfiguration) Validate() bool {\n+func (m *TxConfiguration) Validate() error {\n \tswitch m.Modulation {\n \tcase Modulation_LORA:\n \t\tif m.DataRate == \"\" {\n-\t\t\treturn false\n+\t\t\treturn errors.NewErrInvalidArgument(\"DataRate\", \"can not be empty\")\n \t\t}\n \tcase Modulation_FSK:\n \t\tif m.BitRate == 0 {\n-\t\t\treturn false\n+\t\t\treturn errors.NewErrInvalidArgument(\"BitRate\", \"can not be empty\")\n \t\t}\n \t}\n \tif m.CodingRate == \"\" {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"CodingRate\", \"can not be empty\")\n \t}\n-\treturn true\n+\treturn nil\n }\n \n // Validate implements the api.Validator interface\n-func (m *ActivationMetadata) Validate() bool {\n+func (m *ActivationMetadata) Validate() error {\n \tif m.AppEui == nil || m.AppEui.IsEmpty() {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"AppEui\", \"can not be empty\")\n \t}\n \tif m.DevEui == nil || m.DevEui.IsEmpty() {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"DevEui\", \"can not be empty\")\n \t}\n \tif m.DevAddr != nil && m.DevAddr.IsEmpty() {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"DevAddr\", \"can not be empty\")\n \t}\n \tif m.NwkSKey != nil && m.NwkSKey.IsEmpty() {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"NwkSKey\", \"can not be empty\")\n \t}\n-\treturn true\n+\treturn nil\n }\n \n // Validate implements the api.Validator interface\n-func (m *Message) Validate() bool {\n+func (m *Message) Validate() error {\n \tif m.Major != Major_LORAWAN_R1 {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"Major\", \"invalid value \" + Major_LORAWAN_R1.String())\n \t}\n \tswitch m.MType {\n \tcase MType_JOIN_REQUEST:\n-\t\treturn m.GetJoinRequestPayload() != nil && m.GetJoinRequestPayload().Validate()\n+\t\tif m.GetJoinRequestPayload() == nil {\n+\t\t\treturn errors.NewErrInvalidArgument(\"JoinRequestPayload\", \"can not be empty\")\n+\t\t}\n+\t\tif err := m.GetJoinRequestPayload().Validate(); err != nil {\n+\t\t\treturn errors.NewErrInvalidArgument(\"JoinRequestPayload\", err.Error())\n+\t\t}\n \tcase MType_JOIN_ACCEPT:\n-\t\treturn m.GetJoinAcceptPayload() != nil && m.GetJoinAcceptPayload().Validate()\n+\t\tif m.GetJoinAcceptPayload() == nil {\n+\t\t\treturn errors.NewErrInvalidArgument(\"JoinAcceptPayload\", \"can not be empty\")\n+\t\t}\n+\t\tif err := m.GetJoinAcceptPayload().Validate(); err != nil {\n+\t\t\treturn errors.NewErrInvalidArgument(\"JoinAcceptPayload\", err.Error())\n+\t\t}\n \tcase MType_UNCONFIRMED_UP, MType_UNCONFIRMED_DOWN, MType_CONFIRMED_UP, MType_CONFIRMED_DOWN:\n-\t\treturn m.GetMacPayload() != nil && m.GetMacPayload().Validate()\n+\t\tif m.GetMacPayload() == nil {\n+\t\t\treturn errors.NewErrInvalidArgument(\"MacPayload\", \"can not be empty\")\n+\t\t}\n+\t\tif err := m.GetMacPayload().Validate(); err != nil {\n+\t\t\treturn errors.NewErrInvalidArgument(\"MacPayload\", err.Error())\n+\t\t}\n+\tdefault:\n+\t\treturn errors.NewErrInvalidArgument(\"MType\", \"unknown type \" + m.MType.String())\n \t}\n-\treturn false\n+\n+\treturn nil\n }\n \n // Validate implements the api.Validator interface\n-func (m *JoinRequestPayload) Validate() bool {\n-\treturn len(m.AppEui) == 8 && len(m.DevEui) == 8 && len(m.DevNonce) == 2\n+func (m *JoinRequestPayload) Validate() error {\n+\tif len(m.AppEui) != 8 {\n+\t\treturn errors.NewErrInvalidArgument(\"AppEui\", \"length must be 8\")\n+\t}\n+\tif len(m.DevEui) != 8 {\n+\t\treturn errors.NewErrInvalidArgument(\"DevEui\", \"length must be 8\")\n+\t}\n+\tif len(m.DevNonce) != 2 {\n+\t\treturn errors.NewErrInvalidArgument(\"DevNonce\", \"length must be 2\")\n+\t}\n+\n+\treturn nil\n }\n \n // Validate implements the api.Validator interface\n-func (m *JoinAcceptPayload) Validate() bool {\n+func (m *JoinAcceptPayload) Validate() error {\n \tif len(m.Encrypted) != 0 {\n-\t\treturn true\n+\t\treturn nil\n \t}\n+\n \tif m.CfList != nil && len(m.CfList.Freq) != 5 {\n-\t\treturn false\n+\t\treturn errors.NewErrInvalidArgument(\"CfList.Freq\", \"length must be 5\");\n+\t}\n+\n+\tif len(m.DevAddr) != 4 {","path":"api/protocol/lorawan/validation.go","position":188,"original_position":188,"commit_id":"d8271e5ac67bf0695e4a1ea53cb54197cccce91c","original_commit_id":"d8271e5ac67bf0695e4a1ea53cb54197cccce91c","user":{"login":"htdvisser","id":181308,"avatar_url":"https://avatars.githubusercontent.com/u/181308?v=3","gravatar_id":"","url":"https://api.github.com/users/htdvisser","html_url":"https://github.com/htdvisser","followers_url":"https://api.github.com/users/htdvisser/followers","following_url":"https://api.github.com/users/htdvisser/following{/other_user}","gists_url":"https://api.github.com/users/htdvisser/gists{/gist_id}","starred_url":"https://api.github.com/users/htdvisser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/htdvisser/subscriptions","organizations_url":"https://api.github.com/users/htdvisser/orgs","repos_url":"https://api.github.com/users/htdvisser/repos","events_url":"https://api.github.com/users/htdvisser/events{/privacy}","received_events_url":"https://api.github.com/users/htdvisser/received_events","type":"User","site_admin":false},"body":"Change this to use `Empty()` method (length of a `types.DevAddr` is always 4)","created_at":"2016-11-09T18:20:49Z","updated_at":"2016-11-09T18:20:49Z","html_url":"https://github.com/TheThingsNetwork/ttn/pull/354#discussion_r87247758","pull_request_url":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/354","_links":{"self":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/comments/87247758"},"html":{"href":"https://github.com/TheThingsNetwork/ttn/pull/354#discussion_r87247758"},"pull_request":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/354"}}},"pull_request":{"url":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/354","id":93008573,"html_url":"https://github.com/TheThingsNetwork/ttn/pull/354","diff_url":"https://github.com/TheThingsNetwork/ttn/pull/354.diff","patch_url":"https://github.com/TheThingsNetwork/ttn/pull/354.patch","issue_url":"https://api.github.com/repos/TheThingsNetwork/ttn/issues/354","number":354,"state":"open","locked":false,"title":"Make validation return informative error instead of true/false","user":{"login":"Niondir","id":373559,"avatar_url":"https://avatars.githubusercontent.com/u/373559?v=3","gravatar_id":"","url":"https://api.github.com/users/Niondir","html_url":"https://github.com/Niondir","followers_url":"https://api.github.com/users/Niondir/followers","following_url":"https://api.github.com/users/Niondir/following{/other_user}","gists_url":"https://api.github.com/users/Niondir/gists{/gist_id}","starred_url":"https://api.github.com/users/Niondir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Niondir/subscriptions","organizations_url":"https://api.github.com/users/Niondir/orgs","repos_url":"https://api.github.com/users/Niondir/repos","events_url":"https://api.github.com/users/Niondir/events{/privacy}","received_events_url":"https://api.github.com/users/Niondir/received_events","type":"User","site_admin":false},"body":"Closes #348","created_at":"2016-11-09T17:51:25Z","updated_at":"2016-11-09T18:29:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8900c43e27264aa683fced61eb8c2df737273e00","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/354/commits","review_comments_url":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/354/comments","review_comment_url":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/TheThingsNetwork/ttn/issues/354/comments","statuses_url":"https://api.github.com/repos/TheThingsNetwork/ttn/statuses/d8271e5ac67bf0695e4a1ea53cb54197cccce91c","head":{"label":"Lobaro:fix-348","ref":"fix-348","sha":"d8271e5ac67bf0695e4a1ea53cb54197cccce91c","user":{"login":"Lobaro","id":10530646,"avatar_url":"https://avatars.githubusercontent.com/u/10530646?v=3","gravatar_id":"","url":"https://api.github.com/users/Lobaro","html_url":"https://github.com/Lobaro","followers_url":"https://api.github.com/users/Lobaro/followers","following_url":"https://api.github.com/users/Lobaro/following{/other_user}","gists_url":"https://api.github.com/users/Lobaro/gists{/gist_id}","starred_url":"https://api.github.com/users/Lobaro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Lobaro/subscriptions","organizations_url":"https://api.github.com/users/Lobaro/orgs","repos_url":"https://api.github.com/users/Lobaro/repos","events_url":"https://api.github.com/users/Lobaro/events{/privacy}","received_events_url":"https://api.github.com/users/Lobaro/received_events","type":"Organization","site_admin":false},"repo":{"id":72855725,"name":"ttn","full_name":"Lobaro/ttn","owner":{"login":"Lobaro","id":10530646,"avatar_url":"https://avatars.githubusercontent.com/u/10530646?v=3","gravatar_id":"","url":"https://api.github.com/users/Lobaro","html_url":"https://github.com/Lobaro","followers_url":"https://api.github.com/users/Lobaro/followers","following_url":"https://api.github.com/users/Lobaro/following{/other_user}","gists_url":"https://api.github.com/users/Lobaro/gists{/gist_id}","starred_url":"https://api.github.com/users/Lobaro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Lobaro/subscriptions","organizations_url":"https://api.github.com/users/Lobaro/orgs","repos_url":"https://api.github.com/users/Lobaro/repos","events_url":"https://api.github.com/users/Lobaro/events{/privacy}","received_events_url":"https://api.github.com/users/Lobaro/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Lobaro/ttn","description":"Routing Backend for The Things Network","fork":true,"url":"https://api.github.com/repos/Lobaro/ttn","forks_url":"https://api.github.com/repos/Lobaro/ttn/forks","keys_url":"https://api.github.com/repos/Lobaro/ttn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Lobaro/ttn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Lobaro/ttn/teams","hooks_url":"https://api.github.com/repos/Lobaro/ttn/hooks","issue_events_url":"https://api.github.com/repos/Lobaro/ttn/issues/events{/number}","events_url":"https://api.github.com/repos/Lobaro/ttn/events","assignees_url":"https://api.github.com/repos/Lobaro/ttn/assignees{/user}","branches_url":"https://api.github.com/repos/Lobaro/ttn/branches{/branch}","tags_url":"https://api.github.com/repos/Lobaro/ttn/tags","blobs_url":"https://api.github.com/repos/Lobaro/ttn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Lobaro/ttn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Lobaro/ttn/git/refs{/sha}","trees_url":"https://api.github.com/repos/Lobaro/ttn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Lobaro/ttn/statuses/{sha}","languages_url":"https://api.github.com/repos/Lobaro/ttn/languages","stargazers_url":"https://api.github.com/repos/Lobaro/ttn/stargazers","contributors_url":"https://api.github.com/repos/Lobaro/ttn/contributors","subscribers_url":"https://api.github.com/repos/Lobaro/ttn/subscribers","subscription_url":"https://api.github.com/repos/Lobaro/ttn/subscription","commits_url":"https://api.github.com/repos/Lobaro/ttn/commits{/sha}","git_commits_url":"https://api.github.com/repos/Lobaro/ttn/git/commits{/sha}","comments_url":"https://api.github.com/repos/Lobaro/ttn/comments{/number}","issue_comment_url":"https://api.github.com/repos/Lobaro/ttn/issues/comments{/number}","contents_url":"https://api.github.com/repos/Lobaro/ttn/contents/{+path}","compare_url":"https://api.github.com/repos/Lobaro/ttn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Lobaro/ttn/merges","archive_url":"https://api.github.com/repos/Lobaro/ttn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Lobaro/ttn/downloads","issues_url":"https://api.github.com/repos/Lobaro/ttn/issues{/number}","pulls_url":"https://api.github.com/repos/Lobaro/ttn/pulls{/number}","milestones_url":"https://api.github.com/repos/Lobaro/ttn/milestones{/number}","notifications_url":"https://api.github.com/repos/Lobaro/ttn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Lobaro/ttn/labels{/name}","releases_url":"https://api.github.com/repos/Lobaro/ttn/releases{/id}","deployments_url":"https://api.github.com/repos/Lobaro/ttn/deployments","created_at":"2016-11-04T14:37:58Z","updated_at":"2016-11-04T14:37:59Z","pushed_at":"2016-11-09T17:58:23Z","git_url":"git://github.com/Lobaro/ttn.git","ssh_url":"git@github.com:Lobaro/ttn.git","clone_url":"https://github.com/Lobaro/ttn.git","svn_url":"https://github.com/Lobaro/ttn","homepage":"http://thethingsnetwork.org","size":4593,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"v2-preview"}},"base":{"label":"TheThingsNetwork:v2-preview","ref":"v2-preview","sha":"9d497f037e92d44bc12584be3827e1b1a1ce57d1","user":{"login":"TheThingsNetwork","id":13333576,"avatar_url":"https://avatars.githubusercontent.com/u/13333576?v=3","gravatar_id":"","url":"https://api.github.com/users/TheThingsNetwork","html_url":"https://github.com/TheThingsNetwork","followers_url":"https://api.github.com/users/TheThingsNetwork/followers","following_url":"https://api.github.com/users/TheThingsNetwork/following{/other_user}","gists_url":"https://api.github.com/users/TheThingsNetwork/gists{/gist_id}","starred_url":"https://api.github.com/users/TheThingsNetwork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/TheThingsNetwork/subscriptions","organizations_url":"https://api.github.com/users/TheThingsNetwork/orgs","repos_url":"https://api.github.com/users/TheThingsNetwork/repos","events_url":"https://api.github.com/users/TheThingsNetwork/events{/privacy}","received_events_url":"https://api.github.com/users/TheThingsNetwork/received_events","type":"Organization","site_admin":false},"repo":{"id":47138513,"name":"ttn","full_name":"TheThingsNetwork/ttn","owner":{"login":"TheThingsNetwork","id":13333576,"avatar_url":"https://avatars.githubusercontent.com/u/13333576?v=3","gravatar_id":"","url":"https://api.github.com/users/TheThingsNetwork","html_url":"https://github.com/TheThingsNetwork","followers_url":"https://api.github.com/users/TheThingsNetwork/followers","following_url":"https://api.github.com/users/TheThingsNetwork/following{/other_user}","gists_url":"https://api.github.com/users/TheThingsNetwork/gists{/gist_id}","starred_url":"https://api.github.com/users/TheThingsNetwork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/TheThingsNetwork/subscriptions","organizations_url":"https://api.github.com/users/TheThingsNetwork/orgs","repos_url":"https://api.github.com/users/TheThingsNetwork/repos","events_url":"https://api.github.com/users/TheThingsNetwork/events{/privacy}","received_events_url":"https://api.github.com/users/TheThingsNetwork/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/TheThingsNetwork/ttn","description":"Routing Backend for The Things Network","fork":false,"url":"https://api.github.com/repos/TheThingsNetwork/ttn","forks_url":"https://api.github.com/repos/TheThingsNetwork/ttn/forks","keys_url":"https://api.github.com/repos/TheThingsNetwork/ttn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/TheThingsNetwork/ttn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/TheThingsNetwork/ttn/teams","hooks_url":"https://api.github.com/repos/TheThingsNetwork/ttn/hooks","issue_events_url":"https://api.github.com/repos/TheThingsNetwork/ttn/issues/events{/number}","events_url":"https://api.github.com/repos/TheThingsNetwork/ttn/events","assignees_url":"https://api.github.com/repos/TheThingsNetwork/ttn/assignees{/user}","branches_url":"https://api.github.com/repos/TheThingsNetwork/ttn/branches{/branch}","tags_url":"https://api.github.com/repos/TheThingsNetwork/ttn/tags","blobs_url":"https://api.github.com/repos/TheThingsNetwork/ttn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/TheThingsNetwork/ttn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/TheThingsNetwork/ttn/git/refs{/sha}","trees_url":"https://api.github.com/repos/TheThingsNetwork/ttn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/TheThingsNetwork/ttn/statuses/{sha}","languages_url":"https://api.github.com/repos/TheThingsNetwork/ttn/languages","stargazers_url":"https://api.github.com/repos/TheThingsNetwork/ttn/stargazers","contributors_url":"https://api.github.com/repos/TheThingsNetwork/ttn/contributors","subscribers_url":"https://api.github.com/repos/TheThingsNetwork/ttn/subscribers","subscription_url":"https://api.github.com/repos/TheThingsNetwork/ttn/subscription","commits_url":"https://api.github.com/repos/TheThingsNetwork/ttn/commits{/sha}","git_commits_url":"https://api.github.com/repos/TheThingsNetwork/ttn/git/commits{/sha}","comments_url":"https://api.github.com/repos/TheThingsNetwork/ttn/comments{/number}","issue_comment_url":"https://api.github.com/repos/TheThingsNetwork/ttn/issues/comments{/number}","contents_url":"https://api.github.com/repos/TheThingsNetwork/ttn/contents/{+path}","compare_url":"https://api.github.com/repos/TheThingsNetwork/ttn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/TheThingsNetwork/ttn/merges","archive_url":"https://api.github.com/repos/TheThingsNetwork/ttn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/TheThingsNetwork/ttn/downloads","issues_url":"https://api.github.com/repos/TheThingsNetwork/ttn/issues{/number}","pulls_url":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls{/number}","milestones_url":"https://api.github.com/repos/TheThingsNetwork/ttn/milestones{/number}","notifications_url":"https://api.github.com/repos/TheThingsNetwork/ttn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/TheThingsNetwork/ttn/labels{/name}","releases_url":"https://api.github.com/repos/TheThingsNetwork/ttn/releases{/id}","deployments_url":"https://api.github.com/repos/TheThingsNetwork/ttn/deployments","created_at":"2015-11-30T18:41:33Z","updated_at":"2016-11-03T11:17:26Z","pushed_at":"2016-11-09T17:51:25Z","git_url":"git://github.com/TheThingsNetwork/ttn.git","ssh_url":"git@github.com:TheThingsNetwork/ttn.git","clone_url":"https://github.com/TheThingsNetwork/ttn.git","svn_url":"https://github.com/TheThingsNetwork/ttn","homepage":"http://thethingsnetwork.org","size":6282,"stargazers_count":110,"watchers_count":110,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":54,"mirror_url":null,"open_issues_count":25,"forks":54,"open_issues":25,"watchers":110,"default_branch":"v2-preview"}},"_links":{"self":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/354"},"html":{"href":"https://github.com/TheThingsNetwork/ttn/pull/354"},"issue":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/issues/354"},"comments":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/issues/354/comments"},"review_comments":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/354/comments"},"review_comment":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/pulls/354/commits"},"statuses":{"href":"https://api.github.com/repos/TheThingsNetwork/ttn/statuses/d8271e5ac67bf0695e4a1ea53cb54197cccce91c"}}}}
{"actor":{"display_login":"htdvisser"}}