{"action":"created","comment":{"url":"https://api.github.com/repos/ome/training-scripts/pulls/comments/188070758","pull_request_review_id":119975843,"id":188070758,"diff_hunk":"@@ -0,0 +1,407 @@\n+#!/usr/bin/env python\n+# -*- coding: utf-8 -*-\n+\n+# -----------------------------------------------------------------------------\n+#   Copyright (C) 2018 University of Dundee. All rights reserved.\n+\n+#   This program is free software; you can redistribute it and/or modify\n+#   it under the terms of the GNU General Public License as published by\n+#   the Free Software Foundation; either version 2 of the License, or\n+#   (at your option) any later version.\n+#   This program is distributed in the hope that it will be useful,\n+#   but WITHOUT ANY WARRANTY; without even the implied warranty of\n+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+#   GNU General Public License for more details.\n+\n+#   You should have received a copy of the GNU General Public License along\n+#   with this program; if not, write to the Free Software Foundation, Inc.,\n+#   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n+\n+# ------------------------------------------------------------------------------\n+\n+\"\"\"This script exports ROI intensities for selected images.\"\"\"\n+\n+\n+import omero.scripts as scripts\n+from omero.gateway import BlitzGateway, MapAnnotationWrapper,\\\n+    FileAnnotationWrapper\n+from omero.rtypes import unwrap, rstring, rlong, robject\n+from omero.grid import DoubleColumn, ImageColumn\n+from omero.model import FileAnnotationI, OriginalFileI\n+from omero.constants.namespaces import NSBULKANNOTATIONS\n+\n+from collections import defaultdict\n+\n+DEFAULT_FILE_NAME = \"roi_intensities.csv\"\n+\n+\n+def log(data):\n+    \"\"\"Handle logging or printing in one place.\"\"\"\n+    print data\n+\n+\n+def get_export_data(conn, script_params, image):\n+    \"\"\"Get pixel data for shapes on image and returns list of dicts.\"\"\"\n+    log(\"Image ID %s...\" % image.id)\n+    roi_service = conn.getRoiService()\n+    all_planes = script_params[\"Export_All_Planes\"]\n+    size_c = image.getSizeC()\n+    # Channels index\n+    channels = script_params.get(\"Channels\", [1])\n+    ch_indexes = []\n+    for ch in channels:\n+        if ch < 1 or ch > size_c:\n+            log(\"Channel index: %s out of range 1 - %s\" % (ch, size_c))\n+        else:\n+            # User input is 1-based\n+            ch_indexes.append(ch - 1)\n+\n+    filter_ch = script_params.get(\"Filter_Shapes_By_Channel\")\n+    if filter_ch is not None:\n+        # convert to zero-based index\n+        filter_ch = filter_ch - 1\n+\n+    # For idr0021 use-case, we want to pick filter_channel dynamically...\n+    # First channel where channel name matches Dataset name.\n+    dataset_name = image.getParent().name\n+    for c, name in enumerate(image.getChannelLabels()):\n+        if name in dataset_name:\n+            filter_ch = c\n+\n+    ch_names = image.getChannelLabels()\n+\n+    ch_names = [ch_name.replace(\",\", \".\") for ch_name in ch_names]\n+    image_name = image.getName().replace(\",\", \".\")\n+\n+    result = roi_service.findByImage(image.getId(), None)\n+\n+    export_data = []\n+    print \"Filter_Shapes_By_Channel\", filter_ch\n+    for roi in result.rois:\n+        for shape in roi.copyShapes():\n+            if filter_ch is not None and filter_ch != unwrap(shape.theC):\n+                print filter_ch, \" != \", unwrap(shape.theC)\n+                continue\n+            label = unwrap(shape.getTextValue())\n+            # wrap label in double quotes in case it contains comma\n+            label = \"\" if label is None else '\"%s\"' % label.replace(\",\", \".\")\n+            shape_type = shape.__class__.__name__.rstrip('I').lower()\n+            # If shape has no Z or T, we may go through all planes...\n+            the_z = unwrap(shape.theZ)\n+            z_indexes = [the_z]\n+            if the_z is None and all_planes:\n+                z_indexes = range(image.getSizeZ())\n+            # Same for T...\n+            the_t = unwrap(shape.theT)\n+            t_indexes = [the_t]\n+            if the_t is None and all_planes:\n+                t_indexes = range(image.getSizeT())\n+\n+            # get pixel intensities\n+            for z in z_indexes:\n+                for t in t_indexes:\n+                    if z is None or t is None:\n+                        stats = None\n+                    else:\n+                        stats = roi_service.getShapeStatsRestricted(\n+                            [shape.id.val], z, t, ch_indexes)\n+                    for c, ch_index in enumerate(ch_indexes):\n+                        export_data.append({\n+                            \"image_id\": image.getId(),\n+                            \"image_name\": '\"%s\"' % image_name,\n+                            \"roi_id\": roi.id.val,\n+                            \"shape_id\": shape.id.val,\n+                            \"type\": shape_type,\n+                            \"text\": label,\n+                            \"z\": z + 1 if z is not None else \"\",\n+                            \"t\": t + 1 if t is not None else \"\",\n+                            \"channel\": ch_names[ch_index],\n+                            \"points\": stats[0].pointsCount[c] if stats else \"\",\n+                            \"min\": stats[0].min[c] if stats else \"\",\n+                            \"max\": stats[0].max[c] if stats else \"\",\n+                            \"sum\": stats[0].sum[c] if stats else \"\",\n+                            \"mean\": stats[0].mean[c] if stats else \"\",\n+                            \"std_dev\": stats[0].stdDev[c] if stats else \"\"\n+                        })\n+    return export_data\n+\n+\n+COLUMN_NAMES = [\"image_id\",\n+                \"image_name\",\n+                \"roi_id\",\n+                \"shape_id\",\n+                \"type\",\n+                \"text\",\n+                \"z\",\n+                \"t\",\n+                \"channel\",\n+                \"points\",\n+                \"min\",\n+                \"max\",\n+                \"sum\",\n+                \"mean\",\n+                \"std_dev\"]\n+\n+SUMMARY_COL_NAMES = [\"filter_shapes_by_channel\",\n+                     \"shape_count\",\n+                     \"min_intensity\",\n+                     \"max_intensity\",\n+                     \"mean_intensity\",\n+                     \"min_points\",\n+                     \"max_points\",\n+                     \"mean_points\"]\n+\n+\n+def link_table(conn, table, project):\n+    orig_file = table.getOriginalFile()\n+    file_ann = FileAnnotationWrapper(conn)\n+    file_ann.setNs(NSBULKANNOTATIONS)\n+    file_ann._obj.file = OriginalFileI(orig_file.id.val, False)\n+    file_ann.save()\n+    project.linkAnnotation(file_ann)\n+\n+\n+def write_csv(conn, export_data, script_params):\n+    \"\"\"Write the list of data to a CSV file and create a file annotation.\"\"\"\n+    file_name = script_params.get(\"File_Name\", \"\")\n+    if len(file_name) == 0:\n+        file_name = DEFAULT_FILE_NAME\n+    if not file_name.endswith(\".csv\"):\n+        file_name += \".csv\"\n+\n+    csv_rows = [\",\".join(COLUMN_NAMES)]\n+    for row in export_data:\n+        cells = [str(row.get(name)) for name in COLUMN_NAMES]\n+        csv_rows.append(\",\".join(cells))\n+\n+    with open(file_name, 'w') as csv_file:\n+        csv_file.write(\"\\n\".join(csv_rows))\n+\n+    return conn.createFileAnnfromLocalFile(file_name, mimetype=\"text/csv\")\n+\n+\n+def get_summary_data_for_image(conn, image, export_data, script_params):\n+    \"\"\"Summarise ROIs as dict for this Image.\"\"\"\n+    # get all ROI data for this image\n+    filter_ch = script_params.get('Filter_Shapes_By_Channel', '')\n+\n+    # For idr0021 use-case, we want to pick filter_channel dynamically...\n+    # First channel where channel name matches Dataset name.\n+    dataset_name = image.getParent().name\n+    for c, name in enumerate(image.getChannelLabels()):\n+        if name in dataset_name:\n+            filter_ch = c + 1\n+            break\n+\n+    data = [d for d in export_data if d['image_id'] == image.id]\n+    if len(data) == 0:\n+        return None\n+    min_intensity = min([d['min'] for d in data])\n+    max_intensity = max([d['max'] for d in data])\n+    mean_intensity = sum([d['mean'] for d in data]) / len(data)\n+    min_points = min([d['points'] for d in data])\n+    max_points = max([d['points'] for d in data])\n+    mean_points = sum([d['points'] for d in data]) / len(data)\n+\n+    return {\n+        \"filter_shapes_by_channel\": filter_ch,\n+        \"shape_count\": len(data),\n+        \"min_intensity\": min_intensity,\n+        \"max_intensity\": max_intensity,\n+        \"mean_intensity\": mean_intensity,\n+        \"min_points\": min_points,\n+        \"max_points\": max_points,\n+        \"mean_points\": mean_points,\n+    }\n+\n+\n+def save_table(conn, images, export_data, script_params):\n+    \"\"\"Summarise ROIs as Table (1 row per Image) linked to Project.\"\"\"\n+\n+    resources = conn.c.sf.sharedResources()\n+    repository_id = resources.repositories().descriptions[0].getId().getValue()\n+    table_name = \"batch_roi_export\"\n+    table = resources.newTable(repository_id, table_name)\n+\n+    # Summarise data into columns\n+    image_ids = [i.id for i in images]\n+    col_data = defaultdict(list)\n+\n+    for image in images:\n+        data = get_summary_data_for_image(conn, image, export_data,\n+                                          script_params)\n+        for key in SUMMARY_COL_NAMES:\n+            col_data[key].append(data[key] if data is not None else 0)\n+\n+    # Create table\n+    img_column = ImageColumn('Image', '', image_ids)\n+    cols = [DoubleColumn(k, '', col_data[k]) for k in SUMMARY_COL_NAMES]\n+    data = [img_column] + cols\n+    table.initialize(data)\n+    table.addData(data)\n+    table.close()\n+\n+    # Link Table to first Project we find\n+    project = None\n+    for image in images:\n+        project = image.getProject()\n+        if project is not None:\n+            break\n+    if project is None:\n+        log(\"No Project found to link table\")\n+    else:\n+        link_table(conn, table, project)\n+\n+\n+def save_map_annotations(conn, images, export_data, script_params):\n+    \"\"\"Summarise ROIs as Key-Value pairs for each Image.\"\"\"\n+    for image in images:\n+        data = get_summary_data_for_image(conn, image, export_data,\n+                                          script_params)\n+        if data is None:\n+            continue\n+        key_value_data = [[k, str(data[k])] for k in SUMMARY_COL_NAMES]\n+        map_ann = MapAnnotationWrapper(conn)\n+        # Use 'client' namespace to allow editing in Insight & web\n+        map_ann.setNs(\"omero.batch_roi_export.map_ann\")","path":"practical/python/server/batch_roi_export_to_table.py","position":266,"original_position":266,"commit_id":"eb17323f8b0e0c5cf6e51dea62a5b1fb6ebb801a","original_commit_id":"eb17323f8b0e0c5cf6e51dea62a5b1fb6ebb801a","user":{"login":"jburel","id":1022396,"avatar_url":"https://avatars1.githubusercontent.com/u/1022396?v=4","gravatar_id":"","url":"https://api.github.com/users/jburel","html_url":"https://github.com/jburel","followers_url":"https://api.github.com/users/jburel/followers","following_url":"https://api.github.com/users/jburel/following{/other_user}","gists_url":"https://api.github.com/users/jburel/gists{/gist_id}","starred_url":"https://api.github.com/users/jburel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jburel/subscriptions","organizations_url":"https://api.github.com/users/jburel/orgs","repos_url":"https://api.github.com/users/jburel/repos","events_url":"https://api.github.com/users/jburel/events{/privacy}","received_events_url":"https://api.github.com/users/jburel/received_events","type":"User","site_admin":false},"body":"use NS constant so it is clearer if someone wants to modify the script","created_at":"2018-05-14T19:31:25Z","updated_at":"2018-05-14T19:32:02Z","html_url":"https://github.com/ome/training-scripts/pull/9#discussion_r188070758","pull_request_url":"https://api.github.com/repos/ome/training-scripts/pulls/9","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/ome/training-scripts/pulls/comments/188070758"},"html":{"href":"https://github.com/ome/training-scripts/pull/9#discussion_r188070758"},"pull_request":{"href":"https://api.github.com/repos/ome/training-scripts/pulls/9"}}},"pull_request":{"url":"https://api.github.com/repos/ome/training-scripts/pulls/9","id":185578827,"html_url":"https://github.com/ome/training-scripts/pull/9","diff_url":"https://github.com/ome/training-scripts/pull/9.diff","patch_url":"https://github.com/ome/training-scripts/pull/9.patch","issue_url":"https://api.github.com/repos/ome/training-scripts/issues/9","number":9,"state":"open","locked":false,"title":"Analyse idr0021 users meeting 2018","user":{"login":"will-moore","id":900055,"avatar_url":"https://avatars2.githubusercontent.com/u/900055?v=4","gravatar_id":"","url":"https://api.github.com/users/will-moore","html_url":"https://github.com/will-moore","followers_url":"https://api.github.com/users/will-moore/followers","following_url":"https://api.github.com/users/will-moore/following{/other_user}","gists_url":"https://api.github.com/users/will-moore/gists{/gist_id}","starred_url":"https://api.github.com/users/will-moore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/will-moore/subscriptions","organizations_url":"https://api.github.com/users/will-moore/orgs","repos_url":"https://api.github.com/users/will-moore/repos","events_url":"https://api.github.com/users/will-moore/events{/privacy}","received_events_url":"https://api.github.com/users/will-moore/received_events","type":"User","site_admin":false},"body":"Various scripts to work with images from ```idr0021``` http://idr.openmicroscopy.org/webclient/?show=project-51.\r\n\r\nTo test:\r\n\r\n - Follow steps in maintenance/idr0021-data-prep.md walkthrough\r\n - Check that map annotations are added to Images (see below), and Project has bulk_annotations Table.\r\n - View & filter in OMERO.parade: Filtering by Table ```max_points``` < 50 should show images from most 2 Datasets:\r\n\r\n![screen shot 2018-05-07 at 11 54 59](https://user-images.githubusercontent.com/900055/39698681-a407df5a-51ed-11e8-95b2-b87d84bd637d.png)\r\n\r\nNB: the channel of interest for filtering shapes is different for every Dataset and even changes several times for images within a Dataset. The channel is shown in the Map Annotation and should refer to the Channel that is named the same as the Dataset.\r\n\r\n<img width=\"347\" alt=\"screen shot 2018-05-02 at 23 34 47\" src=\"https://user-images.githubusercontent.com/900055/39552527-7d1dd032-4e61-11e8-9788-eea0d3a09c7c.png\">\r\n\r\nTODO: As discussed with @pwalczysko, although we can filter for Shapes on a *single* Channel, we can choose to measure pixel intensity within those shapes for *multiple* channels. Currently all these intensities are averaged together, even for different channels (if we choose to export intensity for multiple channels) but we should keep these separate and report them as ```min_intensity_channel_1```, ```min_intensity_channel_2``` etc.","created_at":"2018-05-02T22:35:49Z","updated_at":"2018-05-14T19:32:02Z","closed_at":null,"merged_at":null,"merge_commit_sha":"635809b389b1db74651bf771e81e51317a7b1da0","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/ome/training-scripts/pulls/9/commits","review_comments_url":"https://api.github.com/repos/ome/training-scripts/pulls/9/comments","review_comment_url":"https://api.github.com/repos/ome/training-scripts/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ome/training-scripts/issues/9/comments","statuses_url":"https://api.github.com/repos/ome/training-scripts/statuses/eb17323f8b0e0c5cf6e51dea62a5b1fb6ebb801a","head":{"label":"will-moore:analyse_idr0021_users_meeting_2018","ref":"analyse_idr0021_users_meeting_2018","sha":"eb17323f8b0e0c5cf6e51dea62a5b1fb6ebb801a","user":{"login":"will-moore","id":900055,"avatar_url":"https://avatars2.githubusercontent.com/u/900055?v=4","gravatar_id":"","url":"https://api.github.com/users/will-moore","html_url":"https://github.com/will-moore","followers_url":"https://api.github.com/users/will-moore/followers","following_url":"https://api.github.com/users/will-moore/following{/other_user}","gists_url":"https://api.github.com/users/will-moore/gists{/gist_id}","starred_url":"https://api.github.com/users/will-moore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/will-moore/subscriptions","organizations_url":"https://api.github.com/users/will-moore/orgs","repos_url":"https://api.github.com/users/will-moore/repos","events_url":"https://api.github.com/users/will-moore/events{/privacy}","received_events_url":"https://api.github.com/users/will-moore/received_events","type":"User","site_admin":false},"repo":{"id":131912333,"name":"training-scripts","full_name":"will-moore/training-scripts","owner":{"login":"will-moore","id":900055,"avatar_url":"https://avatars2.githubusercontent.com/u/900055?v=4","gravatar_id":"","url":"https://api.github.com/users/will-moore","html_url":"https://github.com/will-moore","followers_url":"https://api.github.com/users/will-moore/followers","following_url":"https://api.github.com/users/will-moore/following{/other_user}","gists_url":"https://api.github.com/users/will-moore/gists{/gist_id}","starred_url":"https://api.github.com/users/will-moore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/will-moore/subscriptions","organizations_url":"https://api.github.com/users/will-moore/orgs","repos_url":"https://api.github.com/users/will-moore/repos","events_url":"https://api.github.com/users/will-moore/events{/privacy}","received_events_url":"https://api.github.com/users/will-moore/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/will-moore/training-scripts","description":"A set of scripts to access, analyse image and metadata from OMERO","fork":true,"url":"https://api.github.com/repos/will-moore/training-scripts","forks_url":"https://api.github.com/repos/will-moore/training-scripts/forks","keys_url":"https://api.github.com/repos/will-moore/training-scripts/keys{/key_id}","collaborators_url":"https://api.github.com/repos/will-moore/training-scripts/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/will-moore/training-scripts/teams","hooks_url":"https://api.github.com/repos/will-moore/training-scripts/hooks","issue_events_url":"https://api.github.com/repos/will-moore/training-scripts/issues/events{/number}","events_url":"https://api.github.com/repos/will-moore/training-scripts/events","assignees_url":"https://api.github.com/repos/will-moore/training-scripts/assignees{/user}","branches_url":"https://api.github.com/repos/will-moore/training-scripts/branches{/branch}","tags_url":"https://api.github.com/repos/will-moore/training-scripts/tags","blobs_url":"https://api.github.com/repos/will-moore/training-scripts/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/will-moore/training-scripts/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/will-moore/training-scripts/git/refs{/sha}","trees_url":"https://api.github.com/repos/will-moore/training-scripts/git/trees{/sha}","statuses_url":"https://api.github.com/repos/will-moore/training-scripts/statuses/{sha}","languages_url":"https://api.github.com/repos/will-moore/training-scripts/languages","stargazers_url":"https://api.github.com/repos/will-moore/training-scripts/stargazers","contributors_url":"https://api.github.com/repos/will-moore/training-scripts/contributors","subscribers_url":"https://api.github.com/repos/will-moore/training-scripts/subscribers","subscription_url":"https://api.github.com/repos/will-moore/training-scripts/subscription","commits_url":"https://api.github.com/repos/will-moore/training-scripts/commits{/sha}","git_commits_url":"https://api.github.com/repos/will-moore/training-scripts/git/commits{/sha}","comments_url":"https://api.github.com/repos/will-moore/training-scripts/comments{/number}","issue_comment_url":"https://api.github.com/repos/will-moore/training-scripts/issues/comments{/number}","contents_url":"https://api.github.com/repos/will-moore/training-scripts/contents/{+path}","compare_url":"https://api.github.com/repos/will-moore/training-scripts/compare/{base}...{head}","merges_url":"https://api.github.com/repos/will-moore/training-scripts/merges","archive_url":"https://api.github.com/repos/will-moore/training-scripts/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/will-moore/training-scripts/downloads","issues_url":"https://api.github.com/repos/will-moore/training-scripts/issues{/number}","pulls_url":"https://api.github.com/repos/will-moore/training-scripts/pulls{/number}","milestones_url":"https://api.github.com/repos/will-moore/training-scripts/milestones{/number}","notifications_url":"https://api.github.com/repos/will-moore/training-scripts/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/will-moore/training-scripts/labels{/name}","releases_url":"https://api.github.com/repos/will-moore/training-scripts/releases{/id}","deployments_url":"https://api.github.com/repos/will-moore/training-scripts/deployments","created_at":"2018-05-02T22:27:31Z","updated_at":"2018-05-02T22:27:33Z","pushed_at":"2018-05-14T14:37:48Z","git_url":"git://github.com/will-moore/training-scripts.git","ssh_url":"git@github.com:will-moore/training-scripts.git","clone_url":"https://github.com/will-moore/training-scripts.git","svn_url":"https://github.com/will-moore/training-scripts","homepage":null,"size":93,"stargazers_count":0,"watchers_count":0,"language":"Python","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":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"ome:master","ref":"master","sha":"f01298a117044c07930479201faffddbede704c0","user":{"login":"ome","id":1831717,"avatar_url":"https://avatars3.githubusercontent.com/u/1831717?v=4","gravatar_id":"","url":"https://api.github.com/users/ome","html_url":"https://github.com/ome","followers_url":"https://api.github.com/users/ome/followers","following_url":"https://api.github.com/users/ome/following{/other_user}","gists_url":"https://api.github.com/users/ome/gists{/gist_id}","starred_url":"https://api.github.com/users/ome/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ome/subscriptions","organizations_url":"https://api.github.com/users/ome/orgs","repos_url":"https://api.github.com/users/ome/repos","events_url":"https://api.github.com/users/ome/events{/privacy}","received_events_url":"https://api.github.com/users/ome/received_events","type":"Organization","site_admin":false},"repo":{"id":127337041,"name":"training-scripts","full_name":"ome/training-scripts","owner":{"login":"ome","id":1831717,"avatar_url":"https://avatars3.githubusercontent.com/u/1831717?v=4","gravatar_id":"","url":"https://api.github.com/users/ome","html_url":"https://github.com/ome","followers_url":"https://api.github.com/users/ome/followers","following_url":"https://api.github.com/users/ome/following{/other_user}","gists_url":"https://api.github.com/users/ome/gists{/gist_id}","starred_url":"https://api.github.com/users/ome/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ome/subscriptions","organizations_url":"https://api.github.com/users/ome/orgs","repos_url":"https://api.github.com/users/ome/repos","events_url":"https://api.github.com/users/ome/events{/privacy}","received_events_url":"https://api.github.com/users/ome/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ome/training-scripts","description":"A set of scripts to access, analyse image and metadata from OMERO","fork":false,"url":"https://api.github.com/repos/ome/training-scripts","forks_url":"https://api.github.com/repos/ome/training-scripts/forks","keys_url":"https://api.github.com/repos/ome/training-scripts/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ome/training-scripts/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ome/training-scripts/teams","hooks_url":"https://api.github.com/repos/ome/training-scripts/hooks","issue_events_url":"https://api.github.com/repos/ome/training-scripts/issues/events{/number}","events_url":"https://api.github.com/repos/ome/training-scripts/events","assignees_url":"https://api.github.com/repos/ome/training-scripts/assignees{/user}","branches_url":"https://api.github.com/repos/ome/training-scripts/branches{/branch}","tags_url":"https://api.github.com/repos/ome/training-scripts/tags","blobs_url":"https://api.github.com/repos/ome/training-scripts/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ome/training-scripts/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ome/training-scripts/git/refs{/sha}","trees_url":"https://api.github.com/repos/ome/training-scripts/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ome/training-scripts/statuses/{sha}","languages_url":"https://api.github.com/repos/ome/training-scripts/languages","stargazers_url":"https://api.github.com/repos/ome/training-scripts/stargazers","contributors_url":"https://api.github.com/repos/ome/training-scripts/contributors","subscribers_url":"https://api.github.com/repos/ome/training-scripts/subscribers","subscription_url":"https://api.github.com/repos/ome/training-scripts/subscription","commits_url":"https://api.github.com/repos/ome/training-scripts/commits{/sha}","git_commits_url":"https://api.github.com/repos/ome/training-scripts/git/commits{/sha}","comments_url":"https://api.github.com/repos/ome/training-scripts/comments{/number}","issue_comment_url":"https://api.github.com/repos/ome/training-scripts/issues/comments{/number}","contents_url":"https://api.github.com/repos/ome/training-scripts/contents/{+path}","compare_url":"https://api.github.com/repos/ome/training-scripts/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ome/training-scripts/merges","archive_url":"https://api.github.com/repos/ome/training-scripts/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ome/training-scripts/downloads","issues_url":"https://api.github.com/repos/ome/training-scripts/issues{/number}","pulls_url":"https://api.github.com/repos/ome/training-scripts/pulls{/number}","milestones_url":"https://api.github.com/repos/ome/training-scripts/milestones{/number}","notifications_url":"https://api.github.com/repos/ome/training-scripts/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ome/training-scripts/labels{/name}","releases_url":"https://api.github.com/repos/ome/training-scripts/releases{/id}","deployments_url":"https://api.github.com/repos/ome/training-scripts/deployments","created_at":"2018-03-29T19:17:49Z","updated_at":"2018-05-04T18:13:05Z","pushed_at":"2018-05-14T14:37:50Z","git_url":"git://github.com/ome/training-scripts.git","ssh_url":"git@github.com:ome/training-scripts.git","clone_url":"https://github.com/ome/training-scripts.git","svn_url":"https://github.com/ome/training-scripts","homepage":null,"size":77,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"archived":false,"open_issues_count":2,"license":null,"forks":4,"open_issues":2,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ome/training-scripts/pulls/9"},"html":{"href":"https://github.com/ome/training-scripts/pull/9"},"issue":{"href":"https://api.github.com/repos/ome/training-scripts/issues/9"},"comments":{"href":"https://api.github.com/repos/ome/training-scripts/issues/9/comments"},"review_comments":{"href":"https://api.github.com/repos/ome/training-scripts/pulls/9/comments"},"review_comment":{"href":"https://api.github.com/repos/ome/training-scripts/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ome/training-scripts/pulls/9/commits"},"statuses":{"href":"https://api.github.com/repos/ome/training-scripts/statuses/eb17323f8b0e0c5cf6e51dea62a5b1fb6ebb801a"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"jburel"}}