{"action":"created","comment":{"url":"https://api.github.com/repos/src-d/style-analyzer/pulls/comments/225572401","pull_request_review_id":165195760,"id":225572401,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNTU3MjQwMQ==","diff_hunk":"@@ -0,0 +1,233 @@\n+\"\"\"Evaluate how well a given model is able to fix style mistakes randomly added in a repository.\"\"\"\n+from collections import defaultdict\n+from difflib import SequenceMatcher\n+import glob\n+from typing import Iterable, List, Mapping, NamedTuple, Set, Tuple\n+\n+from bblfsh import BblfshClient\n+import numpy\n+\n+from lookout.style.format.feature_extractor import FeatureExtractor\n+from lookout.style.format.feature_utils import VirtualNode\n+from lookout.style.format.files_filtering import filter_filepaths\n+from lookout.style.format.model import FormatModel\n+from lookout.style.format.quality_report import prepare_files\n+from lookout.style.format.rules import Rules\n+\n+\n+Misprediction = NamedTuple(\"Misprediction\", [(\"y\", numpy.ndarray), (\"pred\", numpy.ndarray),\n+                                             (\"node\", List[VirtualNode]), (\"rule\", numpy.ndarray)])\n+\n+\n+def get_content_from_repo(folder: str) -> Mapping[str, str]:\n+    \"\"\"\n+    Extract the content of the files given their path.\n+\n+    :param folder: Path to the files to get the content from.\n+    :return: Dictionary where the key is the path to a file and its value the content of the file.\n+    \"\"\"\n+    content = {}\n+    filenames = glob.glob(folder, recursive=True)\n+    for file in filter_filepaths(filenames):\n+        with open(file) as g:\n+            content[file] = g.read()\n+    return content\n+\n+\n+def get_difflib_changes(true_content: Mapping[str, str], noisy_content: Mapping[str, str]\n+                        ) -> Tuple[Iterable[str], Iterable[str], Mapping[str, Set[int]], int]:\n+    \"\"\"\n+    Return the files and lines that have been modified.\n+\n+    Given 2 contents of one repository (the original and its noisy version), returns the list files\n+    that have been modified, the lines that have changed.\n+\n+    :param true_content: Dictionary containing the content of the original repository.\n+    :param noisy_content: Dictionary containing the content of the noisy version of the repository.\n+    :return: The list of files where a style mistake has been added, and the mirror list of the\n+             original files, and the dictionary of the sets of lines modified by file.\n+             The number of lines that have been modified, must be equal to the number\n+             of modified files.\n+    \"\"\"\n+    true_files, noisy_files = set(), set()\n+    lines_changed = defaultdict(set)\n+    for (tf, tc), (nf, nc) in zip(true_content.items(), noisy_content.items()):\n+        matcher = SequenceMatcher(a=tc.splitlines(), b=nc.splitlines())\n+        for action, _, _, j1, j2 in matcher.get_opcodes():\n+            if action is not \"equal\":\n+                lines_changed[nf].update(range(j1, j2+1))\n+                true_files.add(tf)\n+                noisy_files.add(nf)\n+    return sorted(true_files), sorted(noisy_files), lines_changed\n+\n+\n+def files2vnodes(files: Iterable[str], rules: Rules, client: str, language: str\n+                 ) -> Iterable[VirtualNode]:\n+    \"\"\"\n+    Return the `VirtualNodes` extracted from a list of files.\n+\n+    :param files: List of files to get `Mispredictions` and `VirtualNodes` from.\n+    :param rules: rules of the style-analyzer model.\n+    :param client: Babelfish client. Babelfish server should be started accordingly.\n+    :param language: Language to consider, others will be discarded.\n+    :return: List of `VirtualNodes` extracted from a given list of files.\n+    \"\"\"\n+    files = prepare_files(files, client, language)\n+    fe = FeatureExtractor(language=language, **rules.origin_config[\"feature_extractor\"])\n+    X, y, vnodes_y, _ = fe.extract_features(files)\n+    return vnodes_y\n+\n+\n+def files2mispreds(files: Iterable[str], rules: Rules, client: str, language: str\n+                   ) -> Iterable[Misprediction]:\n+    \"\"\"\n+    Return the model's `Mispredictions` on a list of files.\n+\n+    :param files: List of files to get `Mispredictions` from.\n+    :param rules: rules of the style-analyzer model.\n+    :param client: Babelfish client. Babelfish server should be started accordingly.\n+    :param language: Language to consider, others will be discarded.\n+    :return: List of `Mispredictions` extracted from a given list of files.\n+    \"\"\"\n+    files = prepare_files(files, client, language)\n+    fe = FeatureExtractor(language=language, **rules.origin_config[\"feature_extractor\"])\n+    X, y, vnodes_y, _ = fe.extract_features(files)\n+    X, _ = fe.select_features(X, y)\n+    y_pred, winner = rules.predict(X, True)\n+    mispreds = get_mispreds(y, y_pred, vnodes_y, winner)\n+    return mispreds\n+\n+\n+def get_mispreds(y: numpy.ndarray, y_pred: numpy.ndarray, nodes: Iterable[VirtualNode],\n+                 winner: numpy.ndarray) -> Iterable[Misprediction]:\n+    \"\"\"\n+    Return the list of `Mispredictions` where the labels differ.\n+\n+    :param y: Numpy 1-dimensional array of labels.\n+    :param y_pred: Numpy 1-dimensional array of predicted labels by the model.\n+    :param nodes: List of `VirtualNodes`.\n+    :param winner: Numpy 1-dimensional array of the winning rule indices for each sample.\n+    :return: List of `Mispredictions` where the labels `y` and `y_pred` differ.\n+    \"\"\"\n+    mispreds = []\n+    for gt, pred, vn, rule in zip(y, y_pred, nodes, winner):\n+        if gt != pred:\n+            mispreds.append(Misprediction(gt, pred, vn, rule))\n+    return mispreds\n+\n+\n+def get_diff_mispreds(mispreds: Iterable[Misprediction], lines_changed: Mapping[str, Set[int]]\n+                      ) -> Mapping[str, Misprediction]:\n+    \"\"\"\n+    Filter `Mispredictions` to select those involving at least one line that has been modified.\n+\n+    :param mispreds: List of `Mispredictions` to filter.\n+    :param lines_changed: Dict of lines that have been changed when adding random noise.\n+    :return: Dictionary of the `Mispredictions` involving at least one line\n+             that has been modified when adding random noise.\n+    \"\"\"\n+    diff_mispreds = {}\n+    for m in mispreds:\n+        mispred_lines = set(range(m.node.start.line, m.node.end.line + 1))\n+        if set.intersection(mispred_lines, lines_changed[m.node.path]):\n+            try:\n+                if m.node.start.offset < diff_mispreds[m.node.path].node.start.offset:\n+                    diff_mispreds[m.node.path] = m\n+            except KeyError:\n+                diff_mispreds[m.node.path] = m\n+    return diff_mispreds\n+\n+\n+def get_style_fixes(mispreds: Mapping[str, Misprediction], vnodes: Iterable[VirtualNode],\n+                    true_files: Iterable[str], noisy_files: Iterable[str]\n+                    ) -> Iterable[Misprediction]:\n+    \"\"\"\n+    Return `Mispredictions` that fix the style mistakes added.\n+\n+    Given a list of `Mispredictions` potentially fixing a style mistake added since involving\n+    at least one line that has been modified, return the list of `Mispredicitons` really fixing\n+    that mistake because their prediction on the noisy files would match the ground truth\n+    labels of the original files.\n+\n+    :param mispreds: Dictionary of `Mispredictions` potentially fixing a style mistake.\n+    :param vnodes: List of `VirtualNodes` extracted from the list of `true_files`.\n+    :param true_files: list of files of the original repos where a style mistake has been added.\n+    :param noisy_files: list of files from the noisy repos where a modification has been made\n+    :return: List of `Mispredictions` where the prediction on a noisy file matches the ground truth\n+             label of the original file i.e. `Mispredictions` actually fixing the mistakes added.\n+    \"\"\"\n+    style_fixes = []\n+    for true_file, noisy_file in zip(true_files, noisy_files):\n+        try:\n+            mispred = mispreds[noisy_file]\n+        except KeyError:\n+            continue\n+        for vn in vnodes:\n+            if vn.path == true_file and vn.start.offset == mispred.node.start.offset:\n+                if mispred.pred == vn.y:\n+                    style_fixes.append(mispred)\n+                break\n+    return style_fixes\n+\n+\n+def style_robustness_report(true_repo: str, noisy_repo: str, bblfsh: str, language: str,\n+                            model_path: str) -> None:\n+    \"\"\"\n+    Print the quality report of a model tested on a given repository.\n+\n+    The tests consists in adding random style mistakes in the given repo and looking how well\n+    the model is able to fix them according to the style of the original repository.\n+\n+    :param true_repo: Path to the original repository we want to test the model on.\n+    :param noisy_repo: Path to the noisy version of the repository where 1 style mistake is\n+           randomly added in every file.\n+    :param bblfsh: Babelfish client. Babelfish server should be started accordingly.\n+    :param language: Language to consider, others will be discarded.\n+    :param model_path: Path to the model to test. It should be previously trained on the original\n+           repository located in ':param true_repo:'.\n+    \"\"\"\n+    client = BblfshClient(bblfsh)\n+\n+    true_content = get_content_from_repo(true_repo)\n+    noisy_content = get_content_from_repo(noisy_repo)\n+    print(\"len true content :\", len(true_content))\n+    true_files, noisy_files, lines_changed = get_difflib_changes(true_content, noisy_content)\n+\n+    print()\n+    print(\"Number of files modified by adding style noise : %d / %d\"\n+          % (len(true_files), len(true_content)))\n+    del true_content, noisy_content\n+\n+    analyzer = FormatModel().load(model_path)\n+    rules = analyzer[language]\n+\n+    vnodes_y_true = files2vnodes(true_files, rules, client, language)\n+    mispreds_noise = files2mispreds(noisy_files, rules, client, language)\n+\n+    diff_mispreds = get_diff_mispreds(mispreds_noise, lines_changed)\n+    changes_count = len(lines_changed)\n+    print(\"Number of artificial mistakes potentially fixed by the model\"\n+          \"(diff of mispredictions): %d / %d\" % (len(diff_mispreds), changes_count))\n+\n+    style_fixes = get_style_fixes(diff_mispreds, vnodes_y_true, true_files, noisy_files)\n+\n+    print(\"style-analyzer fixes in the noisy repos : %d / %d -> %.1f %%\"","path":"lookout/style/format/robustness.py","position":214,"original_position":214,"commit_id":"71717ca742a022fc50c8c25088d31efb97e0b4f3","original_commit_id":"71717ca742a022fc50c8c25088d31efb97e0b4f3","user":{"login":"vmarkovtsev","id":2793551,"node_id":"MDQ6VXNlcjI3OTM1NTE=","avatar_url":"https://avatars3.githubusercontent.com/u/2793551?v=4","gravatar_id":"","url":"https://api.github.com/users/vmarkovtsev","html_url":"https://github.com/vmarkovtsev","followers_url":"https://api.github.com/users/vmarkovtsev/followers","following_url":"https://api.github.com/users/vmarkovtsev/following{/other_user}","gists_url":"https://api.github.com/users/vmarkovtsev/gists{/gist_id}","starred_url":"https://api.github.com/users/vmarkovtsev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vmarkovtsev/subscriptions","organizations_url":"https://api.github.com/users/vmarkovtsev/orgs","repos_url":"https://api.github.com/users/vmarkovtsev/repos","events_url":"https://api.github.com/users/vmarkovtsev/events{/privacy}","received_events_url":"https://api.github.com/users/vmarkovtsev/received_events","type":"User","site_admin":false},"body":"`repos:`","created_at":"2018-10-16T14:46:13Z","updated_at":"2018-10-16T14:48:07Z","html_url":"https://github.com/src-d/style-analyzer/pull/218#discussion_r225572401","pull_request_url":"https://api.github.com/repos/src-d/style-analyzer/pulls/218","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/src-d/style-analyzer/pulls/comments/225572401"},"html":{"href":"https://github.com/src-d/style-analyzer/pull/218#discussion_r225572401"},"pull_request":{"href":"https://api.github.com/repos/src-d/style-analyzer/pulls/218"}}},"pull_request":{"url":"https://api.github.com/repos/src-d/style-analyzer/pulls/218","id":221363028,"node_id":"MDExOlB1bGxSZXF1ZXN0MjIxMzYzMDI4","html_url":"https://github.com/src-d/style-analyzer/pull/218","diff_url":"https://github.com/src-d/style-analyzer/pull/218.diff","patch_url":"https://github.com/src-d/style-analyzer/pull/218.patch","issue_url":"https://api.github.com/repos/src-d/style-analyzer/issues/218","number":218,"state":"open","locked":false,"title":"Add new quality metric based on the model's ability to fix random style noise","user":{"login":"warenlg","id":24694845,"node_id":"MDQ6VXNlcjI0Njk0ODQ1","avatar_url":"https://avatars2.githubusercontent.com/u/24694845?v=4","gravatar_id":"","url":"https://api.github.com/users/warenlg","html_url":"https://github.com/warenlg","followers_url":"https://api.github.com/users/warenlg/followers","following_url":"https://api.github.com/users/warenlg/following{/other_user}","gists_url":"https://api.github.com/users/warenlg/gists{/gist_id}","starred_url":"https://api.github.com/users/warenlg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/warenlg/subscriptions","organizations_url":"https://api.github.com/users/warenlg/orgs","repos_url":"https://api.github.com/users/warenlg/repos","events_url":"https://api.github.com/users/warenlg/events{/privacy}","received_events_url":"https://api.github.com/users/warenlg/received_events","type":"User","site_admin":false},"body":"Related issue https://github.com/src-d/style-analyzer/issues/163","created_at":"2018-10-09T09:15:02Z","updated_at":"2018-10-16T14:48:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2dea1e80733ab17b879b0a6680f1922a65ca08b2","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/src-d/style-analyzer/pulls/218/commits","review_comments_url":"https://api.github.com/repos/src-d/style-analyzer/pulls/218/comments","review_comment_url":"https://api.github.com/repos/src-d/style-analyzer/pulls/comments{/number}","comments_url":"https://api.github.com/repos/src-d/style-analyzer/issues/218/comments","statuses_url":"https://api.github.com/repos/src-d/style-analyzer/statuses/71717ca742a022fc50c8c25088d31efb97e0b4f3","head":{"label":"warenlg:style_robustness","ref":"style_robustness","sha":"71717ca742a022fc50c8c25088d31efb97e0b4f3","user":{"login":"warenlg","id":24694845,"node_id":"MDQ6VXNlcjI0Njk0ODQ1","avatar_url":"https://avatars2.githubusercontent.com/u/24694845?v=4","gravatar_id":"","url":"https://api.github.com/users/warenlg","html_url":"https://github.com/warenlg","followers_url":"https://api.github.com/users/warenlg/followers","following_url":"https://api.github.com/users/warenlg/following{/other_user}","gists_url":"https://api.github.com/users/warenlg/gists{/gist_id}","starred_url":"https://api.github.com/users/warenlg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/warenlg/subscriptions","organizations_url":"https://api.github.com/users/warenlg/orgs","repos_url":"https://api.github.com/users/warenlg/repos","events_url":"https://api.github.com/users/warenlg/events{/privacy}","received_events_url":"https://api.github.com/users/warenlg/received_events","type":"User","site_admin":false},"repo":{"id":142890109,"node_id":"MDEwOlJlcG9zaXRvcnkxNDI4OTAxMDk=","name":"style-analyzer","full_name":"warenlg/style-analyzer","private":false,"owner":{"login":"warenlg","id":24694845,"node_id":"MDQ6VXNlcjI0Njk0ODQ1","avatar_url":"https://avatars2.githubusercontent.com/u/24694845?v=4","gravatar_id":"","url":"https://api.github.com/users/warenlg","html_url":"https://github.com/warenlg","followers_url":"https://api.github.com/users/warenlg/followers","following_url":"https://api.github.com/users/warenlg/following{/other_user}","gists_url":"https://api.github.com/users/warenlg/gists{/gist_id}","starred_url":"https://api.github.com/users/warenlg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/warenlg/subscriptions","organizations_url":"https://api.github.com/users/warenlg/orgs","repos_url":"https://api.github.com/users/warenlg/repos","events_url":"https://api.github.com/users/warenlg/events{/privacy}","received_events_url":"https://api.github.com/users/warenlg/received_events","type":"User","site_admin":false},"html_url":"https://github.com/warenlg/style-analyzer","description":"Style analyzer experiments","fork":true,"url":"https://api.github.com/repos/warenlg/style-analyzer","forks_url":"https://api.github.com/repos/warenlg/style-analyzer/forks","keys_url":"https://api.github.com/repos/warenlg/style-analyzer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/warenlg/style-analyzer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/warenlg/style-analyzer/teams","hooks_url":"https://api.github.com/repos/warenlg/style-analyzer/hooks","issue_events_url":"https://api.github.com/repos/warenlg/style-analyzer/issues/events{/number}","events_url":"https://api.github.com/repos/warenlg/style-analyzer/events","assignees_url":"https://api.github.com/repos/warenlg/style-analyzer/assignees{/user}","branches_url":"https://api.github.com/repos/warenlg/style-analyzer/branches{/branch}","tags_url":"https://api.github.com/repos/warenlg/style-analyzer/tags","blobs_url":"https://api.github.com/repos/warenlg/style-analyzer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/warenlg/style-analyzer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/warenlg/style-analyzer/git/refs{/sha}","trees_url":"https://api.github.com/repos/warenlg/style-analyzer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/warenlg/style-analyzer/statuses/{sha}","languages_url":"https://api.github.com/repos/warenlg/style-analyzer/languages","stargazers_url":"https://api.github.com/repos/warenlg/style-analyzer/stargazers","contributors_url":"https://api.github.com/repos/warenlg/style-analyzer/contributors","subscribers_url":"https://api.github.com/repos/warenlg/style-analyzer/subscribers","subscription_url":"https://api.github.com/repos/warenlg/style-analyzer/subscription","commits_url":"https://api.github.com/repos/warenlg/style-analyzer/commits{/sha}","git_commits_url":"https://api.github.com/repos/warenlg/style-analyzer/git/commits{/sha}","comments_url":"https://api.github.com/repos/warenlg/style-analyzer/comments{/number}","issue_comment_url":"https://api.github.com/repos/warenlg/style-analyzer/issues/comments{/number}","contents_url":"https://api.github.com/repos/warenlg/style-analyzer/contents/{+path}","compare_url":"https://api.github.com/repos/warenlg/style-analyzer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/warenlg/style-analyzer/merges","archive_url":"https://api.github.com/repos/warenlg/style-analyzer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/warenlg/style-analyzer/downloads","issues_url":"https://api.github.com/repos/warenlg/style-analyzer/issues{/number}","pulls_url":"https://api.github.com/repos/warenlg/style-analyzer/pulls{/number}","milestones_url":"https://api.github.com/repos/warenlg/style-analyzer/milestones{/number}","notifications_url":"https://api.github.com/repos/warenlg/style-analyzer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/warenlg/style-analyzer/labels{/name}","releases_url":"https://api.github.com/repos/warenlg/style-analyzer/releases{/id}","deployments_url":"https://api.github.com/repos/warenlg/style-analyzer/deployments","created_at":"2018-07-30T14:52:55Z","updated_at":"2018-10-08T13:47:03Z","pushed_at":"2018-10-13T08:02:36Z","git_url":"git://github.com/warenlg/style-analyzer.git","ssh_url":"git@github.com:warenlg/style-analyzer.git","clone_url":"https://github.com/warenlg/style-analyzer.git","svn_url":"https://github.com/warenlg/style-analyzer","homepage":null,"size":15787,"stargazers_count":0,"watchers_count":0,"language":"Jupyter Notebook","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"src-d:master","ref":"master","sha":"44434a93a61a298ec3162198321e5f2b951cfe83","user":{"login":"src-d","id":15128793,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1MTI4Nzkz","avatar_url":"https://avatars2.githubusercontent.com/u/15128793?v=4","gravatar_id":"","url":"https://api.github.com/users/src-d","html_url":"https://github.com/src-d","followers_url":"https://api.github.com/users/src-d/followers","following_url":"https://api.github.com/users/src-d/following{/other_user}","gists_url":"https://api.github.com/users/src-d/gists{/gist_id}","starred_url":"https://api.github.com/users/src-d/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/src-d/subscriptions","organizations_url":"https://api.github.com/users/src-d/orgs","repos_url":"https://api.github.com/users/src-d/repos","events_url":"https://api.github.com/users/src-d/events{/privacy}","received_events_url":"https://api.github.com/users/src-d/received_events","type":"Organization","site_admin":false},"repo":{"id":139746338,"node_id":"MDEwOlJlcG9zaXRvcnkxMzk3NDYzMzg=","name":"style-analyzer","full_name":"src-d/style-analyzer","private":false,"owner":{"login":"src-d","id":15128793,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1MTI4Nzkz","avatar_url":"https://avatars2.githubusercontent.com/u/15128793?v=4","gravatar_id":"","url":"https://api.github.com/users/src-d","html_url":"https://github.com/src-d","followers_url":"https://api.github.com/users/src-d/followers","following_url":"https://api.github.com/users/src-d/following{/other_user}","gists_url":"https://api.github.com/users/src-d/gists{/gist_id}","starred_url":"https://api.github.com/users/src-d/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/src-d/subscriptions","organizations_url":"https://api.github.com/users/src-d/orgs","repos_url":"https://api.github.com/users/src-d/repos","events_url":"https://api.github.com/users/src-d/events{/privacy}","received_events_url":"https://api.github.com/users/src-d/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/src-d/style-analyzer","description":"Style analyzer experiments","fork":false,"url":"https://api.github.com/repos/src-d/style-analyzer","forks_url":"https://api.github.com/repos/src-d/style-analyzer/forks","keys_url":"https://api.github.com/repos/src-d/style-analyzer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/src-d/style-analyzer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/src-d/style-analyzer/teams","hooks_url":"https://api.github.com/repos/src-d/style-analyzer/hooks","issue_events_url":"https://api.github.com/repos/src-d/style-analyzer/issues/events{/number}","events_url":"https://api.github.com/repos/src-d/style-analyzer/events","assignees_url":"https://api.github.com/repos/src-d/style-analyzer/assignees{/user}","branches_url":"https://api.github.com/repos/src-d/style-analyzer/branches{/branch}","tags_url":"https://api.github.com/repos/src-d/style-analyzer/tags","blobs_url":"https://api.github.com/repos/src-d/style-analyzer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/src-d/style-analyzer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/src-d/style-analyzer/git/refs{/sha}","trees_url":"https://api.github.com/repos/src-d/style-analyzer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/src-d/style-analyzer/statuses/{sha}","languages_url":"https://api.github.com/repos/src-d/style-analyzer/languages","stargazers_url":"https://api.github.com/repos/src-d/style-analyzer/stargazers","contributors_url":"https://api.github.com/repos/src-d/style-analyzer/contributors","subscribers_url":"https://api.github.com/repos/src-d/style-analyzer/subscribers","subscription_url":"https://api.github.com/repos/src-d/style-analyzer/subscription","commits_url":"https://api.github.com/repos/src-d/style-analyzer/commits{/sha}","git_commits_url":"https://api.github.com/repos/src-d/style-analyzer/git/commits{/sha}","comments_url":"https://api.github.com/repos/src-d/style-analyzer/comments{/number}","issue_comment_url":"https://api.github.com/repos/src-d/style-analyzer/issues/comments{/number}","contents_url":"https://api.github.com/repos/src-d/style-analyzer/contents/{+path}","compare_url":"https://api.github.com/repos/src-d/style-analyzer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/src-d/style-analyzer/merges","archive_url":"https://api.github.com/repos/src-d/style-analyzer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/src-d/style-analyzer/downloads","issues_url":"https://api.github.com/repos/src-d/style-analyzer/issues{/number}","pulls_url":"https://api.github.com/repos/src-d/style-analyzer/pulls{/number}","milestones_url":"https://api.github.com/repos/src-d/style-analyzer/milestones{/number}","notifications_url":"https://api.github.com/repos/src-d/style-analyzer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/src-d/style-analyzer/labels{/name}","releases_url":"https://api.github.com/repos/src-d/style-analyzer/releases{/id}","deployments_url":"https://api.github.com/repos/src-d/style-analyzer/deployments","created_at":"2018-07-04T16:42:30Z","updated_at":"2018-10-16T08:09:27Z","pushed_at":"2018-10-16T14:24:07Z","git_url":"git://github.com/src-d/style-analyzer.git","ssh_url":"git@github.com:src-d/style-analyzer.git","clone_url":"https://github.com/src-d/style-analyzer.git","svn_url":"https://github.com/src-d/style-analyzer","homepage":null,"size":64243,"stargazers_count":5,"watchers_count":5,"language":"Jupyter Notebook","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"archived":false,"open_issues_count":28,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":10,"open_issues":28,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/src-d/style-analyzer/pulls/218"},"html":{"href":"https://github.com/src-d/style-analyzer/pull/218"},"issue":{"href":"https://api.github.com/repos/src-d/style-analyzer/issues/218"},"comments":{"href":"https://api.github.com/repos/src-d/style-analyzer/issues/218/comments"},"review_comments":{"href":"https://api.github.com/repos/src-d/style-analyzer/pulls/218/comments"},"review_comment":{"href":"https://api.github.com/repos/src-d/style-analyzer/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/src-d/style-analyzer/pulls/218/commits"},"statuses":{"href":"https://api.github.com/repos/src-d/style-analyzer/statuses/71717ca742a022fc50c8c25088d31efb97e0b4f3"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"vmarkovtsev"}}