{"action":"created","comment":{"url":"https://api.github.com/repos/pepkit/looper/pulls/comments/197772373","pull_request_review_id":131578512,"id":197772373,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5Nzc3MjM3Mw==","diff_hunk":"@@ -555,20 +566,700 @@ def __call__(self, args, remaining_args):\n         \"\"\"\n \n \n-\n class Summarizer(Executor):\n     \"\"\" Project/Sample output summarizer \"\"\"\n-    \n+\n     def __call__(self):\n         \"\"\" Do the summarization. \"\"\"\n         import csv\n \n         columns = []\n         stats = []\n         figs = _pd.DataFrame()\n+        objs = _pd.DataFrame()\n+\n+        def create_figures_html(figs):\n+            figs_html_path = \"{root}_figs_summary.html\".format(\n+                root=os.path.join(self.prj.metadata.output_dir, self.prj.name))\n+            figs_html_file = open(figs_html_path, 'w')\n+            html_header = \"<html><h1>Summary of sample figures for project {}</h1>\\n\".format(self.prj.name)\n+            figs_html_file.write(html_header)\n+            sample_img_header = \"<h3>{sample_name}</h3>\\n\"\n+            sample_img_code = \"<p><a href='{path}'><img src='{path}'>{key}</a></p>\\n\"\n+            figs.drop_duplicates(keep='last', inplace=True)\n+            for sample_name in figs['sample_name'].drop_duplicates().sort_values():\n+                f = figs[figs['sample_name'] == sample_name]\n+                figs_html_file.write(\n+                    sample_img_header.format(sample_name=sample_name))\n+\n+                for i, row in f.iterrows():\n+                    figs_html_file.write(sample_img_code.format(\n+                        key=str(row['key']),\n+                        path=str(self.prj.metadata.results_subdir + '/' +\n+                                sample_name + '/' + row['value'])))\n+\n+            html_footer = \"</html>\"\n+            figs_html_file.write(html_footer)\n+            figs_html_file.close()\n+            _LOGGER.info(\n+                \"Summary (n=\" + str(len(stats)) + \"): \" + tsv_outfile_path)\n+\n+        def create_object_parent_html(objs):\n+            # Generates a page listing all the project objects with links\n+            # to individual object pages\n+            reports_dir = os.path.join(self.prj.metadata.output_dir,\n+                                       \"reports\")\n+            object_parent_path = os.path.join(reports_dir, \"objects.html\")\n+            if not os.path.exists(os.path.dirname(object_parent_path)):\n+                os.makedirs(os.path.dirname(object_parent_path))\n+            with open(object_parent_path, 'w') as html_file:\n+                html_file.write(HTML_HEAD_OPEN)\n+                html_file.write(create_navbar(objs, reports_dir))\n+                html_file.write(HTML_HEAD_CLOSE)\n+                html_file.write(GENERIC_HEADER.format(header=\"Objects\"))\n+                html_file.write(GENERIC_LIST_HEADER)\n+                for key in objs['key'].drop_duplicates().sort_values():\n+                    page_name = key + \".html\"\n+                    page_path = os.path.join(reports_dir, page_name.replace(' ', '_').lower())\n+                    page_relpath = os.path.relpath(page_path, reports_dir)\n+                    html_file.write(GENERIC_LIST_ENTRY.format(\n+                                    page=page_relpath, label=key))\n+                html_file.write(HTML_FOOTER)\n+                html_file.close()\n+\n+        def create_sample_parent_html(objs):\n+            # Generates a page listing all the project samples with links\n+            # to individual sample pages\n+            reports_dir = os.path.join(self.prj.metadata.output_dir,\n+                                       \"reports\")\n+            sample_parent_path = os.path.join(reports_dir, \"samples.html\")\n+            if not os.path.exists(os.path.dirname(sample_parent_path)):\n+                os.makedirs(os.path.dirname(sample_parent_path))\n+            with open(sample_parent_path, 'w') as html_file:\n+                html_file.write(HTML_HEAD_OPEN)\n+                html_file.write(create_navbar(objs, reports_dir))\n+                html_file.write(HTML_HEAD_CLOSE)\n+                html_file.write(GENERIC_HEADER.format(header=\"Samples\"))\n+                html_file.write(GENERIC_LIST_HEADER)\n+                for sample in self.prj.samples:\n+                    sample_name = str(sample.sample_name)\n+                    page_name = sample_name + \".html\"\n+                    page_path = os.path.join(reports_dir, page_name.replace(' ', '_').lower())\n+                    page_relpath = os.path.relpath(page_path, reports_dir)\n+                    html_file.write(GENERIC_LIST_ENTRY.format(\n+                                    page=page_relpath, label=sample_name))\n+                html_file.write(HTML_FOOTER)\n+                html_file.close()\n+\n+        def create_object_html(objs, nb, type, filename, index_html):\n+            # Generates a page for an individual object type with all of its\n+            # plots from each sample\n+            reports_dir = os.path.join(self.prj.metadata.output_dir, \"reports\")\n+            object_path = os.path.join(reports_dir,\n+                                       filename.replace(' ', '_').lower())\n+            if not os.path.exists(os.path.dirname(object_path)):\n+                os.makedirs(os.path.dirname(object_path))\n+            with open(object_path, 'w') as html_file:\n+                html_file.write(HTML_HEAD_OPEN)\n+                html_file.write(create_navbar(nb, reports_dir))\n+                html_file.write(HTML_HEAD_CLOSE)\n+                html_file.write(\"\\t\\t<h4>{} objects</h4>\\n\".format(str(type)))\n+                links = []\n+                figures = []\n+                warnings = []\n+                for i, row in objs.iterrows():\n+                    page_path = os.path.join(\n+                                 self.prj.metadata.results_subdir,\n+                                 row['sample_name'], row['filename'])\n+                    image_path = os.path.join(\n+                                  self.prj.metadata.results_subdir,\n+                                  row['sample_name'], row['anchor_image'])\n+                    page_relpath = os.path.relpath(page_path, reports_dir)\n+                    # Check for the presence of both the file and thumbnail\n+                    if os.path.isfile(image_path) and os.path.isfile(page_path):\n+                        image_relpath = os.path.relpath(image_path, reports_dir)\n+                        # If the object has a valid image, use it!\n+                        if str(image_path).lower().endswith(('.png', '.jpg', '.jpeg', '.svg', '.gif')):\n+                            figures.append(OBJECTS_PLOTS.format(\n+                                            path=page_relpath,\n+                                            image=image_relpath,\n+                                            label=str(row['sample_name'])))\n+                        # Otherwise treat as a link\n+                        elif os.path.isfile(page_path):\n+                            links.append(GENERIC_LIST_ENTRY.format(\n+                                            page=page_relpath,\n+                                            label=str(row['sample_name'])))\n+                        else:\n+                            warnings.append(str(row['filename']))\n+                    # If no thumbnail image is present, add as a link\n+                    elif os.path.isfile(page_path):\n+                        links.append(GENERIC_LIST_ENTRY.format(\n+                                        page=page_relpath,\n+                                        label=str(row['sample_name'])))\n+                    else:\n+                        warnings.append(str(row['filename']))\n+\n+                html_file.write(GENERIC_LIST_HEADER)\n+                html_file.write(\"\\n\".join(links))\n+                html_file.write(GENERIC_LIST_FOOTER)\n+                html_file.write(\"\\t\\t\\t<hr>\\n\")\n+                html_file.write(\"\\n\".join(figures))\n+                html_file.write(\"\\t\\t\\t<hr>\\n\")\n+                html_file.write(HTML_FOOTER)\n+                html_file.close()\n+\n+            if warnings:\n+                _LOGGER.warn(\"Warning: \" + filename.replace(' ', '_').lower() +\n+                             \" references nonexistent object files\")\n+                _LOGGER.debug(filename.replace(' ', '_').lower() +\n+                              \" nonexistent files: \" +\n+                              ','.join(str(file) for file in warnings))\n+\n+        def create_status_html(all_samples):\n+            # Generates a page listing all the samples, their run status, their\n+            # log file, and the total runtime if completed.\n+            reports_dir = os.path.join(self.prj.metadata.output_dir, \"reports\")\n+            status_html_path = os.path.join(reports_dir, \"status.html\")\n+            if not os.path.exists(os.path.dirname(status_html_path)):\n+                os.makedirs(os.path.dirname(status_html_path))\n+            with open(status_html_path, 'w') as html_file:\n+                html_file.write(HTML_HEAD_OPEN)\n+                html_file.write(create_navbar(all_samples, reports_dir))\n+                html_file.write(HTML_HEAD_CLOSE)\n+                html_file.write(STATUS_HEADER)\n+                html_file.write(STATUS_TABLE_HEAD)\n+                warnings = []\n+                for sample in self.prj.samples:\n+                    sample_name = str(sample.sample_name)\n+                    # Grab the status flag for the current sample\n+                    flag = glob.glob(os.path.join(\n+                                        self.prj.metadata.results_subdir,\n+                                        sample_name, '*.flag'))\n+                    if \"completed\" in str(flag):\n+                        button_class = \"table-success\"\n+                        flag = \"Completed\"\n+                    elif \"running\" in str(flag):\n+                        button_class = \"table-warning\"\n+                        flag = \"Running\"\n+                    elif \"failed\" in str(flag):\n+                        button_class = \"table-danger\"\n+                        flag = \"Failed\"\n+                    else:\n+                        button_class = \"table-secondary\"\n+                        flag = \"Unknown\"\n+\n+                    # Create table entry for each sample\n+                    html_file.write(STATUS_ROW_HEADER)\n+                    # First Col: Sample_Name (w/ link to sample page)\n+                    page_name = sample_name + \".html\"\n+                    page_path = os.path.join(reports_dir, page_name.replace(' ', '_').lower())\n+                    page_relpath = os.path.relpath(page_path, reports_dir)\n+                    html_file.write(STATUS_ROW_LINK.format(\n+                                        row_class=\"\",\n+                                        file_link=page_relpath,\n+                                        link_name=sample_name))\n+                    # Second Col: Status (color-coded)\n+                    html_file.write(STATUS_ROW_VALUE.format(\n+                                        row_class=button_class,\n+                                        value=flag))\n+                    # Third Col: Log File (w/ link to file)\n+                    single_sample = all_samples[all_samples['sample_name'] == sample_name]\n+                    if single_sample.empty:\n+                        # When there is no objects.tsv file, search for the\n+                        # presence of log, profile, and command files\n+                        log_name = os.path.basename(str(glob.glob(os.path.join(\n+                                    self.prj.metadata.results_subdir,\n+                                    sample_name, '*log.md'))[0]))\n+                        # Currently unused. Future?\n+                        # profile_name = os.path.basename(str(glob.glob(os.path.join(\n+                                            # self.prj.metadata.results_subdir,\n+                                            # sample_name, '*profile.tsv'))[0]))\n+                        # command_name = os.path.basename(str(glob.glob(os.path.join(\n+                                            # self.prj.metadata.results_subdir,\n+                                            # sample_name, '*commands.sh'))[0]))\n+                    else:\n+                        log_name = str(single_sample.iloc[0]['annotation']) + \"_log.md\"\n+                        # Currently unused. Future?\n+                        # profile_name = str(single_sample.iloc[0]['annotation']) + \"_profile.tsv\"\n+                        # command_name = str(single_sample.iloc[0]['annotation']) + \"_commands.sh\"\n+                    log_file = os.path.join(self.prj.metadata.results_subdir,\n+                                            sample_name, log_name)\n+                    log_relpath = os.path.relpath(log_file, reports_dir)\n+                    if os.path.isfile(log_file):\n+                        html_file.write(STATUS_ROW_LINK.format(\n+                                            row_class=\"\",\n+                                            file_link=log_relpath,\n+                                            link_name=log_name))\n+                    else:\n+                        # Leave cell empty\n+                        html_file.write(STATUS_ROW_LINK.format(\n+                                            row_class=\"\",\n+                                            file_link=\"\",\n+                                            link_name=\"\"))\n+                    # Fourth Col: Sample runtime (if completed)\n+                    # If Completed, use stats.tsv\n+                    stats_file = os.path.join(\n+                                    self.prj.metadata.results_subdir,\n+                                    sample_name, \"stats.tsv\")\n+                    if os.path.isfile(stats_file):\n+                        t = _pd.read_table(stats_file, header=None,\n+                                           names=['key', 'value', 'pl'])\n+                        t.drop_duplicates(subset=['key', 'pl'],\n+                                          keep='last', inplace=True)\n+                        try:\n+                            time = str(t[t['key'] == 'Time'].iloc[0]['value'])\n+                            html_file.write(STATUS_ROW_VALUE.format(\n+                                            row_class=\"\",\n+                                            value=str(time)))\n+                        except IndexError:\n+                            warnings.append(\"The stats_summary.tsv file is incomplete\")                        \n+                    else:\n+                        html_file.write(STATUS_ROW_VALUE.format(\n+                                            row_class=button_class,\n+                                            value=\"Unknown\"))\n+                    html_file.write(STATUS_ROW_FOOTER)\n+\n+                html_file.write(STATUS_FOOTER)\n+                html_file.write(HTML_FOOTER)\n+                html_file.close()\n+                if warnings:\n+                    _LOGGER.warn(\"Warning: \" + ''.join(list(set(warnings))))\n+\n+        def create_sample_html(all_samples, sample_name, sample_stats,\n+                               index_html):\n+            # Produce an HTML page containing all of a sample's objects\n+            # and the sample summary statistics\n+            reports_dir = os.path.join(self.prj.metadata.output_dir, \"reports\")\n+            html_filename = sample_name + \".html\"\n+            html_page = os.path.join(\n+                reports_dir, html_filename.replace(' ', '_').lower())\n+            sample_page_relpath = os.path.relpath(\n+                html_page, self.prj.metadata.output_dir)\n+            single_sample = all_samples[all_samples['sample_name'] == sample_name]\n+            if not os.path.exists(os.path.dirname(html_page)):\n+                os.makedirs(os.path.dirname(html_page))\n+            with open(html_page, 'w') as html_file:\n+                html_file.write(HTML_HEAD_OPEN)\n+                html_file.write(\"\\t\\t<style>\\n\")\n+                html_file.write(SAMPLE_TABLE_STYLE)\n+                html_file.write(\"\\t\\t</style>\\n\")\n+                html_file.write(create_navbar(all_samples, reports_dir))\n+                html_file.write(HTML_HEAD_CLOSE)\n+                html_file.write(\"\\t\\t<h4>{}</h4>\\n\".format(str(sample_name)))\n+                if single_sample.empty:\n+                    # When there is no objects.tsv file, search for the\n+                    # presence of log, profile, and command files\n+                    log_name = os.path.basename(str(glob.glob(os.path.join(","path":"looper/looper.py","position":541,"original_position":541,"commit_id":"98ff1487dc7eb1f356dc262057e52440e5683e19","original_commit_id":"98ff1487dc7eb1f356dc262057e52440e5683e19","user":{"login":"nsheff","id":5271009,"node_id":"MDQ6VXNlcjUyNzEwMDk=","avatar_url":"https://avatars2.githubusercontent.com/u/5271009?v=4","gravatar_id":"","url":"https://api.github.com/users/nsheff","html_url":"https://github.com/nsheff","followers_url":"https://api.github.com/users/nsheff/followers","following_url":"https://api.github.com/users/nsheff/following{/other_user}","gists_url":"https://api.github.com/users/nsheff/gists{/gist_id}","starred_url":"https://api.github.com/users/nsheff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nsheff/subscriptions","organizations_url":"https://api.github.com/users/nsheff/orgs","repos_url":"https://api.github.com/users/nsheff/repos","events_url":"https://api.github.com/users/nsheff/events{/privacy}","received_events_url":"https://api.github.com/users/nsheff/received_events","type":"User","site_admin":false},"body":"can we just use `prj.logfile` in this case? I'm pretty sure the log filename is an attribute of the project.","created_at":"2018-06-25T12:09:09Z","updated_at":"2018-06-25T12:09:09Z","html_url":"https://github.com/pepkit/looper/pull/39#discussion_r197772373","pull_request_url":"https://api.github.com/repos/pepkit/looper/pulls/39","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/pepkit/looper/pulls/comments/197772373"},"html":{"href":"https://github.com/pepkit/looper/pull/39#discussion_r197772373"},"pull_request":{"href":"https://api.github.com/repos/pepkit/looper/pulls/39"}},"in_reply_to_id":197693677},"pull_request":{"url":"https://api.github.com/repos/pepkit/looper/pulls/39","id":196789012,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk2Nzg5MDEy","html_url":"https://github.com/pepkit/looper/pull/39","diff_url":"https://github.com/pepkit/looper/pull/39.diff","patch_url":"https://github.com/pepkit/looper/pull/39.patch","issue_url":"https://api.github.com/repos/pepkit/looper/issues/39","number":39,"state":"open","locked":false,"title":"version 0.9 release","user":{"login":"nsheff","id":5271009,"node_id":"MDQ6VXNlcjUyNzEwMDk=","avatar_url":"https://avatars2.githubusercontent.com/u/5271009?v=4","gravatar_id":"","url":"https://api.github.com/users/nsheff","html_url":"https://github.com/nsheff","followers_url":"https://api.github.com/users/nsheff/followers","following_url":"https://api.github.com/users/nsheff/following{/other_user}","gists_url":"https://api.github.com/users/nsheff/gists{/gist_id}","starred_url":"https://api.github.com/users/nsheff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nsheff/subscriptions","organizations_url":"https://api.github.com/users/nsheff/orgs","repos_url":"https://api.github.com/users/nsheff/repos","events_url":"https://api.github.com/users/nsheff/events{/privacy}","received_events_url":"https://api.github.com/users/nsheff/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-06-22T16:40:20Z","updated_at":"2018-06-25T12:09:09Z","closed_at":null,"merged_at":null,"merge_commit_sha":"08be22f4a37a69f9c281e5f0ec2076a10fa23544","assignee":null,"assignees":[],"requested_reviewers":[{"login":"afrendeiro","id":2065206,"node_id":"MDQ6VXNlcjIwNjUyMDY=","avatar_url":"https://avatars1.githubusercontent.com/u/2065206?v=4","gravatar_id":"","url":"https://api.github.com/users/afrendeiro","html_url":"https://github.com/afrendeiro","followers_url":"https://api.github.com/users/afrendeiro/followers","following_url":"https://api.github.com/users/afrendeiro/following{/other_user}","gists_url":"https://api.github.com/users/afrendeiro/gists{/gist_id}","starred_url":"https://api.github.com/users/afrendeiro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/afrendeiro/subscriptions","organizations_url":"https://api.github.com/users/afrendeiro/orgs","repos_url":"https://api.github.com/users/afrendeiro/repos","events_url":"https://api.github.com/users/afrendeiro/events{/privacy}","received_events_url":"https://api.github.com/users/afrendeiro/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/pepkit/looper/pulls/39/commits","review_comments_url":"https://api.github.com/repos/pepkit/looper/pulls/39/comments","review_comment_url":"https://api.github.com/repos/pepkit/looper/pulls/comments{/number}","comments_url":"https://api.github.com/repos/pepkit/looper/issues/39/comments","statuses_url":"https://api.github.com/repos/pepkit/looper/statuses/98ff1487dc7eb1f356dc262057e52440e5683e19","head":{"label":"pepkit:dev","ref":"dev","sha":"98ff1487dc7eb1f356dc262057e52440e5683e19","user":{"login":"pepkit","id":29280461,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5MjgwNDYx","avatar_url":"https://avatars1.githubusercontent.com/u/29280461?v=4","gravatar_id":"","url":"https://api.github.com/users/pepkit","html_url":"https://github.com/pepkit","followers_url":"https://api.github.com/users/pepkit/followers","following_url":"https://api.github.com/users/pepkit/following{/other_user}","gists_url":"https://api.github.com/users/pepkit/gists{/gist_id}","starred_url":"https://api.github.com/users/pepkit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pepkit/subscriptions","organizations_url":"https://api.github.com/users/pepkit/orgs","repos_url":"https://api.github.com/users/pepkit/repos","events_url":"https://api.github.com/users/pepkit/events{/privacy}","received_events_url":"https://api.github.com/users/pepkit/received_events","type":"Organization","site_admin":false},"repo":{"id":110996406,"node_id":"MDEwOlJlcG9zaXRvcnkxMTA5OTY0MDY=","name":"looper","full_name":"pepkit/looper","owner":{"login":"pepkit","id":29280461,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5MjgwNDYx","avatar_url":"https://avatars1.githubusercontent.com/u/29280461?v=4","gravatar_id":"","url":"https://api.github.com/users/pepkit","html_url":"https://github.com/pepkit","followers_url":"https://api.github.com/users/pepkit/followers","following_url":"https://api.github.com/users/pepkit/following{/other_user}","gists_url":"https://api.github.com/users/pepkit/gists{/gist_id}","starred_url":"https://api.github.com/users/pepkit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pepkit/subscriptions","organizations_url":"https://api.github.com/users/pepkit/orgs","repos_url":"https://api.github.com/users/pepkit/repos","events_url":"https://api.github.com/users/pepkit/events{/privacy}","received_events_url":"https://api.github.com/users/pepkit/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pepkit/looper","description":"A job submitter that uses Portable Encapsulated Projects","fork":false,"url":"https://api.github.com/repos/pepkit/looper","forks_url":"https://api.github.com/repos/pepkit/looper/forks","keys_url":"https://api.github.com/repos/pepkit/looper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pepkit/looper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pepkit/looper/teams","hooks_url":"https://api.github.com/repos/pepkit/looper/hooks","issue_events_url":"https://api.github.com/repos/pepkit/looper/issues/events{/number}","events_url":"https://api.github.com/repos/pepkit/looper/events","assignees_url":"https://api.github.com/repos/pepkit/looper/assignees{/user}","branches_url":"https://api.github.com/repos/pepkit/looper/branches{/branch}","tags_url":"https://api.github.com/repos/pepkit/looper/tags","blobs_url":"https://api.github.com/repos/pepkit/looper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pepkit/looper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pepkit/looper/git/refs{/sha}","trees_url":"https://api.github.com/repos/pepkit/looper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pepkit/looper/statuses/{sha}","languages_url":"https://api.github.com/repos/pepkit/looper/languages","stargazers_url":"https://api.github.com/repos/pepkit/looper/stargazers","contributors_url":"https://api.github.com/repos/pepkit/looper/contributors","subscribers_url":"https://api.github.com/repos/pepkit/looper/subscribers","subscription_url":"https://api.github.com/repos/pepkit/looper/subscription","commits_url":"https://api.github.com/repos/pepkit/looper/commits{/sha}","git_commits_url":"https://api.github.com/repos/pepkit/looper/git/commits{/sha}","comments_url":"https://api.github.com/repos/pepkit/looper/comments{/number}","issue_comment_url":"https://api.github.com/repos/pepkit/looper/issues/comments{/number}","contents_url":"https://api.github.com/repos/pepkit/looper/contents/{+path}","compare_url":"https://api.github.com/repos/pepkit/looper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pepkit/looper/merges","archive_url":"https://api.github.com/repos/pepkit/looper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pepkit/looper/downloads","issues_url":"https://api.github.com/repos/pepkit/looper/issues{/number}","pulls_url":"https://api.github.com/repos/pepkit/looper/pulls{/number}","milestones_url":"https://api.github.com/repos/pepkit/looper/milestones{/number}","notifications_url":"https://api.github.com/repos/pepkit/looper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pepkit/looper/labels{/name}","releases_url":"https://api.github.com/repos/pepkit/looper/releases{/id}","deployments_url":"https://api.github.com/repos/pepkit/looper/deployments","created_at":"2017-11-16T16:39:21Z","updated_at":"2018-04-07T19:50:15Z","pushed_at":"2018-06-22T17:52:22Z","git_url":"git://github.com/pepkit/looper.git","ssh_url":"git@github.com:pepkit/looper.git","clone_url":"https://github.com/pepkit/looper.git","svn_url":"https://github.com/pepkit/looper","homepage":"http://looper.readthedocs.io","size":1873,"stargazers_count":3,"watchers_count":3,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"archived":false,"open_issues_count":22,"license":{"key":"bsd-2-clause","name":"BSD 2-Clause \"Simplified\" License","spdx_id":"BSD-2-Clause","url":"https://api.github.com/licenses/bsd-2-clause","node_id":"MDc6TGljZW5zZTQ="},"forks":2,"open_issues":22,"watchers":3,"default_branch":"master"}},"base":{"label":"pepkit:master","ref":"master","sha":"7751d1ecf61767e33372984fe456d2db78343f65","user":{"login":"pepkit","id":29280461,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5MjgwNDYx","avatar_url":"https://avatars1.githubusercontent.com/u/29280461?v=4","gravatar_id":"","url":"https://api.github.com/users/pepkit","html_url":"https://github.com/pepkit","followers_url":"https://api.github.com/users/pepkit/followers","following_url":"https://api.github.com/users/pepkit/following{/other_user}","gists_url":"https://api.github.com/users/pepkit/gists{/gist_id}","starred_url":"https://api.github.com/users/pepkit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pepkit/subscriptions","organizations_url":"https://api.github.com/users/pepkit/orgs","repos_url":"https://api.github.com/users/pepkit/repos","events_url":"https://api.github.com/users/pepkit/events{/privacy}","received_events_url":"https://api.github.com/users/pepkit/received_events","type":"Organization","site_admin":false},"repo":{"id":110996406,"node_id":"MDEwOlJlcG9zaXRvcnkxMTA5OTY0MDY=","name":"looper","full_name":"pepkit/looper","owner":{"login":"pepkit","id":29280461,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5MjgwNDYx","avatar_url":"https://avatars1.githubusercontent.com/u/29280461?v=4","gravatar_id":"","url":"https://api.github.com/users/pepkit","html_url":"https://github.com/pepkit","followers_url":"https://api.github.com/users/pepkit/followers","following_url":"https://api.github.com/users/pepkit/following{/other_user}","gists_url":"https://api.github.com/users/pepkit/gists{/gist_id}","starred_url":"https://api.github.com/users/pepkit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pepkit/subscriptions","organizations_url":"https://api.github.com/users/pepkit/orgs","repos_url":"https://api.github.com/users/pepkit/repos","events_url":"https://api.github.com/users/pepkit/events{/privacy}","received_events_url":"https://api.github.com/users/pepkit/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pepkit/looper","description":"A job submitter that uses Portable Encapsulated Projects","fork":false,"url":"https://api.github.com/repos/pepkit/looper","forks_url":"https://api.github.com/repos/pepkit/looper/forks","keys_url":"https://api.github.com/repos/pepkit/looper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pepkit/looper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pepkit/looper/teams","hooks_url":"https://api.github.com/repos/pepkit/looper/hooks","issue_events_url":"https://api.github.com/repos/pepkit/looper/issues/events{/number}","events_url":"https://api.github.com/repos/pepkit/looper/events","assignees_url":"https://api.github.com/repos/pepkit/looper/assignees{/user}","branches_url":"https://api.github.com/repos/pepkit/looper/branches{/branch}","tags_url":"https://api.github.com/repos/pepkit/looper/tags","blobs_url":"https://api.github.com/repos/pepkit/looper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pepkit/looper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pepkit/looper/git/refs{/sha}","trees_url":"https://api.github.com/repos/pepkit/looper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pepkit/looper/statuses/{sha}","languages_url":"https://api.github.com/repos/pepkit/looper/languages","stargazers_url":"https://api.github.com/repos/pepkit/looper/stargazers","contributors_url":"https://api.github.com/repos/pepkit/looper/contributors","subscribers_url":"https://api.github.com/repos/pepkit/looper/subscribers","subscription_url":"https://api.github.com/repos/pepkit/looper/subscription","commits_url":"https://api.github.com/repos/pepkit/looper/commits{/sha}","git_commits_url":"https://api.github.com/repos/pepkit/looper/git/commits{/sha}","comments_url":"https://api.github.com/repos/pepkit/looper/comments{/number}","issue_comment_url":"https://api.github.com/repos/pepkit/looper/issues/comments{/number}","contents_url":"https://api.github.com/repos/pepkit/looper/contents/{+path}","compare_url":"https://api.github.com/repos/pepkit/looper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pepkit/looper/merges","archive_url":"https://api.github.com/repos/pepkit/looper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pepkit/looper/downloads","issues_url":"https://api.github.com/repos/pepkit/looper/issues{/number}","pulls_url":"https://api.github.com/repos/pepkit/looper/pulls{/number}","milestones_url":"https://api.github.com/repos/pepkit/looper/milestones{/number}","notifications_url":"https://api.github.com/repos/pepkit/looper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pepkit/looper/labels{/name}","releases_url":"https://api.github.com/repos/pepkit/looper/releases{/id}","deployments_url":"https://api.github.com/repos/pepkit/looper/deployments","created_at":"2017-11-16T16:39:21Z","updated_at":"2018-04-07T19:50:15Z","pushed_at":"2018-06-22T17:52:22Z","git_url":"git://github.com/pepkit/looper.git","ssh_url":"git@github.com:pepkit/looper.git","clone_url":"https://github.com/pepkit/looper.git","svn_url":"https://github.com/pepkit/looper","homepage":"http://looper.readthedocs.io","size":1873,"stargazers_count":3,"watchers_count":3,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"archived":false,"open_issues_count":22,"license":{"key":"bsd-2-clause","name":"BSD 2-Clause \"Simplified\" License","spdx_id":"BSD-2-Clause","url":"https://api.github.com/licenses/bsd-2-clause","node_id":"MDc6TGljZW5zZTQ="},"forks":2,"open_issues":22,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/pepkit/looper/pulls/39"},"html":{"href":"https://github.com/pepkit/looper/pull/39"},"issue":{"href":"https://api.github.com/repos/pepkit/looper/issues/39"},"comments":{"href":"https://api.github.com/repos/pepkit/looper/issues/39/comments"},"review_comments":{"href":"https://api.github.com/repos/pepkit/looper/pulls/39/comments"},"review_comment":{"href":"https://api.github.com/repos/pepkit/looper/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/pepkit/looper/pulls/39/commits"},"statuses":{"href":"https://api.github.com/repos/pepkit/looper/statuses/98ff1487dc7eb1f356dc262057e52440e5683e19"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"nsheff"}}