{"action":"created","comment":{"url":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/comments/28614291","id":28614291,"diff_hunk":"@@ -0,0 +1,403 @@\n+/* This Source Code Form is subject to the terms of the Mozilla Public\n+ * License, v. 2.0. If a copy of the MPL was not distributed with this\n+ * file, you can obtain one at http://mozilla.org/MPL/2.0/. */\n+\n+\"use strict\";\n+\n+\n+// -------------------------------------------------------------------------\n+// Utility Functions\n+// -------------------------------------------------------------------------\n+\n+\n+/**\n+ * Compute the standard deviation for an array of values.\n+ * \n+ * @param values\n+ *        An array of numbers.\n+ * @param avg\n+ *        Average of the values.\n+ * @return a number (the standard deviation)\n+ */\n+function stddev(values, avg) {\n+  if (values.length <= 1) {\n+    return 0;\n+  }\n+\n+  return Math.sqrt(\n+    values.map(function (v) { return Math.pow(v - avg, 2); })\n+          .reduce(function (a, b) { return a + b; }) / (values.length - 1));\n+}\n+\n+\n+// -------------------------------------------------------------------------\n+// End Utility Functions\n+// -------------------------------------------------------------------------\n+\n+\n+var compare = angular.module(\"compare\", ['ui.router', 'ui.bootstrap', 'treeherder']);\n+\n+//TODO: make getSeriesSummary part of a common library\n+compare.factory('getSeriesSummary', [ function() {\n+  return function(signature, signatureProps, optionCollectionMap, pgo, e10s) {\n+    var platform = signatureProps.machine_platform + \" \" +\n+      signatureProps.machine_architecture;\n+    var extra = \"\";\n+    if (signatureProps.job_group_symbol === \"T-e10s\") {\n+      extra = \" e10s\";\n+    }\n+    var testName = signatureProps.test;\n+    var subtestSignatures;\n+    if (testName === undefined) {\n+      testName = \"summary\";\n+      subtestSignatures = signatureProps.subtest_signatures;\n+    }\n+    var name = signatureProps.suite + \" \" + testName +\n+      \" \" + optionCollectionMap[signatureProps.option_collection_hash] + extra;\n+\n+    //Only keep summary signatures, filter in/out e10s and pgo\n+    if (name.indexOf('summary') <= 0) {\n+        return null;\n+    }\n+    if (e10s && (name.indexOf('e10s') <= 0)) {\n+        return null;\n+    } else if (!e10s && (name.indexOf('e10s') > 0)) {\n+        return null;\n+    }\n+\n+    //TODO: pgo is linux/windows only- what about osx and android\n+    if (pgo && (name.indexOf('pgo') <= 1)) {\n+        return null;\n+    } else if (!pgo && (name.indexOf('pgo') > 0)) {\n+        return null;\n+    }\n+\n+    return { name: name, signature: signature, platform: platform,\n+             subtestSignatures: subtestSignatures };\n+  };\n+}]);\n+\n+compare.controller('CompareCtrl', [ '$state', '$stateParams', '$scope', '$rootScope', '$location',\n+                              'thServiceDomain', '$http', '$q', '$timeout', 'getSeriesSummary',\n+  function CompareCtrl($state, $stateParams, $scope, $rootScope, $location,\n+                    thServiceDomain, $http, $q, $timeout, getSeriesSummary) {\n+\n+    function displayComparision() {\n+      //TODO: determine the dates of the two revisions and only grab what we need\n+      $scope.timeRange = 2592000; // last 30 days\n+      $scope.testList = [];\n+      $scope.platformList = [];\n+\n+      var signatureURL = thServiceDomain + '/api/project/' + $scope.originalProject + \n+          '/performance-data/0/get_performance_series_summary/?interval=' +\n+          $scope.timeRange;\n+\n+      $http.get(signatureURL).then(\n+        function(response) {\n+          var seriesList = [];\n+\n+          Object.keys(response.data).forEach(function(signature) {\n+            var seriesSummary = getSeriesSummary(signature,\n+                                                 response.data[signature],\n+                                                 optionCollectionMap,\n+                                                 $stateParams.pgo,\n+                                                 $stateParams.e10s);\n+\n+            if (seriesSummary != null && seriesSummary.signature !== undefined) {\n+              seriesList.push(seriesSummary);\n+\n+              if ($scope.platformList.indexOf(seriesSummary.platform) === -1) {\n+                $scope.platformList.push(seriesSummary.platform);\n+              }\n+\n+              if ($scope.testList.indexOf(seriesSummary.name) === -1) {\n+                $scope.testList.push(seriesSummary.name);\n+              }\n+            }\n+          });\n+\n+          // find summary results for all tests/platforms for the original rev\n+          var signatureURL = thServiceDomain + '/api/project/' +\n+              $scope.originalProject + '/performance-data/0/' +\n+              'get_performance_data/?interval_seconds=' + $scope.timeRange;\n+\n+          // TODO: figure how how to reduce these maps\n+          var rawResultsMap = {};\n+\n+          $q.all(seriesList.map(function(series) {\n+            return $http.get(signatureURL + \"&signatures=\" + series.signature).then(function(response) {\n+              response.data.forEach(function(data) {\n+                rawResultsMap[data.series_signature] = calculateStats(data.blob, $scope.originalResultSetID);\n+                rawResultsMap[data.series_signature].name = series.name;\n+                rawResultsMap[data.series_signature].platform = series.platform;\n+              });\n+            });\n+          })).then(function () {\n+\n+            // find summary results for all tests/platforms for the original rev\n+            var signatureURL = thServiceDomain + '/api/project/' +\n+                           $scope.newProject + '/performance-data/0/' +\n+                           'get_performance_data/?interval_seconds=' + $scope.timeRange;\n+\n+            //ok, now get the new revision\n+            var signatureListURL = thServiceDomain + '/api/project/' + $scope.newProject + \n+              '/performance-data/0/get_performance_series_summary/?interval=' +\n+              $scope.timeRange;\n+\n+            var newRawResultsMap = {};\n+            var newSeriesList = [];\n+\n+\n+            $http.get(signatureListURL).then(function(response) {\n+              Object.keys(response.data).forEach(function(signature) {\n+                var seriesSummary = getSeriesSummary(signature,\n+                                                     response.data[signature],\n+                                                     optionCollectionMap,\n+                                                     $stateParams.pgo,\n+                                                     $stateParams.e10s);\n+\n+                if (seriesSummary != null && seriesSummary.signature !== undefined) {\n+                  newSeriesList.push(seriesSummary);\n+\n+                  if ($scope.platformList.indexOf(seriesSummary.platform) === -1) {\n+                    $scope.platformList.push(seriesSummary.platform);\n+                  }\n+\n+                  if ($scope.testList.indexOf(seriesSummary.name) === -1) {\n+                    $scope.testList.push(seriesSummary.name);\n+                  }\n+                }\n+              });\n+              $scope.testList.sort();\n+              $scope.platformList.sort();\n+\n+\n+              $q.all(newSeriesList.map(function(series) {\n+                return $http.get(signatureURL + \"&signatures=\" + series.signature).then(function(response) {\n+                  response.data.forEach(function(data) {\n+                    newRawResultsMap[data.series_signature] = calculateStats(data.blob, $scope.newResultSetID);\n+                    newRawResultsMap[data.series_signature].name = series.name;\n+                    newRawResultsMap[data.series_signature].platform = series.platform;\n+                  });\n+                });\n+              })).then(function () {\n+                $scope.dataLoading = false;\n+                displayResults(rawResultsMap, newRawResultsMap);\n+              });\n+            });\n+          });\n+        }\n+      );\n+    }\n+\n+    //TODO: put this into a generic library\n+    function calculateStats(perfData, resultSetID) {\n+      var geomeans = [];\n+      var total = 0;\n+      perfData.forEach(function(pdata) {\n+        if (pdata.result_set_id === resultSetID) {\n+          geomeans.push(pdata.geomean);\n+          total += pdata.geomean;\n+        }\n+      });\n+\n+      var avg = total / geomeans.length;\n+      var sigma = stddev(geomeans, avg);\n+      return {'geomean': avg.toFixed(2), 'stddev': sigma.toFixed(2), 'runs': geomeans.length};\n+    }\n+\n+    //TODO: put this into a generic library\n+    function isReverseTest(testName) {\n+      var reverseTests = ['dromaeo_dom', 'dromaeo_css', 'v8_7', 'canvasmark'];\n+      var found = false;\n+      reverseTests.forEach(function(rt) {\n+        if (testName.indexOf(rt) >= 0) {\n+          found = true;\n+        }\n+      });\n+      return found;\n+    }\n+\n+    function displayResults(rawResultsMap, newRawResultsMap) {\n+      var counter = 0;\n+      var compareResultsMap = {};\n+\n+      $scope.testList.forEach(function(testName) {\n+        if (counter > 0 && compareResultsMap[(counter-1)].headerColumns==2) {\n+          counter--;\n+        }\n+\n+        //TODO: figure out a cleaner method for making the names a header row\n+        compareResultsMap[counter++] = {'name': testName.replace(' summary', ''),\n+                                        'isEmpty': true, 'isMinor': false, 'headerColumns': 2,\n+                                        'originalGeoMean': 'Old Rev', 'originalStddev': 'StdDev',\n+                                        'newGeoMean': 'New Rev', 'newStddev': 'StdDev',\n+                                        'delta': 'Delta', 'deltaPercentage': 'Delta'};\n+\n+\n+        $scope.platformList.forEach(function(platform) {\n+          var cmap = {'originalGeoMean': NaN, 'originalRuns': 0, 'originalStddev': NaN,\n+                      'newGeoMean': NaN, 'newRuns': 0, 'newStddev': NaN, 'headerColumns': 1,\n+                      'delta': NaN, 'deltaPercentage': NaN, 'isEmpty': false,\n+                      'isRegression': false, 'isImprovement': false, 'isMinor': true};\n+\n+          var oldSig = _.find(Object.keys(rawResultsMap), function (sig) {\n+            return (rawResultsMap[sig].name == testName && rawResultsMap[sig].platform == platform)});\n+          var newSig = _.find(Object.keys(newRawResultsMap), function (sig) {\n+            return (newRawResultsMap[sig].name == testName && newRawResultsMap[sig].platform == platform)});\n+\n+          if (oldSig !== undefined) {","path":"webapp/app/js/compare.js","position":249,"original_position":249,"commit_id":"a0bfa78759692118ec45eb40b750bdf227f2f426","original_commit_id":"a0bfa78759692118ec45eb40b750bdf227f2f426","user":{"login":"wlach","id":20569,"avatar_url":"https://avatars.githubusercontent.com/u/20569?v=3","gravatar_id":"","url":"https://api.github.com/users/wlach","html_url":"https://github.com/wlach","followers_url":"https://api.github.com/users/wlach/followers","following_url":"https://api.github.com/users/wlach/following{/other_user}","gists_url":"https://api.github.com/users/wlach/gists{/gist_id}","starred_url":"https://api.github.com/users/wlach/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wlach/subscriptions","organizations_url":"https://api.github.com/users/wlach/orgs","repos_url":"https://api.github.com/users/wlach/repos","events_url":"https://api.github.com/users/wlach/events{/privacy}","received_events_url":"https://api.github.com/users/wlach/received_events","type":"User","site_admin":false},"body":"!== undefined isn't necessary, I don't think","created_at":"2015-04-17T17:40:12Z","updated_at":"2015-04-17T17:40:12Z","html_url":"https://github.com/mozilla/treeherder-ui/pull/465#discussion_r28614291","pull_request_url":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/465","_links":{"self":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/comments/28614291"},"html":{"href":"https://github.com/mozilla/treeherder-ui/pull/465#discussion_r28614291"},"pull_request":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/465"}}},"pull_request":{"url":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/465","id":33263124,"html_url":"https://github.com/mozilla/treeherder-ui/pull/465","diff_url":"https://github.com/mozilla/treeherder-ui/pull/465.diff","patch_url":"https://github.com/mozilla/treeherder-ui/pull/465.patch","issue_url":"https://api.github.com/repos/mozilla/treeherder-ui/issues/465","number":465,"state":"open","locked":false,"title":"initial work to get compare-talos stood up inside of perfherder","user":{"login":"jmaher","id":62588,"avatar_url":"https://avatars.githubusercontent.com/u/62588?v=3","gravatar_id":"","url":"https://api.github.com/users/jmaher","html_url":"https://github.com/jmaher","followers_url":"https://api.github.com/users/jmaher/followers","following_url":"https://api.github.com/users/jmaher/following{/other_user}","gists_url":"https://api.github.com/users/jmaher/gists{/gist_id}","starred_url":"https://api.github.com/users/jmaher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jmaher/subscriptions","organizations_url":"https://api.github.com/users/jmaher/orgs","repos_url":"https://api.github.com/users/jmaher/repos","events_url":"https://api.github.com/users/jmaher/events{/privacy}","received_events_url":"https://api.github.com/users/jmaher/received_events","type":"User","site_admin":false},"body":"first round attempt.\n\n<!-- Reviewable:start -->\n[<img src=\"https://reviewable.io/review_button.png\" height=40 alt=\"Review on Reviewable\"/>](https://reviewable.io/reviews/mozilla/treeherder-ui/465)\n<!-- Reviewable:end -->\n","created_at":"2015-04-14T14:32:57Z","updated_at":"2015-04-17T17:40:12Z","closed_at":null,"merged_at":null,"merge_commit_sha":"33901ea5e07884cd4871f097230bbf1af8ddeafb","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/465/commits","review_comments_url":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/465/comments","review_comment_url":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mozilla/treeherder-ui/issues/465/comments","statuses_url":"https://api.github.com/repos/mozilla/treeherder-ui/statuses/a0bfa78759692118ec45eb40b750bdf227f2f426","head":{"label":"jmaher:master","ref":"master","sha":"a0bfa78759692118ec45eb40b750bdf227f2f426","user":{"login":"jmaher","id":62588,"avatar_url":"https://avatars.githubusercontent.com/u/62588?v=3","gravatar_id":"","url":"https://api.github.com/users/jmaher","html_url":"https://github.com/jmaher","followers_url":"https://api.github.com/users/jmaher/followers","following_url":"https://api.github.com/users/jmaher/following{/other_user}","gists_url":"https://api.github.com/users/jmaher/gists{/gist_id}","starred_url":"https://api.github.com/users/jmaher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jmaher/subscriptions","organizations_url":"https://api.github.com/users/jmaher/orgs","repos_url":"https://api.github.com/users/jmaher/repos","events_url":"https://api.github.com/users/jmaher/events{/privacy}","received_events_url":"https://api.github.com/users/jmaher/received_events","type":"User","site_admin":false},"repo":{"id":33500682,"name":"treeherder-ui","full_name":"jmaher/treeherder-ui","owner":{"login":"jmaher","id":62588,"avatar_url":"https://avatars.githubusercontent.com/u/62588?v=3","gravatar_id":"","url":"https://api.github.com/users/jmaher","html_url":"https://github.com/jmaher","followers_url":"https://api.github.com/users/jmaher/followers","following_url":"https://api.github.com/users/jmaher/following{/other_user}","gists_url":"https://api.github.com/users/jmaher/gists{/gist_id}","starred_url":"https://api.github.com/users/jmaher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jmaher/subscriptions","organizations_url":"https://api.github.com/users/jmaher/orgs","repos_url":"https://api.github.com/users/jmaher/repos","events_url":"https://api.github.com/users/jmaher/events{/privacy}","received_events_url":"https://api.github.com/users/jmaher/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jmaher/treeherder-ui","description":"The UI for treeherder, a replacement for TBPL. See wiki page for where to file bugs.","fork":true,"url":"https://api.github.com/repos/jmaher/treeherder-ui","forks_url":"https://api.github.com/repos/jmaher/treeherder-ui/forks","keys_url":"https://api.github.com/repos/jmaher/treeherder-ui/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jmaher/treeherder-ui/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jmaher/treeherder-ui/teams","hooks_url":"https://api.github.com/repos/jmaher/treeherder-ui/hooks","issue_events_url":"https://api.github.com/repos/jmaher/treeherder-ui/issues/events{/number}","events_url":"https://api.github.com/repos/jmaher/treeherder-ui/events","assignees_url":"https://api.github.com/repos/jmaher/treeherder-ui/assignees{/user}","branches_url":"https://api.github.com/repos/jmaher/treeherder-ui/branches{/branch}","tags_url":"https://api.github.com/repos/jmaher/treeherder-ui/tags","blobs_url":"https://api.github.com/repos/jmaher/treeherder-ui/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jmaher/treeherder-ui/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jmaher/treeherder-ui/git/refs{/sha}","trees_url":"https://api.github.com/repos/jmaher/treeherder-ui/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jmaher/treeherder-ui/statuses/{sha}","languages_url":"https://api.github.com/repos/jmaher/treeherder-ui/languages","stargazers_url":"https://api.github.com/repos/jmaher/treeherder-ui/stargazers","contributors_url":"https://api.github.com/repos/jmaher/treeherder-ui/contributors","subscribers_url":"https://api.github.com/repos/jmaher/treeherder-ui/subscribers","subscription_url":"https://api.github.com/repos/jmaher/treeherder-ui/subscription","commits_url":"https://api.github.com/repos/jmaher/treeherder-ui/commits{/sha}","git_commits_url":"https://api.github.com/repos/jmaher/treeherder-ui/git/commits{/sha}","comments_url":"https://api.github.com/repos/jmaher/treeherder-ui/comments{/number}","issue_comment_url":"https://api.github.com/repos/jmaher/treeherder-ui/issues/comments{/number}","contents_url":"https://api.github.com/repos/jmaher/treeherder-ui/contents/{+path}","compare_url":"https://api.github.com/repos/jmaher/treeherder-ui/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jmaher/treeherder-ui/merges","archive_url":"https://api.github.com/repos/jmaher/treeherder-ui/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jmaher/treeherder-ui/downloads","issues_url":"https://api.github.com/repos/jmaher/treeherder-ui/issues{/number}","pulls_url":"https://api.github.com/repos/jmaher/treeherder-ui/pulls{/number}","milestones_url":"https://api.github.com/repos/jmaher/treeherder-ui/milestones{/number}","notifications_url":"https://api.github.com/repos/jmaher/treeherder-ui/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jmaher/treeherder-ui/labels{/name}","releases_url":"https://api.github.com/repos/jmaher/treeherder-ui/releases{/id}","created_at":"2015-04-06T19:22:22Z","updated_at":"2015-04-17T15:58:07Z","pushed_at":"2015-04-17T15:58:07Z","git_url":"git://github.com/jmaher/treeherder-ui.git","ssh_url":"git@github.com:jmaher/treeherder-ui.git","clone_url":"https://github.com/jmaher/treeherder-ui.git","svn_url":"https://github.com/jmaher/treeherder-ui","homepage":"https://wiki.mozilla.org/Auto-tools/Projects/Treeherder","size":12506,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"mozilla:master","ref":"master","sha":"2f4e0ce393b06966a919f5221036a95dc76e6c59","user":{"login":"mozilla","id":131524,"avatar_url":"https://avatars.githubusercontent.com/u/131524?v=3","gravatar_id":"","url":"https://api.github.com/users/mozilla","html_url":"https://github.com/mozilla","followers_url":"https://api.github.com/users/mozilla/followers","following_url":"https://api.github.com/users/mozilla/following{/other_user}","gists_url":"https://api.github.com/users/mozilla/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla/subscriptions","organizations_url":"https://api.github.com/users/mozilla/orgs","repos_url":"https://api.github.com/users/mozilla/repos","events_url":"https://api.github.com/users/mozilla/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla/received_events","type":"Organization","site_admin":false},"repo":{"id":10973059,"name":"treeherder-ui","full_name":"mozilla/treeherder-ui","owner":{"login":"mozilla","id":131524,"avatar_url":"https://avatars.githubusercontent.com/u/131524?v=3","gravatar_id":"","url":"https://api.github.com/users/mozilla","html_url":"https://github.com/mozilla","followers_url":"https://api.github.com/users/mozilla/followers","following_url":"https://api.github.com/users/mozilla/following{/other_user}","gists_url":"https://api.github.com/users/mozilla/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla/subscriptions","organizations_url":"https://api.github.com/users/mozilla/orgs","repos_url":"https://api.github.com/users/mozilla/repos","events_url":"https://api.github.com/users/mozilla/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mozilla/treeherder-ui","description":"The UI for treeherder, a replacement for TBPL. See wiki page for where to file bugs.","fork":false,"url":"https://api.github.com/repos/mozilla/treeherder-ui","forks_url":"https://api.github.com/repos/mozilla/treeherder-ui/forks","keys_url":"https://api.github.com/repos/mozilla/treeherder-ui/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mozilla/treeherder-ui/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mozilla/treeherder-ui/teams","hooks_url":"https://api.github.com/repos/mozilla/treeherder-ui/hooks","issue_events_url":"https://api.github.com/repos/mozilla/treeherder-ui/issues/events{/number}","events_url":"https://api.github.com/repos/mozilla/treeherder-ui/events","assignees_url":"https://api.github.com/repos/mozilla/treeherder-ui/assignees{/user}","branches_url":"https://api.github.com/repos/mozilla/treeherder-ui/branches{/branch}","tags_url":"https://api.github.com/repos/mozilla/treeherder-ui/tags","blobs_url":"https://api.github.com/repos/mozilla/treeherder-ui/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mozilla/treeherder-ui/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mozilla/treeherder-ui/git/refs{/sha}","trees_url":"https://api.github.com/repos/mozilla/treeherder-ui/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mozilla/treeherder-ui/statuses/{sha}","languages_url":"https://api.github.com/repos/mozilla/treeherder-ui/languages","stargazers_url":"https://api.github.com/repos/mozilla/treeherder-ui/stargazers","contributors_url":"https://api.github.com/repos/mozilla/treeherder-ui/contributors","subscribers_url":"https://api.github.com/repos/mozilla/treeherder-ui/subscribers","subscription_url":"https://api.github.com/repos/mozilla/treeherder-ui/subscription","commits_url":"https://api.github.com/repos/mozilla/treeherder-ui/commits{/sha}","git_commits_url":"https://api.github.com/repos/mozilla/treeherder-ui/git/commits{/sha}","comments_url":"https://api.github.com/repos/mozilla/treeherder-ui/comments{/number}","issue_comment_url":"https://api.github.com/repos/mozilla/treeherder-ui/issues/comments{/number}","contents_url":"https://api.github.com/repos/mozilla/treeherder-ui/contents/{+path}","compare_url":"https://api.github.com/repos/mozilla/treeherder-ui/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mozilla/treeherder-ui/merges","archive_url":"https://api.github.com/repos/mozilla/treeherder-ui/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mozilla/treeherder-ui/downloads","issues_url":"https://api.github.com/repos/mozilla/treeherder-ui/issues{/number}","pulls_url":"https://api.github.com/repos/mozilla/treeherder-ui/pulls{/number}","milestones_url":"https://api.github.com/repos/mozilla/treeherder-ui/milestones{/number}","notifications_url":"https://api.github.com/repos/mozilla/treeherder-ui/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mozilla/treeherder-ui/labels{/name}","releases_url":"https://api.github.com/repos/mozilla/treeherder-ui/releases{/id}","created_at":"2013-06-26T16:25:19Z","updated_at":"2015-04-16T16:45:22Z","pushed_at":"2015-04-17T15:58:10Z","git_url":"git://github.com/mozilla/treeherder-ui.git","ssh_url":"git@github.com:mozilla/treeherder-ui.git","clone_url":"https://github.com/mozilla/treeherder-ui.git","svn_url":"https://github.com/mozilla/treeherder-ui","homepage":"https://wiki.mozilla.org/Auto-tools/Projects/Treeherder","size":19586,"stargazers_count":24,"watchers_count":24,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":41,"mirror_url":null,"open_issues_count":5,"forks":41,"open_issues":5,"watchers":24,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/465"},"html":{"href":"https://github.com/mozilla/treeherder-ui/pull/465"},"issue":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/issues/465"},"comments":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/issues/465/comments"},"review_comments":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/465/comments"},"review_comment":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/pulls/465/commits"},"statuses":{"href":"https://api.github.com/repos/mozilla/treeherder-ui/statuses/a0bfa78759692118ec45eb40b750bdf227f2f426"}}}}