{"action":"created","comment":{"url":"https://api.github.com/repos/mumble-voip/mumble/pulls/comments/62390983","id":62390983,"diff_hunk":"@@ -0,0 +1,324 @@\n+#!/usr/bin/env python\n+# -*- coding: utf-8 -*-\n+#\n+# Copyright 2009-2016 The Mumble Developers. All rights reserved.\n+# Use of this source code is governed by a BSD-style license\n+# that can be found in the LICENSE file at the root of the\n+# Mumble source tree or at <https://www.mumble.info/LICENSE>.\n+\n+# Convert the Git log of the repository into a CHANGES file.\n+#\n+# This script uses the same formatting that\n+# 'git2cl.pl' has historically used.\n+\n+from __future__ import (unicode_literals, print_function, division)\n+\n+import subprocess\n+import sys\n+import re\n+\n+def textwidth(text):\n+\t'''\n+\t\tCalculate the with of 'text' in number\n+\t\tof characters.\n+\n+\t\tThis function counts tabs as 8 characters.\n+\t'''\n+\tcount = 0\n+\tfor char in text:\n+\t\tif char == '\\t':\n+\t\t\tcount += 8\n+\t\telse:\n+\t\t\tcount += 1\n+\treturn count\n+\n+\n+def perlCompatibleTextWrap(text, width, initial_indent, subsequent_indent):\n+\t'''\n+\t\tFormat text like Perl's Text::Wrap#wrap function.\n+\n+\t\tWe do this to keep compatibility with existing formatting in\n+\t\tthe CHANGES file. (Invoking this script overwrites the old file,\n+\t\tso the output of this function must match the Perl function's\n+\t\toutput.)\n+\t'''\n+\n+\tlines = []\n+\tline = \"\"\n+\n+\t# Require at least one empty character\n+\t# of free space at the end of the line.\n+\twidth -= 1\n+\n+\t# Create our word queue by splitting the commit\n+\t# description by a regular space character (' ').\n+\t#\n+\t# This is a little simplistic, but it works in practice.\n+\t# In an ideal world, we should probably split all\n+\t# whitespace, so our queue guaranteed to only contain\n+\t# words.\n+\tqueue = text.split(' ')\n+\n+\t# Iterate through each word and in the queue\n+\t# and construct our formatted text.\n+\twhile len(queue) > 0:\n+\t\tword = queue.pop(0)\n+\n+\t\t# Which indentation mode should we use for\n+\t\t# this line?\n+\t\t# If this is the first line, use 'initial_indent'.\n+\t\t# If not, use 'subsequent_indent'.\n+\t\tif len(lines) == 0:\n+\t\t\t indent = initial_indent\n+\t\telse:\n+\t\t\tindent = subsequent_indent\n+\n+\t\t# If nothing has been added to our line yet,\n+\t\t# add the indentation.\n+\t\tif line == \"\":\n+\t\t\tline = indent\n+\n+\t\t# Find the wordPrefix.\n+\t\t#\n+\t\t# The wordPrefix represents\n+\t\t# the string that will comes before\n+\t\t# 'word' when 'word' is added to the line.\n+\t\t#\n+\t\t# If no other words have been added to the\n+\t\t# line, the wordPrefix is the indentation.\n+\t\t# (Either initial_indnet or subsequent_indent).\n+\t\t# If other words have been added to the line\n+\t\t# already, the wordPrefix will be the existing\n+\t\t# content of the line, plus a space.\n+\t\tif line == indent:\n+\t\t\twordPrefix = line\n+\t\telse:\n+\t\t\twordPrefix = line + \" \"\n+\n+\t\t# Calculate the width of line with the word added.\n+\t\twidthWithWordAdded = textwidth(wordPrefix + word)\n+\n+\t\t# Check if the line would become too long if the word\n+\t\t# was added to the line as-is (considering the wordPrefix).\n+\t\tif widthWithWordAdded > width:\n+\t\t\t# Handle words that need to be split.\n+\t\t\t# As a rule, split words MUST start at the very beginning\n+\t\t\t# of a line (considering indentation) -- that is, there\n+\t\t\t# most be no other words in the line for a split word to\n+\t\t\t# be output.\n+\t\t\t#\n+\t\t\t# We check:\n+\t\t\t# (1) If the word is too long to be the only word on a line\n+\t\t\t# with the current width and indentation settings, and...\n+\t\t\t# (2) That the line only contains indentation.\n+\t\t\t#     This is the same as saying that the current line has\n+\t\t\t#     no other words in it.\n+\t\t\t#\n+\t\t\t# Both (1) and (2) must be true for the split word to be\n+\t\t\t# output.\n+\t\t\t#\n+\t\t\t# If only (1) is true, the word will be put back into the\n+\t\t\t# queue.\n+\t\t\t# Since the word could not fit onto the line, we enter the\n+\t\t\t# 'else'-part of this if-statement, and we consider the\n+\t\t\t# current line done -- the rest of the current line is\n+\t\t\t# left unused.\n+\t\t\t# Then, once we're on the next line, which is empty, we\n+\t\t\t# enter the word-splitting part of this if-statement and\n+\t\t\t# begin outputting the split word.\n+\t\t\tif textwidth(indent + word) > width and line == indent:\n+\t\t\t\t# The preconditions have been met\n+\t\t\t\t# for word splitting to occur.\n+\t\t\t\t#\n+\t\t\t\t# Cut the word into two parts.\n+\t\t\t\t#\n+\t\t\t\t# The first part is the one that goes\n+\t\t\t\t# onto the empty line are are currently at,\n+\t\t\t\t# and fills it.\n+\t\t\t\t#\n+\t\t\t\t# The other part is the remainder. That part\n+\t\t\t\t# is put back into the word queue.\n+\t\t\t\tsize = width - textwidth(wordPrefix)\n+\t\t\t\tkeep = word[0:size]\n+\t\t\t\tputBack = word[size:]\n+\t\t\t\tqueue.insert(0, putBack)\n+\t\t\t\tword = keep\n+\t\t\telse:\n+\t\t\t\t# There was not enough space left in the line to be\n+\t\t\t\t# able to contain this word.\n+\t\t\t\t#\n+\t\t\t\t# This is either because,\n+\t\t\t\t# (a) There simply was not enough space, or...\n+\t\t\t\t# (b) The word-splitting check demanded that\n+\t\t\t\t#     we skip the rest of the line. This\n+\t\t\t\t#     happens because we, as a rule, only\n+\t\t\t\t#     output split words beginning on their\n+\t\t\t\t#     own pristine line.\n+\t\t\t\t#\n+\t\t\t\t# Discard the word, and consider the current line complete.\n+\t\t\t\t# This moves on to the next line.\n+\t\t\t\tqueue.insert(0, word)\n+\t\t\t\tlines.append(line)\n+\t\t\t\tline = \"\"\n+\t\t\t\tcontinue\n+\n+\t\t# Add the word to the line\n+\t\tif line == indent:\n+\t\t\tline = wordPrefix + word\n+\t\telse:\n+\t\t\tline = wordPrefix + word\n+\n+\t# If we have a non-empty line, but no\n+\t# words left in the queue, it is the last\n+\t# line. Append it to the 'lines' list.\n+\tif line != \"\":\n+\t\tlines.append(line)\n+\n+\t# Format the lines for user consumption.\n+\treturn \"\\n\".join(lines)\n+\n+def matchRegexp(regexp, content):\n+\t'''\n+\t\tA simple function to make regular\n+\t\texpression matching return a boolean\n+\t\tvalue for easier readability.\n+\t'''\n+\treturn re.match(regexp, content, re.UNICODE) is not None\n+\n+def gitLogOutput():\n+\t'''\n+\t\tInvoke git to get NUL-separated log lines.\n+\t\tThe rows are as follows:\n+\t\t - Commit hash\n+\t\t - Author\n+\t\t - Email\n+\t\t - Date (YYYY-MM-DD)\n+\t\t - Subject\n+\t'''\n+\tp = subprocess.Popen([\"git\", \"log\", \"--date=short\", \"--pretty=format:%h%x00%an%x00%ae%x00%ad%x00%s\"], stdout=subprocess.PIPE)\n+\tstdout, stderr = p.communicate()\n+\tif stdout is not None:\n+\t\tstdout = stdout.decode('utf-8')\n+\tif stderr is not None:\n+\t\tstderr = stderr.decode('utf-8')\n+\tif p.returncode != 0:\n+\t\traise Exception('\"git log\" failed: %s', stderr)\n+\treturn stdout\n+\n+def main():\n+\tlog = gitLogOutput()\n+\n+\t# The authors dict maps between email addresses\n+\t# and author names.\n+\tauthors = {}\n+\n+\t# The dates dictionary maps from\n+\t# dates, to another dictionary\n+\t# that maps from email addresses\n+\t# to a sorted list of commit subject\n+\t# lines.\n+\t#\n+\t# In pseudo-code, the type of 'dates' is:\n+\t# \n+\t#     dict<string(YYMMDD), dict<string(email), list(subject)>>\n+\t#\n+\tdates = {}\n+\n+\t# lastSubject contains the last subject line\n+\t# processed. It is used to detect duplicate\n+\t# subject lines and discard them.\n+\tlastSubject = \"\"\n+\n+\tfor line in log.split('\\n'):\n+\t\tcommit, author, email, date, subject = line.split('\\0')\n+\n+\t\tif author == \"Thorvald Natvig\":\n+\t\t\t# Because someone forgets to set their git username on every platform...\n+\t\t\temail = \"slicer@users.sourceforge.net\"\n+\n+\t\t# Back in the old days, we appended [$SourceForgeUserName]\n+\t\t# in our commit messages when we applied patches by contributors\n+\t\t# on SourceForge.\n+\t\t#\n+\t\t# For example:\n+\t\t#\n+\t\t#     Half-Life 2 Deathmatch Positional Audio [Snares]\n+\t\t#\n+\t\t# The code below extracts author names from the subject line\n+\t\t# of the commit message, and updates the 'author' and\n+\t\t# 'email' variables to point to the SourceForge user\n+\t\t# specified in the square brackets. The email address\n+\t\t# is simply the lowercase username @users.sourceforge.net.\n+\t\t# \n+\t\tpatchAuthorRe = \"\\s*\\[([\\w-]+)\\]\\s*$\"\n+\t\tmatch = re.search(patchAuthorRe, subject, flags=re.UNICODE)\n+\t\tif match is not None:\n+\t\t\tauthor = match.groups()[0]\n+\t\t\temail = \"{0}@users.sourceforge.net\".format(author.lower())\n+\n+\t\t\t# Remove the [$SourceForgeUserName] from the subject line.\n+\t\t\tsubject = re.sub(patchAuthorRe, \"\", subject)\n+\n+\t\t# Record the first occurrence of an author's\n+\t\t# email address and name in the author <-> email map.\n+\t\t#\n+\t\t# This mapping is used \n+\t\tif authors.get(email, None) is None:\n+\t\t\tauthors[email] = author\n+","path":"scripts/generate-CHANGES.py","position":268,"original_position":268,"commit_id":"f6036ce6d123bd1ca3136a7b811703e1fd6d8a48","original_commit_id":"f6036ce6d123bd1ca3136a7b811703e1fd6d8a48","user":{"login":"mkrautz","id":36527,"avatar_url":"https://avatars.githubusercontent.com/u/36527?v=3","gravatar_id":"","url":"https://api.github.com/users/mkrautz","html_url":"https://github.com/mkrautz","followers_url":"https://api.github.com/users/mkrautz/followers","following_url":"https://api.github.com/users/mkrautz/following{/other_user}","gists_url":"https://api.github.com/users/mkrautz/gists{/gist_id}","starred_url":"https://api.github.com/users/mkrautz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mkrautz/subscriptions","organizations_url":"https://api.github.com/users/mkrautz/orgs","repos_url":"https://api.github.com/users/mkrautz/repos","events_url":"https://api.github.com/users/mkrautz/events{/privacy}","received_events_url":"https://api.github.com/users/mkrautz/received_events","type":"User","site_admin":false},"body":"That's probably a good idea!","created_at":"2016-05-06T21:05:51Z","updated_at":"2016-05-06T21:05:51Z","html_url":"https://github.com/mumble-voip/mumble/pull/2246#discussion_r62390983","pull_request_url":"https://api.github.com/repos/mumble-voip/mumble/pulls/2246","_links":{"self":{"href":"https://api.github.com/repos/mumble-voip/mumble/pulls/comments/62390983"},"html":{"href":"https://github.com/mumble-voip/mumble/pull/2246#discussion_r62390983"},"pull_request":{"href":"https://api.github.com/repos/mumble-voip/mumble/pulls/2246"}}},"pull_request":{"url":"https://api.github.com/repos/mumble-voip/mumble/pulls/2246","id":69208097,"html_url":"https://github.com/mumble-voip/mumble/pull/2246","diff_url":"https://github.com/mumble-voip/mumble/pull/2246.diff","patch_url":"https://github.com/mumble-voip/mumble/pull/2246.patch","issue_url":"https://api.github.com/repos/mumble-voip/mumble/issues/2246","number":2246,"state":"open","locked":false,"title":"scripts/generate-CHANGES.py: add Python replacement for 'git2cl.pl'.","user":{"login":"mkrautz","id":36527,"avatar_url":"https://avatars.githubusercontent.com/u/36527?v=3","gravatar_id":"","url":"https://api.github.com/users/mkrautz","html_url":"https://github.com/mkrautz","followers_url":"https://api.github.com/users/mkrautz/followers","following_url":"https://api.github.com/users/mkrautz/following{/other_user}","gists_url":"https://api.github.com/users/mkrautz/gists{/gist_id}","starred_url":"https://api.github.com/users/mkrautz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mkrautz/subscriptions","organizations_url":"https://api.github.com/users/mkrautz/orgs","repos_url":"https://api.github.com/users/mkrautz/repos","events_url":"https://api.github.com/users/mkrautz/events{/privacy}","received_events_url":"https://api.github.com/users/mkrautz/received_events","type":"User","site_admin":false},"body":"This is a pure-Python, 100% compatible replacement of 'git2cl.pl'.","created_at":"2016-05-06T20:47:36Z","updated_at":"2016-05-06T21:05:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f42c3eaaf7e4b36dd7471b5eb1f33c5780525859","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/mumble-voip/mumble/pulls/2246/commits","review_comments_url":"https://api.github.com/repos/mumble-voip/mumble/pulls/2246/comments","review_comment_url":"https://api.github.com/repos/mumble-voip/mumble/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mumble-voip/mumble/issues/2246/comments","statuses_url":"https://api.github.com/repos/mumble-voip/mumble/statuses/f6036ce6d123bd1ca3136a7b811703e1fd6d8a48","head":{"label":"mkrautz:generate-CHANGES-py","ref":"generate-CHANGES-py","sha":"f6036ce6d123bd1ca3136a7b811703e1fd6d8a48","user":{"login":"mkrautz","id":36527,"avatar_url":"https://avatars.githubusercontent.com/u/36527?v=3","gravatar_id":"","url":"https://api.github.com/users/mkrautz","html_url":"https://github.com/mkrautz","followers_url":"https://api.github.com/users/mkrautz/followers","following_url":"https://api.github.com/users/mkrautz/following{/other_user}","gists_url":"https://api.github.com/users/mkrautz/gists{/gist_id}","starred_url":"https://api.github.com/users/mkrautz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mkrautz/subscriptions","organizations_url":"https://api.github.com/users/mkrautz/orgs","repos_url":"https://api.github.com/users/mkrautz/repos","events_url":"https://api.github.com/users/mkrautz/events{/privacy}","received_events_url":"https://api.github.com/users/mkrautz/received_events","type":"User","site_admin":false},"repo":{"id":3210109,"name":"mumble","full_name":"mkrautz/mumble","owner":{"login":"mkrautz","id":36527,"avatar_url":"https://avatars.githubusercontent.com/u/36527?v=3","gravatar_id":"","url":"https://api.github.com/users/mkrautz","html_url":"https://github.com/mkrautz","followers_url":"https://api.github.com/users/mkrautz/followers","following_url":"https://api.github.com/users/mkrautz/following{/other_user}","gists_url":"https://api.github.com/users/mkrautz/gists{/gist_id}","starred_url":"https://api.github.com/users/mkrautz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mkrautz/subscriptions","organizations_url":"https://api.github.com/users/mkrautz/orgs","repos_url":"https://api.github.com/users/mkrautz/repos","events_url":"https://api.github.com/users/mkrautz/events{/privacy}","received_events_url":"https://api.github.com/users/mkrautz/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mkrautz/mumble","description":"Mumble VoIP Client/Server","fork":true,"url":"https://api.github.com/repos/mkrautz/mumble","forks_url":"https://api.github.com/repos/mkrautz/mumble/forks","keys_url":"https://api.github.com/repos/mkrautz/mumble/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mkrautz/mumble/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mkrautz/mumble/teams","hooks_url":"https://api.github.com/repos/mkrautz/mumble/hooks","issue_events_url":"https://api.github.com/repos/mkrautz/mumble/issues/events{/number}","events_url":"https://api.github.com/repos/mkrautz/mumble/events","assignees_url":"https://api.github.com/repos/mkrautz/mumble/assignees{/user}","branches_url":"https://api.github.com/repos/mkrautz/mumble/branches{/branch}","tags_url":"https://api.github.com/repos/mkrautz/mumble/tags","blobs_url":"https://api.github.com/repos/mkrautz/mumble/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mkrautz/mumble/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mkrautz/mumble/git/refs{/sha}","trees_url":"https://api.github.com/repos/mkrautz/mumble/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mkrautz/mumble/statuses/{sha}","languages_url":"https://api.github.com/repos/mkrautz/mumble/languages","stargazers_url":"https://api.github.com/repos/mkrautz/mumble/stargazers","contributors_url":"https://api.github.com/repos/mkrautz/mumble/contributors","subscribers_url":"https://api.github.com/repos/mkrautz/mumble/subscribers","subscription_url":"https://api.github.com/repos/mkrautz/mumble/subscription","commits_url":"https://api.github.com/repos/mkrautz/mumble/commits{/sha}","git_commits_url":"https://api.github.com/repos/mkrautz/mumble/git/commits{/sha}","comments_url":"https://api.github.com/repos/mkrautz/mumble/comments{/number}","issue_comment_url":"https://api.github.com/repos/mkrautz/mumble/issues/comments{/number}","contents_url":"https://api.github.com/repos/mkrautz/mumble/contents/{+path}","compare_url":"https://api.github.com/repos/mkrautz/mumble/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mkrautz/mumble/merges","archive_url":"https://api.github.com/repos/mkrautz/mumble/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mkrautz/mumble/downloads","issues_url":"https://api.github.com/repos/mkrautz/mumble/issues{/number}","pulls_url":"https://api.github.com/repos/mkrautz/mumble/pulls{/number}","milestones_url":"https://api.github.com/repos/mkrautz/mumble/milestones{/number}","notifications_url":"https://api.github.com/repos/mkrautz/mumble/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mkrautz/mumble/labels{/name}","releases_url":"https://api.github.com/repos/mkrautz/mumble/releases{/id}","deployments_url":"https://api.github.com/repos/mkrautz/mumble/deployments","created_at":"2012-01-18T16:24:06Z","updated_at":"2015-08-14T23:40:24Z","pushed_at":"2016-05-06T20:56:58Z","git_url":"git://github.com/mkrautz/mumble.git","ssh_url":"git@github.com:mkrautz/mumble.git","clone_url":"https://github.com/mkrautz/mumble.git","svn_url":"https://github.com/mkrautz/mumble","homepage":"http://mumble.info","size":33964,"stargazers_count":6,"watchers_count":6,"language":"TypeScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":2,"forks":2,"open_issues":2,"watchers":6,"default_branch":"master"}},"base":{"label":"mumble-voip:master","ref":"master","sha":"f885c419b7a9fae2d87f23f48605d25454e9cc97","user":{"login":"mumble-voip","id":639008,"avatar_url":"https://avatars.githubusercontent.com/u/639008?v=3","gravatar_id":"","url":"https://api.github.com/users/mumble-voip","html_url":"https://github.com/mumble-voip","followers_url":"https://api.github.com/users/mumble-voip/followers","following_url":"https://api.github.com/users/mumble-voip/following{/other_user}","gists_url":"https://api.github.com/users/mumble-voip/gists{/gist_id}","starred_url":"https://api.github.com/users/mumble-voip/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mumble-voip/subscriptions","organizations_url":"https://api.github.com/users/mumble-voip/orgs","repos_url":"https://api.github.com/users/mumble-voip/repos","events_url":"https://api.github.com/users/mumble-voip/events{/privacy}","received_events_url":"https://api.github.com/users/mumble-voip/received_events","type":"Organization","site_admin":false},"repo":{"id":1413319,"name":"mumble","full_name":"mumble-voip/mumble","owner":{"login":"mumble-voip","id":639008,"avatar_url":"https://avatars.githubusercontent.com/u/639008?v=3","gravatar_id":"","url":"https://api.github.com/users/mumble-voip","html_url":"https://github.com/mumble-voip","followers_url":"https://api.github.com/users/mumble-voip/followers","following_url":"https://api.github.com/users/mumble-voip/following{/other_user}","gists_url":"https://api.github.com/users/mumble-voip/gists{/gist_id}","starred_url":"https://api.github.com/users/mumble-voip/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mumble-voip/subscriptions","organizations_url":"https://api.github.com/users/mumble-voip/orgs","repos_url":"https://api.github.com/users/mumble-voip/repos","events_url":"https://api.github.com/users/mumble-voip/events{/privacy}","received_events_url":"https://api.github.com/users/mumble-voip/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mumble-voip/mumble","description":"Mumble VoIP Client/Server","fork":false,"url":"https://api.github.com/repos/mumble-voip/mumble","forks_url":"https://api.github.com/repos/mumble-voip/mumble/forks","keys_url":"https://api.github.com/repos/mumble-voip/mumble/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mumble-voip/mumble/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mumble-voip/mumble/teams","hooks_url":"https://api.github.com/repos/mumble-voip/mumble/hooks","issue_events_url":"https://api.github.com/repos/mumble-voip/mumble/issues/events{/number}","events_url":"https://api.github.com/repos/mumble-voip/mumble/events","assignees_url":"https://api.github.com/repos/mumble-voip/mumble/assignees{/user}","branches_url":"https://api.github.com/repos/mumble-voip/mumble/branches{/branch}","tags_url":"https://api.github.com/repos/mumble-voip/mumble/tags","blobs_url":"https://api.github.com/repos/mumble-voip/mumble/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mumble-voip/mumble/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mumble-voip/mumble/git/refs{/sha}","trees_url":"https://api.github.com/repos/mumble-voip/mumble/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mumble-voip/mumble/statuses/{sha}","languages_url":"https://api.github.com/repos/mumble-voip/mumble/languages","stargazers_url":"https://api.github.com/repos/mumble-voip/mumble/stargazers","contributors_url":"https://api.github.com/repos/mumble-voip/mumble/contributors","subscribers_url":"https://api.github.com/repos/mumble-voip/mumble/subscribers","subscription_url":"https://api.github.com/repos/mumble-voip/mumble/subscription","commits_url":"https://api.github.com/repos/mumble-voip/mumble/commits{/sha}","git_commits_url":"https://api.github.com/repos/mumble-voip/mumble/git/commits{/sha}","comments_url":"https://api.github.com/repos/mumble-voip/mumble/comments{/number}","issue_comment_url":"https://api.github.com/repos/mumble-voip/mumble/issues/comments{/number}","contents_url":"https://api.github.com/repos/mumble-voip/mumble/contents/{+path}","compare_url":"https://api.github.com/repos/mumble-voip/mumble/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mumble-voip/mumble/merges","archive_url":"https://api.github.com/repos/mumble-voip/mumble/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mumble-voip/mumble/downloads","issues_url":"https://api.github.com/repos/mumble-voip/mumble/issues{/number}","pulls_url":"https://api.github.com/repos/mumble-voip/mumble/pulls{/number}","milestones_url":"https://api.github.com/repos/mumble-voip/mumble/milestones{/number}","notifications_url":"https://api.github.com/repos/mumble-voip/mumble/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mumble-voip/mumble/labels{/name}","releases_url":"https://api.github.com/repos/mumble-voip/mumble/releases{/id}","deployments_url":"https://api.github.com/repos/mumble-voip/mumble/deployments","created_at":"2011-02-26T01:30:08Z","updated_at":"2016-05-06T13:37:42Z","pushed_at":"2016-05-06T20:56:58Z","git_url":"git://github.com/mumble-voip/mumble.git","ssh_url":"git@github.com:mumble-voip/mumble.git","clone_url":"https://github.com/mumble-voip/mumble.git","svn_url":"https://github.com/mumble-voip/mumble","homepage":"http://www.mumble.info","size":40765,"stargazers_count":1263,"watchers_count":1263,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":394,"mirror_url":null,"open_issues_count":511,"forks":394,"open_issues":511,"watchers":1263,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mumble-voip/mumble/pulls/2246"},"html":{"href":"https://github.com/mumble-voip/mumble/pull/2246"},"issue":{"href":"https://api.github.com/repos/mumble-voip/mumble/issues/2246"},"comments":{"href":"https://api.github.com/repos/mumble-voip/mumble/issues/2246/comments"},"review_comments":{"href":"https://api.github.com/repos/mumble-voip/mumble/pulls/2246/comments"},"review_comment":{"href":"https://api.github.com/repos/mumble-voip/mumble/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mumble-voip/mumble/pulls/2246/commits"},"statuses":{"href":"https://api.github.com/repos/mumble-voip/mumble/statuses/f6036ce6d123bd1ca3136a7b811703e1fd6d8a48"}}}}