{"action":"created","comment":{"url":"https://api.github.com/repos/dimagi/commcare-hq/pulls/comments/197737099","pull_request_review_id":131533098,"id":197737099,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NzczNzA5OQ==","diff_hunk":"@@ -0,0 +1,185 @@\n+\"\"\"\n+This module deals with data ingestion: populating the aggregate tables from other tables.\n+\"\"\"\n+from __future__ import absolute_import, unicode_literals\n+from collections import namedtuple\n+from datetime import datetime\n+\n+import sqlalchemy\n+from sqlalchemy.dialects.postgresql import insert\n+\n+from corehq.apps.aggregate_ucrs.aggregations import AGG_WINDOW_START_PARAM, AGG_WINDOW_END_PARAM, \\\n+    TimePeriodAggregationWindow, get_time_period_class\n+from corehq.apps.userreports.sql import IndicatorSqlAdapter\n+\n+\n+AggregationParam = namedtuple('AggregationParam', 'name value mapped_column_id')\n+AggregationWindow = namedtuple('AggregationWindow', 'start end')\n+\n+\n+def populate_aggregate_table_data(aggregate_table_adapter):\n+    \"\"\"\n+    Seeds the database table with all data from the table adapter.\n+    \"\"\"\n+    aggregate_table_definition = aggregate_table_adapter.config\n+    # get checkpoint\n+    last_update = get_last_aggregate_checkpoint(aggregate_table_definition)\n+    for window in get_time_aggregation_windows(aggregate_table_definition, last_update):\n+        populate_aggregate_table_data_for_time_period(\n+            aggregate_table_adapter, window,\n+        )\n+\n+\n+def get_last_aggregate_checkpoint(aggregate_table_definition):\n+    \"\"\"\n+    Checkpoints indicate the last time the aggregation script successfully ran.\n+    Will be used to do partial ingestion.\n+    \"\"\"\n+    # todo\n+    return None\n+\n+\n+def get_time_aggregation_windows(aggregate_table_definition, last_update):\n+    if aggregate_table_definition.time_aggregation is None:\n+        # if there is no time aggregation just include a single window with no value\n+        yield None\n+    else:\n+        start_time = get_aggregation_start_period(aggregate_table_definition, last_update)\n+        end_time = get_aggregation_end_period(aggregate_table_definition, last_update)\n+        assert end_time >= start_time","path":"corehq/apps/aggregate_ucrs/ingestion.py","position":49,"original_position":49,"commit_id":"ba7b03e588b54067ef0813fe76e62a1435a1bab4","original_commit_id":"ba7b03e588b54067ef0813fe76e62a1435a1bab4","user":{"login":"snopoke","id":249606,"node_id":"MDQ6VXNlcjI0OTYwNg==","avatar_url":"https://avatars3.githubusercontent.com/u/249606?v=4","gravatar_id":"","url":"https://api.github.com/users/snopoke","html_url":"https://github.com/snopoke","followers_url":"https://api.github.com/users/snopoke/followers","following_url":"https://api.github.com/users/snopoke/following{/other_user}","gists_url":"https://api.github.com/users/snopoke/gists{/gist_id}","starred_url":"https://api.github.com/users/snopoke/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/snopoke/subscriptions","organizations_url":"https://api.github.com/users/snopoke/orgs","repos_url":"https://api.github.com/users/snopoke/repos","events_url":"https://api.github.com/users/snopoke/events{/privacy}","received_events_url":"https://api.github.com/users/snopoke/received_events","type":"User","site_admin":false},"body":"I think this should be strictly `>` since `end_time` is not inclusive.","created_at":"2018-06-25T09:44:42Z","updated_at":"2018-06-25T09:59:43Z","html_url":"https://github.com/dimagi/commcare-hq/pull/20874#discussion_r197737099","pull_request_url":"https://api.github.com/repos/dimagi/commcare-hq/pulls/20874","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/dimagi/commcare-hq/pulls/comments/197737099"},"html":{"href":"https://github.com/dimagi/commcare-hq/pull/20874#discussion_r197737099"},"pull_request":{"href":"https://api.github.com/repos/dimagi/commcare-hq/pulls/20874"}}},"pull_request":{"url":"https://api.github.com/repos/dimagi/commcare-hq/pulls/20874","id":194228675,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk0MjI4Njc1","html_url":"https://github.com/dimagi/commcare-hq/pull/20874","diff_url":"https://github.com/dimagi/commcare-hq/pull/20874.diff","patch_url":"https://github.com/dimagi/commcare-hq/pull/20874.patch","issue_url":"https://api.github.com/repos/dimagi/commcare-hq/issues/20874","number":20874,"state":"open","locked":false,"title":"PoC for Aggregate UCRs","user":{"login":"czue","id":66555,"node_id":"MDQ6VXNlcjY2NTU1","avatar_url":"https://avatars3.githubusercontent.com/u/66555?v=4","gravatar_id":"","url":"https://api.github.com/users/czue","html_url":"https://github.com/czue","followers_url":"https://api.github.com/users/czue/followers","following_url":"https://api.github.com/users/czue/following{/other_user}","gists_url":"https://api.github.com/users/czue/gists{/gist_id}","starred_url":"https://api.github.com/users/czue/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/czue/subscriptions","organizations_url":"https://api.github.com/users/czue/orgs","repos_url":"https://api.github.com/users/czue/repos","events_url":"https://api.github.com/users/czue/events{/privacy}","received_events_url":"https://api.github.com/users/czue/received_events","type":"User","site_admin":false},"body":"[Largely Based off this Spec Document](https://docs.google.com/document/d/1O3p4KC1Tw251ILbCa6IIq6MPvyKTSgEgN7tHq6r_0RY/edit#)\r\n\r\nReview all at once :house: \r\n\r\nI've been working on this off and on for a while and thought it would be a good time to get some more eyes on it. :eyes: \r\n\r\nThis is a proof of concept implementation of a way to build aggregate \"UCRs\" on top of existing UCR data sources. Currently it only creates and populates the underlying database tables and does not provide any interface for reporting on top of them. \r\n\r\n## 1,000 foot view\r\n\r\nThis is almost completely encapsulated in a new HQ app.\r\n\r\n- :notebook: It's probably worth starting with the sample config files to get a sense of what this does. There's a [basic version that joins forms and cases](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/tests/data/table_definitions/basic_aggregate_definition.yml) and [another one that does monthly aggregation](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/tests/data/table_definitions/monthly_aggregate_definition.yml).\r\n- :white_check_mark: Next thing to look at is probably [the main tests](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/tests/test_aggregation.py). This will show how the configs get mapped to actual data processing via UCR data sources and form/case data.\r\n- :unicorn: Behind the scenes the spec format gets [parsed into json](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/parser.py), then [imported](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/importer.py) into [a set of django models](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/models.py) that basically map 1:1 to the spec. This is all pretty boiler-plate.\r\n- :dizzy_face: The heavy lifting and confusing part is mostly around the [data ingestion](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/ingestion.py) and supporting models. The work is all done directly in SQL via a complex dynamically-generated sqlalchemy operatoin. There are some helpers to handle [time-based aggregation](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/aggregations.py), [months](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/date_utils.py), and [different column types](https://github.com/dimagi/commcare-hq/blob/cz/aggregation/corehq/apps/aggregate_ucrs/column_specs.py). Overall the interfaces to these objects were mostly built up out of necessity based on where I wanted/needed to draw different abstraction barriers to implement the functionality I wanted. Possibly lots could be improved here.\r\n\r\n## A non-exhaustive list of things still on my radar\r\n\r\n(not necessarily trying to do all of these before this goes out, but is a list of things on my high-level todo list)\r\n\r\n- :calendar: I'd like to add support for another time-based aggregation window besides month (e.g. quarterly or daily) just to make sure that it's pretty easy to drop those in.\r\n- :lock: I'd like to fully convince myself that I haven't opened up any opportunities for SQL injection attacks\r\n- :steam_locomotive: There's a bunch of infrastructure around data processing / celery / airflow type of stuff that still needs to get built for this to actually be usable in production\r\n- :bar_chart: something in the way of visualizing the data in HQ, even if it's just exposing the underlying tables similar to the UCR export API\r\n- :heavy_plus_sign: Figuring out how we should expose the creation/editing of these models to our pilot user base. \r\n- :busts_in_silhouette: Figuring out if there's any other aggregations we want to support besides time-based. Like maybe groups or locations?\r\n- :mag: whatever comes up during code / architecture review","created_at":"2018-06-12T10:04:57Z","updated_at":"2018-06-25T09:59:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c8e2efcadaa5ca1e0351aca0552b628a308713bd","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":79032211,"node_id":"MDU6TGFiZWw3OTAzMjIxMQ==","url":"https://api.github.com/repos/dimagi/commcare-hq/labels/Open%20for%20review:%20hold%20off%20on%20merge","name":"Open for review: hold off on merge","color":"5319e7","default":false},{"id":724785066,"node_id":"MDU6TGFiZWw3MjQ3ODUwNjY=","url":"https://api.github.com/repos/dimagi/commcare-hq/labels/product/feature-flag","name":"product/feature-flag","color":"d38737","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/dimagi/commcare-hq/pulls/20874/commits","review_comments_url":"https://api.github.com/repos/dimagi/commcare-hq/pulls/20874/comments","review_comment_url":"https://api.github.com/repos/dimagi/commcare-hq/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dimagi/commcare-hq/issues/20874/comments","statuses_url":"https://api.github.com/repos/dimagi/commcare-hq/statuses/ba7b03e588b54067ef0813fe76e62a1435a1bab4","head":{"label":"dimagi:cz/aggregation","ref":"cz/aggregation","sha":"ba7b03e588b54067ef0813fe76e62a1435a1bab4","user":{"login":"dimagi","id":94514,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk0NTE0","avatar_url":"https://avatars1.githubusercontent.com/u/94514?v=4","gravatar_id":"","url":"https://api.github.com/users/dimagi","html_url":"https://github.com/dimagi","followers_url":"https://api.github.com/users/dimagi/followers","following_url":"https://api.github.com/users/dimagi/following{/other_user}","gists_url":"https://api.github.com/users/dimagi/gists{/gist_id}","starred_url":"https://api.github.com/users/dimagi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dimagi/subscriptions","organizations_url":"https://api.github.com/users/dimagi/orgs","repos_url":"https://api.github.com/users/dimagi/repos","events_url":"https://api.github.com/users/dimagi/events{/privacy}","received_events_url":"https://api.github.com/users/dimagi/received_events","type":"Organization","site_admin":false},"repo":{"id":247278,"node_id":"MDEwOlJlcG9zaXRvcnkyNDcyNzg=","name":"commcare-hq","full_name":"dimagi/commcare-hq","owner":{"login":"dimagi","id":94514,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk0NTE0","avatar_url":"https://avatars1.githubusercontent.com/u/94514?v=4","gravatar_id":"","url":"https://api.github.com/users/dimagi","html_url":"https://github.com/dimagi","followers_url":"https://api.github.com/users/dimagi/followers","following_url":"https://api.github.com/users/dimagi/following{/other_user}","gists_url":"https://api.github.com/users/dimagi/gists{/gist_id}","starred_url":"https://api.github.com/users/dimagi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dimagi/subscriptions","organizations_url":"https://api.github.com/users/dimagi/orgs","repos_url":"https://api.github.com/users/dimagi/repos","events_url":"https://api.github.com/users/dimagi/events{/privacy}","received_events_url":"https://api.github.com/users/dimagi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dimagi/commcare-hq","description":"A server-side tool to help manage community health workers, written in Django","fork":false,"url":"https://api.github.com/repos/dimagi/commcare-hq","forks_url":"https://api.github.com/repos/dimagi/commcare-hq/forks","keys_url":"https://api.github.com/repos/dimagi/commcare-hq/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dimagi/commcare-hq/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dimagi/commcare-hq/teams","hooks_url":"https://api.github.com/repos/dimagi/commcare-hq/hooks","issue_events_url":"https://api.github.com/repos/dimagi/commcare-hq/issues/events{/number}","events_url":"https://api.github.com/repos/dimagi/commcare-hq/events","assignees_url":"https://api.github.com/repos/dimagi/commcare-hq/assignees{/user}","branches_url":"https://api.github.com/repos/dimagi/commcare-hq/branches{/branch}","tags_url":"https://api.github.com/repos/dimagi/commcare-hq/tags","blobs_url":"https://api.github.com/repos/dimagi/commcare-hq/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dimagi/commcare-hq/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dimagi/commcare-hq/git/refs{/sha}","trees_url":"https://api.github.com/repos/dimagi/commcare-hq/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dimagi/commcare-hq/statuses/{sha}","languages_url":"https://api.github.com/repos/dimagi/commcare-hq/languages","stargazers_url":"https://api.github.com/repos/dimagi/commcare-hq/stargazers","contributors_url":"https://api.github.com/repos/dimagi/commcare-hq/contributors","subscribers_url":"https://api.github.com/repos/dimagi/commcare-hq/subscribers","subscription_url":"https://api.github.com/repos/dimagi/commcare-hq/subscription","commits_url":"https://api.github.com/repos/dimagi/commcare-hq/commits{/sha}","git_commits_url":"https://api.github.com/repos/dimagi/commcare-hq/git/commits{/sha}","comments_url":"https://api.github.com/repos/dimagi/commcare-hq/comments{/number}","issue_comment_url":"https://api.github.com/repos/dimagi/commcare-hq/issues/comments{/number}","contents_url":"https://api.github.com/repos/dimagi/commcare-hq/contents/{+path}","compare_url":"https://api.github.com/repos/dimagi/commcare-hq/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dimagi/commcare-hq/merges","archive_url":"https://api.github.com/repos/dimagi/commcare-hq/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dimagi/commcare-hq/downloads","issues_url":"https://api.github.com/repos/dimagi/commcare-hq/issues{/number}","pulls_url":"https://api.github.com/repos/dimagi/commcare-hq/pulls{/number}","milestones_url":"https://api.github.com/repos/dimagi/commcare-hq/milestones{/number}","notifications_url":"https://api.github.com/repos/dimagi/commcare-hq/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dimagi/commcare-hq/labels{/name}","releases_url":"https://api.github.com/repos/dimagi/commcare-hq/releases{/id}","deployments_url":"https://api.github.com/repos/dimagi/commcare-hq/deployments","created_at":"2009-07-09T17:00:07Z","updated_at":"2018-06-25T07:54:13Z","pushed_at":"2018-06-25T09:17:22Z","git_url":"git://github.com/dimagi/commcare-hq.git","ssh_url":"git@github.com:dimagi/commcare-hq.git","clone_url":"https://github.com/dimagi/commcare-hq.git","svn_url":"https://github.com/dimagi/commcare-hq","homepage":"https://www.commcarehq.org","size":444784,"stargazers_count":93,"watchers_count":93,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":106,"mirror_url":null,"archived":false,"open_issues_count":85,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":106,"open_issues":85,"watchers":93,"default_branch":"master"}},"base":{"label":"dimagi:master","ref":"master","sha":"512c077acdb1b4d064963c8d5325ed4661be7029","user":{"login":"dimagi","id":94514,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk0NTE0","avatar_url":"https://avatars1.githubusercontent.com/u/94514?v=4","gravatar_id":"","url":"https://api.github.com/users/dimagi","html_url":"https://github.com/dimagi","followers_url":"https://api.github.com/users/dimagi/followers","following_url":"https://api.github.com/users/dimagi/following{/other_user}","gists_url":"https://api.github.com/users/dimagi/gists{/gist_id}","starred_url":"https://api.github.com/users/dimagi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dimagi/subscriptions","organizations_url":"https://api.github.com/users/dimagi/orgs","repos_url":"https://api.github.com/users/dimagi/repos","events_url":"https://api.github.com/users/dimagi/events{/privacy}","received_events_url":"https://api.github.com/users/dimagi/received_events","type":"Organization","site_admin":false},"repo":{"id":247278,"node_id":"MDEwOlJlcG9zaXRvcnkyNDcyNzg=","name":"commcare-hq","full_name":"dimagi/commcare-hq","owner":{"login":"dimagi","id":94514,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk0NTE0","avatar_url":"https://avatars1.githubusercontent.com/u/94514?v=4","gravatar_id":"","url":"https://api.github.com/users/dimagi","html_url":"https://github.com/dimagi","followers_url":"https://api.github.com/users/dimagi/followers","following_url":"https://api.github.com/users/dimagi/following{/other_user}","gists_url":"https://api.github.com/users/dimagi/gists{/gist_id}","starred_url":"https://api.github.com/users/dimagi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dimagi/subscriptions","organizations_url":"https://api.github.com/users/dimagi/orgs","repos_url":"https://api.github.com/users/dimagi/repos","events_url":"https://api.github.com/users/dimagi/events{/privacy}","received_events_url":"https://api.github.com/users/dimagi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dimagi/commcare-hq","description":"A server-side tool to help manage community health workers, written in Django","fork":false,"url":"https://api.github.com/repos/dimagi/commcare-hq","forks_url":"https://api.github.com/repos/dimagi/commcare-hq/forks","keys_url":"https://api.github.com/repos/dimagi/commcare-hq/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dimagi/commcare-hq/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dimagi/commcare-hq/teams","hooks_url":"https://api.github.com/repos/dimagi/commcare-hq/hooks","issue_events_url":"https://api.github.com/repos/dimagi/commcare-hq/issues/events{/number}","events_url":"https://api.github.com/repos/dimagi/commcare-hq/events","assignees_url":"https://api.github.com/repos/dimagi/commcare-hq/assignees{/user}","branches_url":"https://api.github.com/repos/dimagi/commcare-hq/branches{/branch}","tags_url":"https://api.github.com/repos/dimagi/commcare-hq/tags","blobs_url":"https://api.github.com/repos/dimagi/commcare-hq/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dimagi/commcare-hq/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dimagi/commcare-hq/git/refs{/sha}","trees_url":"https://api.github.com/repos/dimagi/commcare-hq/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dimagi/commcare-hq/statuses/{sha}","languages_url":"https://api.github.com/repos/dimagi/commcare-hq/languages","stargazers_url":"https://api.github.com/repos/dimagi/commcare-hq/stargazers","contributors_url":"https://api.github.com/repos/dimagi/commcare-hq/contributors","subscribers_url":"https://api.github.com/repos/dimagi/commcare-hq/subscribers","subscription_url":"https://api.github.com/repos/dimagi/commcare-hq/subscription","commits_url":"https://api.github.com/repos/dimagi/commcare-hq/commits{/sha}","git_commits_url":"https://api.github.com/repos/dimagi/commcare-hq/git/commits{/sha}","comments_url":"https://api.github.com/repos/dimagi/commcare-hq/comments{/number}","issue_comment_url":"https://api.github.com/repos/dimagi/commcare-hq/issues/comments{/number}","contents_url":"https://api.github.com/repos/dimagi/commcare-hq/contents/{+path}","compare_url":"https://api.github.com/repos/dimagi/commcare-hq/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dimagi/commcare-hq/merges","archive_url":"https://api.github.com/repos/dimagi/commcare-hq/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dimagi/commcare-hq/downloads","issues_url":"https://api.github.com/repos/dimagi/commcare-hq/issues{/number}","pulls_url":"https://api.github.com/repos/dimagi/commcare-hq/pulls{/number}","milestones_url":"https://api.github.com/repos/dimagi/commcare-hq/milestones{/number}","notifications_url":"https://api.github.com/repos/dimagi/commcare-hq/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dimagi/commcare-hq/labels{/name}","releases_url":"https://api.github.com/repos/dimagi/commcare-hq/releases{/id}","deployments_url":"https://api.github.com/repos/dimagi/commcare-hq/deployments","created_at":"2009-07-09T17:00:07Z","updated_at":"2018-06-25T07:54:13Z","pushed_at":"2018-06-25T09:17:22Z","git_url":"git://github.com/dimagi/commcare-hq.git","ssh_url":"git@github.com:dimagi/commcare-hq.git","clone_url":"https://github.com/dimagi/commcare-hq.git","svn_url":"https://github.com/dimagi/commcare-hq","homepage":"https://www.commcarehq.org","size":444784,"stargazers_count":93,"watchers_count":93,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":106,"mirror_url":null,"archived":false,"open_issues_count":85,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":106,"open_issues":85,"watchers":93,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dimagi/commcare-hq/pulls/20874"},"html":{"href":"https://github.com/dimagi/commcare-hq/pull/20874"},"issue":{"href":"https://api.github.com/repos/dimagi/commcare-hq/issues/20874"},"comments":{"href":"https://api.github.com/repos/dimagi/commcare-hq/issues/20874/comments"},"review_comments":{"href":"https://api.github.com/repos/dimagi/commcare-hq/pulls/20874/comments"},"review_comment":{"href":"https://api.github.com/repos/dimagi/commcare-hq/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dimagi/commcare-hq/pulls/20874/commits"},"statuses":{"href":"https://api.github.com/repos/dimagi/commcare-hq/statuses/ba7b03e588b54067ef0813fe76e62a1435a1bab4"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"snopoke"}}