{"action":"created","comment":{"url":"https://api.github.com/repos/stb-tester/stb-tester/pulls/comments/32452185","id":32452185,"diff_hunk":"@@ -1,315 +1,181 @@\n-#!/usr/bin/env bash\n-#                                                    -*- sh-basic-offset: 2 -*-\n+#!/usr/bin/env python\n \n-# Copyright 2013 YouView TV Ltd.\n+# Copyright 2015 stb-tester.com Ltd.\n # License: LGPL v2.1 or (at your option) any later version (see\n # https://github.com/stb-tester/stb-tester/blob/master/LICENSE for details).\n \n-#/ Usage:\n-#/   stbt batch run [options] test.py [test.py ...]\n-#/   stbt batch run [options] test.py arg [arg ...] -- test.py arg [arg ...] [-- ...]\n-#/\n-#/ Options:\n-#/   -1    Run once. The default behaviour is to run the test\n-#/         repeatedly as long as it passes.\n-#/   -k    Continue running after \"uninteresting\" failures.\n-#/   -kk   Continue running after any failure (except those\n-#/         that would prevent any further test from passing).\n-#/\n-#/   -d    Enable \"stbt-debug\" dump of intermediate images.\n-#/   -v    Verbose. Print stbt standard output.\n-#/   -vv   Extra verbose. Print stbt standard error output.\n-#/\n-#/   -o    Output directory to save the report and test-run\n-#/         logs under (defaults to the current directory).\n-#/   -t <tag>  Tag to add to test run directory names (useful\n-#/         to differentiate directories when you intend to\n-#/         merge test results from multiple machines).\n \n-usage() { grep '^#/' \"$0\" | cut -c4-; }\n-die() { echo \"$(basename \"$0\"): error: $*\" >&2; exit 1; }\n-\n-main() {\n-  runner=$(dirname \"$(realpath \"$0\")\")\n-  export PYTHONUNBUFFERED=x\n-\n-  keep_going=0\n-  outputdir=\"$PWD\"\n-  run_once=false\n-  stop=false\n-  tag=\n-  v=-v\n-  verbose=0\n-  failure_count=0\n-  while getopts \":1dhko:t:v\" option; do\n-    case $option in\n-      1) run_once=true;;\n-      d) v=-vv;;\n-      h) usage; exit 0;;\n-      k) keep_going=$((keep_going + 1));;\n-      o) outputdir=$(realpath \"$OPTARG\");;\n-      t) tag=-$OPTARG;;\n-      v) verbose=$((verbose + 1));;\n-      *) die \"Invalid option '-$OPTARG'. Use '-h' for help.\";;\n-    esac\n-  done\n-  shift $((OPTIND - 1))\n-  [[ $# -gt 0 ]] || { usage >&2; exit 1; }\n-\n-  which ts &>/dev/null ||\n-    die \"No 'ts' command found; please install 'moreutils' package\"\n-\n-  exec 3>/dev/null 4>/dev/null\n-  [ $verbose -gt 0 ] && exec 3>&1\n-  [ $verbose -gt 1 ] && exec 4>&1\n-\n-  run_count=0\n-  while true; do\n-    while IFS=$'\\t' read -a test; do\n-      run_count=$((run_count+1))\n-      run \"${test[@]}\" </dev/null;\n-      last_exit_status=$?\n-      [ \"$last_exit_status\" = 0 ] || failure_count=$((failure_count+1))\n-      should_i_continue || break 2\n-    done < <(parse_test_args \"$@\")\n-    $run_once && break\n-  done\n-\n-  if [ \"$run_count\" = 1 ]; then\n-    # If we only run a single test a single time propagate the result through\n-    exit \"$last_exit_status\"\n-  elif [ \"$failure_count\" = 0 ]; then\n-    exit 0\n-  else\n-    exit 1\n-  fi\n-}\n-\n-send_state_change() {\n-  if [ -z \"$STBT_TRACING_SOCKET\" ]; then\n-    return\n-  fi\n-\n-  date='\"'$(date --iso-8601=ns)'\"'\n-  echo '{\"state_change\": {\"changes\": {\"'\"$1\"'\": '\"$2\"'}, \"time\": '\"$date\"'}}' \\\n-    | socat STDIN \"UNIX-CONNECT:$STBT_TRACING_SOCKET\"\n-  true\n-}\n-\n-run() {\n-  local test testpath tmpdir rundir\n-\n-  test=\"$1\" && shift &&\n-  testpath=$(realpath \"$test\") &&\n-  mkdir -p \"$outputdir\" &&\n-  pushd \"$outputdir\" >/dev/null &&\n-  rundir=$(date +%Y-%m-%d_%H.%M.%S)\"$tag\" &&\n-  mkdir \"$rundir\" &&\n-  send_state_change active_results_directory \"\\\"$outputdir/$rundir\\\"\" &&\n-  rm -f current\"$tag\" && ln -s \"$rundir\" current\"$tag\" &&\n-  cd \"$rundir\" &&\n-  tmpdir=\"$(mktemp -dt stbt-batch.XXX)\" &&\n-  mkfifo \"$tmpdir\"/rawout \"$tmpdir\"/rawerr ||\n-  die \"Failed to set up test-run directory '$outputdir/$rundir'.\"\n-\n-  [ -n \"$tag\" ] && echo \"Tag\t${tag#-}\" > extra-columns\n-\n-  ( cd \"$(dirname \"$testpath\")\" &&\n-    git describe --always --dirty 2>/dev/null\n-  ) > git-commit || rm -f git-commit\n-\n-  ( cd \"$(dirname \"$testpath\")\" &&\n-    gitdir=$(dirname \"$(realpath \"$(git rev-parse --git-dir 2>/dev/null)\")\") &&\n-    echo \"${testpath#$gitdir/}\" || echo \"$testpath\"\n-  ) > test-name\n-\n-  printf \"%s\\n\" \"$@\" > test-args\n-\n-  \"$runner\"/report --html-only . >/dev/null\n-\n-  user_command pre_run start\n-\n-  [ $verbose -gt 0 ] && printf \"\\n$test $*...\\n\" || printf \"$test $*... \"\n-  \"$runner\"/../stbt-run $v --save-video \"video.webm\" \"$testpath\" -- \"$@\" \\\n-    >\"$tmpdir\"/rawout 2>\"$tmpdir\"/rawerr &\n-  stbtpid=$!\n-  local start_time=$(date +%s)\n-  ts '[%Y-%m-%d %H:%M:%.S %z] ' < \"$tmpdir\"/rawout | tee stdout.log >&3 &\n-  ts '[%Y-%m-%d %H:%M:%.S %z] ' < \"$tmpdir\"/rawerr | tee stderr.log >&4 &\n-\n-  while true; do\n-    interrupted=false\n-    wait $stbtpid\n-    exit_status=$?\n-    $interrupted || break\n-  done\n-\n-  [[ $exit_status -eq 0 ]] && echo OK || echo FAILED\n-\n-  # Data that must be collected ASAP\n-  echo $(( $(date +%s) - $start_time )) > duration\n-  which sensors &>/dev/null && sensors &> sensors.log\n-  [[ -f screenshot.png ]] || \"$runner\"/../stbt-screenshot &>/dev/null\n-  echo $exit_status > exit-status\n-\n-  cat <<-EOF | python &&\n-\t\timport cv2\n-\t\tim = cv2.imread('screenshot.png')\n-\t\tif im is not None:\n-\t\t    cv2.imwrite(\n-\t\t        'thumbnail.jpg',\n-\t\t        cv2.resize(im, (640, 640 * im.shape[0] // im.shape[1])),\n-\t\t        [cv2.cv.CV_IMWRITE_JPEG_QUALITY, 50])\n-\t\tEOF\n-  [[ $exit_status -eq 0 ]] && rm -f screenshot.png\n-\n-  user_command post_run stop\n-\n-  rm \"$tmpdir\"/rawout \"$tmpdir\"/rawerr\n-  rmdir \"$tmpdir\"\n-  echo \"$STBT_VERSION\" > stbt-version.log\n-  grep -q \"FAIL: .*: MatchTimeout\" stdout.log && template\n-  [ -f core* ] && backtrace core*\n-  STBT_TRACING_SOCKET=\"\" \"$runner\"/report --classify-only . >/dev/null\n-  grep -q \"FAIL: .*: NoVideo\" stdout.log && {\n-    check_capture_hardware || stop=true; }\n-\n-  if [[ $exit_status -ne 0 ]]; then\n-    user_command recover || stop=true\n-  fi\n-\n-  \"$runner\"/report --html-only . >/dev/null\n-\n-  cd ..\n-  send_state_change active_results_directory null\n-  rm -f latest\"$tag\"; ln -s \"$rundir\" latest\"$tag\"\n-  popd >/dev/null\n-  return $exit_status\n-}\n-\n-trap on_kill1 sigint sigterm\n-on_kill1() {\n-  printf \"\\nReceived interrupt; waiting for current test to complete.\\n\" >&2\n-  interrupted=true stop=true\n-  trap on_kill2 sigint sigterm\n-}\n-on_kill2() {\n-  echo \"Received interrupt; exiting.\" >&2\n-  interrupted=true stop=true\n-  killtree $stbtpid\n-}\n-\n-should_i_continue() {\n-  $stop && return 1;\n-  [[ $exit_status -eq 0 ]] ||\n-  # \"Uninteresting\" failures due to the test infrastructure\n-  [[ $keep_going -gt 0 && $exit_status -gt 1 ]] ||\n-  # Failures due to the system under test\n-  [[ $keep_going -gt 1 ]]\n-}\n-\n-template() {\n-  local template=$(\n-    sed -n 's,^.*stbt-run: Searching for \\(.*\\.png\\)$,\\1,p' stderr.log |\n-    tail -1)\n-  [ -f \"$template\" ] && cp \"$template\" template.png\n-}\n-\n-backtrace() {\n-  local gdbcommand corefile=$1\n-  gdbcommand=$(mktemp -t report.XXX) || die \"Failed to create temp file\"\n-  echo \"thread apply all bt\" > $gdbcommand\n-  gdb $(which python) $corefile -batch -x $gdbcommand &> backtrace.log\n-  rm -f $gdbcommand\n-}\n-\n-user_command() {\n-  local c=$(\"$runner\"/../stbt-config batch.$1 2>/dev/null)\n-  [[ -z \"$c\" ]] && return\n-  \"$c\" $2 </dev/null\n-}\n-\n-check_capture_hardware() {\n-  case \"$(\"$runner\"/../stbt-config global.source_pipeline | awk '{print $1}')\" in\n-    v4l2src)\n-      if grep -q \"Cannot identify device '/dev/v\" failure-reason; then\n-        echo \"v4l2 device not found; exiting.\"\n+import argparse\n+import os\n+import signal\n+import subprocess\n+import sys\n+from distutils.spawn import find_executable\n+\n+\n+def main(argv):\n+    runner = os.path.dirname(os.path.abspath(__file__))\n+\n+    parser = argparse.ArgumentParser(usage=(\n+        \"stbt batch run [options] test.py [test.py ...]\\n\"\n+        \"stbt batch run [options] test.py arg [arg ...] -- \"\n+        \"test.py arg [arg ...] [-- ...])\"))\n+    parser.add_argument(\n+        '-1', '--run-once', action=\"store_true\", help=(\n+            'Run once. The default behaviour is to run the test repeatedly as '\n+            'long as it passes.'))\n+    parser.add_argument(\n+        '-k', '--keep-going', action=\"count\", help=(\n+            'Continue running after failures.  Provide this argument once to '\n+            'continue running after \"uninteresting\" failures, and twice to '\n+            'continue running after any failure (except those that would '\n+            'prevent any further test from passing).'))\n+    parser.add_argument(\n+        '-d', '--debug', action=\"store_true\", help=(\n+            'Enable \"stbt-debug\" dump of intermediate images.'))\n+    parser.add_argument(\n+        '-v', '--verbose', action=\"count\", default=0, help=(\n+            'Verbose. Provide this argument once to print stbt standard '\n+            'output. Provide this argument twice to also print stbt stderr '\n+            'output'))\n+    parser.add_argument(\n+        '-o', '--output', default=os.curdir, help=(\n+            'Output directory to save the report and test-run logs under '\n+            '(defaults to the current directory).'))\n+    parser.add_argument(\n+        '-t', '--tag', help=(\n+            'Tag to add to test run directory names (useful to differentiate '\n+            'directories when you intend to merge test results from multiple '\n+            'machines).'))\n+    parser.add_argument('test_name', nargs=argparse.REMAINDER)\n+    args = parser.parse_args(argv[1:])\n+\n+    if args.tag is not None:\n+        tag = '-' + args.tag\n+    else:\n+        tag = \"\"\n+\n+    os.environ['PYTHONUNBUFFERED'] = 'x'\n+\n+    term_count = [0]","path":"stbt-batch.d/run","position":291,"original_position":291,"commit_id":"d03354d0bf9804abc819c265bc9cec3a3ff228b6","original_commit_id":"d03354d0bf9804abc819c265bc9cec3a3ff228b6","user":{"login":"drothlis","id":12424,"avatar_url":"https://avatars.githubusercontent.com/u/12424?v=3","gravatar_id":"","url":"https://api.github.com/users/drothlis","html_url":"https://github.com/drothlis","followers_url":"https://api.github.com/users/drothlis/followers","following_url":"https://api.github.com/users/drothlis/following{/other_user}","gists_url":"https://api.github.com/users/drothlis/gists{/gist_id}","starred_url":"https://api.github.com/users/drothlis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/drothlis/subscriptions","organizations_url":"https://api.github.com/users/drothlis/orgs","repos_url":"https://api.github.com/users/drothlis/repos","events_url":"https://api.github.com/users/drothlis/events{/privacy}","received_events_url":"https://api.github.com/users/drothlis/received_events","type":"User","site_admin":false},"body":"You define `term_count` here but you define `stop` below `on_term` (and they're both used in `on_term`).","created_at":"2015-06-15T18:40:39Z","updated_at":"2015-06-15T18:40:39Z","html_url":"https://github.com/stb-tester/stb-tester/pull/286#discussion_r32452185","pull_request_url":"https://api.github.com/repos/stb-tester/stb-tester/pulls/286","_links":{"self":{"href":"https://api.github.com/repos/stb-tester/stb-tester/pulls/comments/32452185"},"html":{"href":"https://github.com/stb-tester/stb-tester/pull/286#discussion_r32452185"},"pull_request":{"href":"https://api.github.com/repos/stb-tester/stb-tester/pulls/286"}}},"pull_request":{"url":"https://api.github.com/repos/stb-tester/stb-tester/pulls/286","id":37494420,"html_url":"https://github.com/stb-tester/stb-tester/pull/286","diff_url":"https://github.com/stb-tester/stb-tester/pull/286.diff","patch_url":"https://github.com/stb-tester/stb-tester/pull/286.patch","issue_url":"https://api.github.com/repos/stb-tester/stb-tester/issues/286","number":286,"state":"open","locked":false,"title":"pythonify stbt-batch","user":{"login":"wmanley","id":494659,"avatar_url":"https://avatars.githubusercontent.com/u/494659?v=3","gravatar_id":"","url":"https://api.github.com/users/wmanley","html_url":"https://github.com/wmanley","followers_url":"https://api.github.com/users/wmanley/followers","following_url":"https://api.github.com/users/wmanley/following{/other_user}","gists_url":"https://api.github.com/users/wmanley/gists{/gist_id}","starred_url":"https://api.github.com/users/wmanley/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wmanley/subscriptions","organizations_url":"https://api.github.com/users/wmanley/orgs","repos_url":"https://api.github.com/users/wmanley/repos","events_url":"https://api.github.com/users/wmanley/events{/privacy}","received_events_url":"https://api.github.com/users/wmanley/received_events","type":"User","site_admin":false},"body":"It turned out to be too difficult to reimplement this in one big go so I ended up taking a different approach.  I've split stbt batch run into:\r\n\r\n* The scheduler (`stbt-batch.d/run` decides which tests to run and invokes the runner.\r\n* The (private) runner (`stbt-batch.d/run-one`) runs the tests and all the associated pre_run, post_run, classify, recover, etc. scripts.\r\n\r\nI've then rewritten the scheduler in Python, leaving the runner in bash.  The process heirarchy will now look like:\r\n\r\n         python      ->         bash         -> python\r\n    stbt-batch.d/run -> stbt-batch.d/run-one -> stbt-run\r\n\r\nPotentially in the future we can look at pulling the functionality of `run-one` apart and into either the scheduler or `stbt-run` itself.","created_at":"2015-06-11T18:34:29Z","updated_at":"2015-06-15T18:40:39Z","closed_at":null,"merged_at":null,"merge_commit_sha":"42586db5113872f1103576da42d82e18dc4c38b3","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/stb-tester/stb-tester/pulls/286/commits","review_comments_url":"https://api.github.com/repos/stb-tester/stb-tester/pulls/286/comments","review_comment_url":"https://api.github.com/repos/stb-tester/stb-tester/pulls/comments{/number}","comments_url":"https://api.github.com/repos/stb-tester/stb-tester/issues/286/comments","statuses_url":"https://api.github.com/repos/stb-tester/stb-tester/statuses/d03354d0bf9804abc819c265bc9cec3a3ff228b6","head":{"label":"wmanley:pythonify-stbt-batch","ref":"pythonify-stbt-batch","sha":"d03354d0bf9804abc819c265bc9cec3a3ff228b6","user":{"login":"wmanley","id":494659,"avatar_url":"https://avatars.githubusercontent.com/u/494659?v=3","gravatar_id":"","url":"https://api.github.com/users/wmanley","html_url":"https://github.com/wmanley","followers_url":"https://api.github.com/users/wmanley/followers","following_url":"https://api.github.com/users/wmanley/following{/other_user}","gists_url":"https://api.github.com/users/wmanley/gists{/gist_id}","starred_url":"https://api.github.com/users/wmanley/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wmanley/subscriptions","organizations_url":"https://api.github.com/users/wmanley/orgs","repos_url":"https://api.github.com/users/wmanley/repos","events_url":"https://api.github.com/users/wmanley/events{/privacy}","received_events_url":"https://api.github.com/users/wmanley/received_events","type":"User","site_admin":false},"repo":{"id":4783326,"name":"stb-tester","full_name":"wmanley/stb-tester","owner":{"login":"wmanley","id":494659,"avatar_url":"https://avatars.githubusercontent.com/u/494659?v=3","gravatar_id":"","url":"https://api.github.com/users/wmanley","html_url":"https://github.com/wmanley","followers_url":"https://api.github.com/users/wmanley/followers","following_url":"https://api.github.com/users/wmanley/following{/other_user}","gists_url":"https://api.github.com/users/wmanley/gists{/gist_id}","starred_url":"https://api.github.com/users/wmanley/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wmanley/subscriptions","organizations_url":"https://api.github.com/users/wmanley/orgs","repos_url":"https://api.github.com/users/wmanley/repos","events_url":"https://api.github.com/users/wmanley/events{/privacy}","received_events_url":"https://api.github.com/users/wmanley/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/wmanley/stb-tester","description":"A record + playback testing system for set-top boxes","fork":true,"url":"https://api.github.com/repos/wmanley/stb-tester","forks_url":"https://api.github.com/repos/wmanley/stb-tester/forks","keys_url":"https://api.github.com/repos/wmanley/stb-tester/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wmanley/stb-tester/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wmanley/stb-tester/teams","hooks_url":"https://api.github.com/repos/wmanley/stb-tester/hooks","issue_events_url":"https://api.github.com/repos/wmanley/stb-tester/issues/events{/number}","events_url":"https://api.github.com/repos/wmanley/stb-tester/events","assignees_url":"https://api.github.com/repos/wmanley/stb-tester/assignees{/user}","branches_url":"https://api.github.com/repos/wmanley/stb-tester/branches{/branch}","tags_url":"https://api.github.com/repos/wmanley/stb-tester/tags","blobs_url":"https://api.github.com/repos/wmanley/stb-tester/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wmanley/stb-tester/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wmanley/stb-tester/git/refs{/sha}","trees_url":"https://api.github.com/repos/wmanley/stb-tester/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wmanley/stb-tester/statuses/{sha}","languages_url":"https://api.github.com/repos/wmanley/stb-tester/languages","stargazers_url":"https://api.github.com/repos/wmanley/stb-tester/stargazers","contributors_url":"https://api.github.com/repos/wmanley/stb-tester/contributors","subscribers_url":"https://api.github.com/repos/wmanley/stb-tester/subscribers","subscription_url":"https://api.github.com/repos/wmanley/stb-tester/subscription","commits_url":"https://api.github.com/repos/wmanley/stb-tester/commits{/sha}","git_commits_url":"https://api.github.com/repos/wmanley/stb-tester/git/commits{/sha}","comments_url":"https://api.github.com/repos/wmanley/stb-tester/comments{/number}","issue_comment_url":"https://api.github.com/repos/wmanley/stb-tester/issues/comments{/number}","contents_url":"https://api.github.com/repos/wmanley/stb-tester/contents/{+path}","compare_url":"https://api.github.com/repos/wmanley/stb-tester/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wmanley/stb-tester/merges","archive_url":"https://api.github.com/repos/wmanley/stb-tester/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wmanley/stb-tester/downloads","issues_url":"https://api.github.com/repos/wmanley/stb-tester/issues{/number}","pulls_url":"https://api.github.com/repos/wmanley/stb-tester/pulls{/number}","milestones_url":"https://api.github.com/repos/wmanley/stb-tester/milestones{/number}","notifications_url":"https://api.github.com/repos/wmanley/stb-tester/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wmanley/stb-tester/labels{/name}","releases_url":"https://api.github.com/repos/wmanley/stb-tester/releases{/id}","created_at":"2012-06-25T15:17:46Z","updated_at":"2015-02-24T16:36:05Z","pushed_at":"2015-06-15T17:20:37Z","git_url":"git://github.com/wmanley/stb-tester.git","ssh_url":"git@github.com:wmanley/stb-tester.git","clone_url":"https://github.com/wmanley/stb-tester.git","svn_url":"https://github.com/wmanley/stb-tester","homepage":null,"size":7481,"stargazers_count":2,"watchers_count":2,"language":"Python","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":2,"default_branch":"master"}},"base":{"label":"stb-tester:master","ref":"master","sha":"4f7bc4f598047ba5e200100f5de13ff5ef5fd9f0","user":{"login":"stb-tester","id":5528358,"avatar_url":"https://avatars.githubusercontent.com/u/5528358?v=3","gravatar_id":"","url":"https://api.github.com/users/stb-tester","html_url":"https://github.com/stb-tester","followers_url":"https://api.github.com/users/stb-tester/followers","following_url":"https://api.github.com/users/stb-tester/following{/other_user}","gists_url":"https://api.github.com/users/stb-tester/gists{/gist_id}","starred_url":"https://api.github.com/users/stb-tester/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stb-tester/subscriptions","organizations_url":"https://api.github.com/users/stb-tester/orgs","repos_url":"https://api.github.com/users/stb-tester/repos","events_url":"https://api.github.com/users/stb-tester/events{/privacy}","received_events_url":"https://api.github.com/users/stb-tester/received_events","type":"Organization","site_admin":false},"repo":{"id":4739298,"name":"stb-tester","full_name":"stb-tester/stb-tester","owner":{"login":"stb-tester","id":5528358,"avatar_url":"https://avatars.githubusercontent.com/u/5528358?v=3","gravatar_id":"","url":"https://api.github.com/users/stb-tester","html_url":"https://github.com/stb-tester","followers_url":"https://api.github.com/users/stb-tester/followers","following_url":"https://api.github.com/users/stb-tester/following{/other_user}","gists_url":"https://api.github.com/users/stb-tester/gists{/gist_id}","starred_url":"https://api.github.com/users/stb-tester/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stb-tester/subscriptions","organizations_url":"https://api.github.com/users/stb-tester/orgs","repos_url":"https://api.github.com/users/stb-tester/repos","events_url":"https://api.github.com/users/stb-tester/events{/privacy}","received_events_url":"https://api.github.com/users/stb-tester/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/stb-tester/stb-tester","description":"Automated Testing for Set-Top Boxes and Smart TVs","fork":false,"url":"https://api.github.com/repos/stb-tester/stb-tester","forks_url":"https://api.github.com/repos/stb-tester/stb-tester/forks","keys_url":"https://api.github.com/repos/stb-tester/stb-tester/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stb-tester/stb-tester/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stb-tester/stb-tester/teams","hooks_url":"https://api.github.com/repos/stb-tester/stb-tester/hooks","issue_events_url":"https://api.github.com/repos/stb-tester/stb-tester/issues/events{/number}","events_url":"https://api.github.com/repos/stb-tester/stb-tester/events","assignees_url":"https://api.github.com/repos/stb-tester/stb-tester/assignees{/user}","branches_url":"https://api.github.com/repos/stb-tester/stb-tester/branches{/branch}","tags_url":"https://api.github.com/repos/stb-tester/stb-tester/tags","blobs_url":"https://api.github.com/repos/stb-tester/stb-tester/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stb-tester/stb-tester/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stb-tester/stb-tester/git/refs{/sha}","trees_url":"https://api.github.com/repos/stb-tester/stb-tester/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stb-tester/stb-tester/statuses/{sha}","languages_url":"https://api.github.com/repos/stb-tester/stb-tester/languages","stargazers_url":"https://api.github.com/repos/stb-tester/stb-tester/stargazers","contributors_url":"https://api.github.com/repos/stb-tester/stb-tester/contributors","subscribers_url":"https://api.github.com/repos/stb-tester/stb-tester/subscribers","subscription_url":"https://api.github.com/repos/stb-tester/stb-tester/subscription","commits_url":"https://api.github.com/repos/stb-tester/stb-tester/commits{/sha}","git_commits_url":"https://api.github.com/repos/stb-tester/stb-tester/git/commits{/sha}","comments_url":"https://api.github.com/repos/stb-tester/stb-tester/comments{/number}","issue_comment_url":"https://api.github.com/repos/stb-tester/stb-tester/issues/comments{/number}","contents_url":"https://api.github.com/repos/stb-tester/stb-tester/contents/{+path}","compare_url":"https://api.github.com/repos/stb-tester/stb-tester/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stb-tester/stb-tester/merges","archive_url":"https://api.github.com/repos/stb-tester/stb-tester/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stb-tester/stb-tester/downloads","issues_url":"https://api.github.com/repos/stb-tester/stb-tester/issues{/number}","pulls_url":"https://api.github.com/repos/stb-tester/stb-tester/pulls{/number}","milestones_url":"https://api.github.com/repos/stb-tester/stb-tester/milestones{/number}","notifications_url":"https://api.github.com/repos/stb-tester/stb-tester/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stb-tester/stb-tester/labels{/name}","releases_url":"https://api.github.com/repos/stb-tester/stb-tester/releases{/id}","created_at":"2012-06-21T13:11:28Z","updated_at":"2015-05-29T13:04:38Z","pushed_at":"2015-06-15T17:20:38Z","git_url":"git://github.com/stb-tester/stb-tester.git","ssh_url":"git@github.com:stb-tester/stb-tester.git","clone_url":"https://github.com/stb-tester/stb-tester.git","svn_url":"https://github.com/stb-tester/stb-tester","homepage":"http://stb-tester.com","size":10131,"stargazers_count":39,"watchers_count":39,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":41,"mirror_url":null,"open_issues_count":16,"forks":41,"open_issues":16,"watchers":39,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/stb-tester/stb-tester/pulls/286"},"html":{"href":"https://github.com/stb-tester/stb-tester/pull/286"},"issue":{"href":"https://api.github.com/repos/stb-tester/stb-tester/issues/286"},"comments":{"href":"https://api.github.com/repos/stb-tester/stb-tester/issues/286/comments"},"review_comments":{"href":"https://api.github.com/repos/stb-tester/stb-tester/pulls/286/comments"},"review_comment":{"href":"https://api.github.com/repos/stb-tester/stb-tester/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/stb-tester/stb-tester/pulls/286/commits"},"statuses":{"href":"https://api.github.com/repos/stb-tester/stb-tester/statuses/d03354d0bf9804abc819c265bc9cec3a3ff228b6"}}}}