{"action":"created","comment":{"url":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/comments/170133577","pull_request_review_id":98761660,"id":170133577,"diff_hunk":"@@ -25,312 +41,567 @@ export function mockAPI(mock_api) {\n // ---- Our Store ----\n // Master state for the workflow. Export so that components can store.dispatch()\n // var so it can be mocked for testing\n-export var store = createStore(workflowReducer, window.initState, applyMiddleware(promiseMiddleware));\n+export var store = createStore(workflowReducer, window.initState, applyMiddleware( promiseMiddleware(), thunk ));\n \n export function mockStore(mock_store) {\n   store = mock_store;\n }\n \n+const reducerFunc = {};\n+\n+const registerReducerFunc = (key, func) => {\n+  reducerFunc[key] = func;\n+};\n+\n+// ---- Utilities ----\n+\n+const findIdxByProp = (searchArray, searchProp, searchValue) => {\n+  let returnIdx;\n+  for (let i = 0; i < searchArray.length; i++) {\n+    if (searchArray[i][searchProp] === searchValue) {\n+      returnIdx = i;\n+      break;\n+    }\n+  }\n+  return returnIdx;\n+};\n+\n+\n // ---- Actions ----\n \n-// Load the whole workflow. Returns a promise which returns an action to dispatch when it completes\n-export function reloadWorkflowAction() {\n-  return (\n-    api.loadWorkflow(getPageID())\n-    .then(json => ({  type: RELOAD_WORKFLOW, workflow: json }))\n-  )\n-}\n+// -- Workflow --\n+\n \n+// INITIAL_LOAD_WORKFLOW\n+// Load the workflow for the first time\n export function initialLoadWorkflowAction() {\n-  return (\n-    api.loadWorkflow(getPageID())\n-    .then(json => ({ type: INITIAL_LOAD_WORKFLOW, workflow: json }))\n-  )\n+  return {\n+    type: INITIAL_LOAD_WORKFLOW,\n+    payload: api.loadWorkflow(getPageID()).then((json) => {return json})\n+  }\n }\n+registerReducerFunc(INITIAL_LOAD_WORKFLOW + '_FULFILLED', (state, action) => {\n+  // Sets the selected module from backend if it exists, or the first module if there are any at all\n+  console.log(\"INITIAL_LOAD_WORKFLOW\");\n+  let selectedWfModule = null;\n+\n+  if (action.payload.selected_wf_module) {\n+    selectedWfModule = action.payload.selected_wf_module;\n+  } else if (action.payload.wf_modules && action.payload.wf_modules.length) {\n+    selectedWfModule = action.payload.wf_modules[0].id;\n+  }\n \n-// Make an addModule call, then reload the workflow\n+  return Object.assign({}, state, {\n+    selected_wf_module: selectedWfModule,\n+    workflow: action.payload\n+  });\n+});\n+\n+// RELOAD_WORKFLOW\n+// Re-load the workflow\n+// TODO: Do we need both initial and reload?\n+export function reloadWorkflowAction() {\n+  return {\n+    type: RELOAD_WORKFLOW,\n+    payload: api.loadWorkflow(getPageID()).then((json) => {return json})\n+  }\n+}\n+registerReducerFunc(RELOAD_WORKFLOW + '_FULFILLED', (state, action) => {\n+  console.log(\"RELOAD_WORKFLOW\");\n+  console.log(\"new workflow revision \" + action.payload.revision);\n+  /*var selectedWfModule = null;\n+  if (action.payload.selected_wf_module) {\n+    selectedWfModule = action.payload.selected_wf_module;\n+  } else if (action.payload.wf_modules && action.payload.wf_modules.length) {\n+    selectedWfModule = action.payload.wf_modules[0].id;\n+  };*/\n+  return update(state, {\n+    //selected_wf_module: {$set: selectedWfModule},\n+    workflow: {$merge: action.payload}\n+  });\n+});\n+\n+\n+// ADD_MODULE\n+// Add a module, then save the new module as the selected workflow\n export function addModuleAction(moduleId, insertBefore) {\n-  return (\n-    api.addModule(getPageID(), moduleId, insertBefore)\n-    .then( data => store.dispatch(changeSelectedWfModuleAction(data.id)))\n-    .then( reloadWorkflowAction )\n-  )\n+  return function (dispatch) {\n+    return (\n+\n+      dispatch({\n+        type: ADD_MODULE,\n+        payload: api.addModule(getPageID(), moduleId, insertBefore)\n+      }).then( ({value, action}) => {\n+\n+      dispatch(\n+        setSelectedWfModuleAction(value.id)\n+      );\n+\n+    }));\n+  }\n }\n+registerReducerFunc(ADD_MODULE + '_FULFILLED', (state, action) => {\n+  let insertBefore = action.payload.insert_before;\n \n-// Call delete API, then dispatch a reload\n-export function removeModuleAction(id_to_delete) {\n+  delete action.payload.insert_before;\n+\n+  return update(state, {\n+    selected_wf_module: {$set: action.payload.id},\n+    workflow: {\n+      wf_modules: { $splice:[ [insertBefore, 0, action.payload] ] }\n+    }\n+  });\n+});\n \n+\n+// DELETE_MODULE_ACTION\n+// Call delete API, then dispatch a reload\n+export function deleteModuleAction(id_to_delete) {\n   // If we are deleting the selected module, then set previous module in stack as selected\n-  var state = store.getState();\n+  let newSelectedId = null;\n+  let state = store.getState();\n   if (id_to_delete === state.selected_wf_module) {\n \n     // Find id of previous in stack\n-    var wf_modules = state.workflow.wf_modules;\n-    var new_selected_id = null;\n-    for (var wfm of wf_modules) {\n+    let wf_modules = state.workflow.wf_modules;\n+    for (let wfm of wf_modules) {\n       if (wfm.id === id_to_delete)\n         break;\n-      new_selected_id = wfm.id;\n+      newSelectedId = wfm.id;\n     }\n \n     // if we are deleting first module, set to new first module if any\n-    if (new_selected_id === null) {\n-      if (wf_modules.length > 1)\n-        new_selected_id = wf_modules[1].id;\n-      else\n-        new_selected_id = null;\n+    if (newSelectedId === null && wf_modules.length > 1) {\n+      newSelectedId = wf_modules[1].id;\n     }\n-\n-    store.dispatch(changeSelectedWfModuleAction(new_selected_id))\n   }\n \n-  return (\n-    api.deleteModule(id_to_delete)\n-    .then( reloadWorkflowAction )\n-  )\n-}\n-\n-export function wfModuleStatusAction(wfModuleID, status, error_msg='') {\n-  return {\n-    type : MODULE_STATUS_CHANGE,\n-    id : wfModuleID,\n-    status : status,\n-    error_msg: error_msg\n+  // If the selected module isn't changing, set it to the current selected module.\n+  if (newSelectedId === null) {\n+    newSelectedId = state.selected_wf_module;\n   }\n-}\n \n-export function changeSelectedWfModuleAction(wfModuleID) {\n-  return {\n-    type : SELECTED_MODULE_CHANGE,\n-    id : wfModuleID,\n+  return function (dispatch) {\n+    return (\n+      // Set the new selected module before deleting to avoid errors.\n+      // We do this even if the selected module isn't changing to avoid\n+      // writing a subtly tricky conditional here.","path":"assets/js/workflow-reducer.js","position":244,"original_position":244,"commit_id":"f98a05a968153e5ea1cef038c3caaa940095411a","original_commit_id":"f98a05a968153e5ea1cef038c3caaa940095411a","user":{"login":"jstray","id":1028628,"avatar_url":"https://avatars0.githubusercontent.com/u/1028628?v=4","gravatar_id":"","url":"https://api.github.com/users/jstray","html_url":"https://github.com/jstray","followers_url":"https://api.github.com/users/jstray/followers","following_url":"https://api.github.com/users/jstray/following{/other_user}","gists_url":"https://api.github.com/users/jstray/gists{/gist_id}","starred_url":"https://api.github.com/users/jstray/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jstray/subscriptions","organizations_url":"https://api.github.com/users/jstray/orgs","repos_url":"https://api.github.com/users/jstray/repos","events_url":"https://api.github.com/users/jstray/events{/privacy}","received_events_url":"https://api.github.com/users/jstray/received_events","type":"User","site_admin":false},"body":"It does cost an extra server round-trip, however. Or maybe we do this optimistically anyway so we delete on the client without waiting?","created_at":"2018-02-23T00:13:03Z","updated_at":"2018-02-23T00:38:10Z","html_url":"https://github.com/CJWorkbench/cjworkbench/pull/31#discussion_r170133577","pull_request_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/31","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/comments/170133577"},"html":{"href":"https://github.com/CJWorkbench/cjworkbench/pull/31#discussion_r170133577"},"pull_request":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/31"}}},"pull_request":{"url":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/31","id":170643657,"html_url":"https://github.com/CJWorkbench/cjworkbench/pull/31","diff_url":"https://github.com/CJWorkbench/cjworkbench/pull/31.diff","patch_url":"https://github.com/CJWorkbench/cjworkbench/pull/31.patch","issue_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues/31","number":31,"state":"open","locked":false,"title":"Reduxify","user":{"login":"mgerring","id":287109,"avatar_url":"https://avatars2.githubusercontent.com/u/287109?v=4","gravatar_id":"","url":"https://api.github.com/users/mgerring","html_url":"https://github.com/mgerring","followers_url":"https://api.github.com/users/mgerring/followers","following_url":"https://api.github.com/users/mgerring/following{/other_user}","gists_url":"https://api.github.com/users/mgerring/gists{/gist_id}","starred_url":"https://api.github.com/users/mgerring/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mgerring/subscriptions","organizations_url":"https://api.github.com/users/mgerring/orgs","repos_url":"https://api.github.com/users/mgerring/repos","events_url":"https://api.github.com/users/mgerring/events{/privacy}","received_events_url":"https://api.github.com/users/mgerring/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-02-22T02:42:17Z","updated_at":"2018-02-23T00:38:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bf9363770917139917224355e8ef2abe47515c5a","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/31/commits","review_comments_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/31/comments","review_comment_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/comments{/number}","comments_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues/31/comments","statuses_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/statuses/f98a05a968153e5ea1cef038c3caaa940095411a","head":{"label":"CJWorkbench:reduxify","ref":"reduxify","sha":"f98a05a968153e5ea1cef038c3caaa940095411a","user":{"login":"CJWorkbench","id":30188687,"avatar_url":"https://avatars0.githubusercontent.com/u/30188687?v=4","gravatar_id":"","url":"https://api.github.com/users/CJWorkbench","html_url":"https://github.com/CJWorkbench","followers_url":"https://api.github.com/users/CJWorkbench/followers","following_url":"https://api.github.com/users/CJWorkbench/following{/other_user}","gists_url":"https://api.github.com/users/CJWorkbench/gists{/gist_id}","starred_url":"https://api.github.com/users/CJWorkbench/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CJWorkbench/subscriptions","organizations_url":"https://api.github.com/users/CJWorkbench/orgs","repos_url":"https://api.github.com/users/CJWorkbench/repos","events_url":"https://api.github.com/users/CJWorkbench/events{/privacy}","received_events_url":"https://api.github.com/users/CJWorkbench/received_events","type":"Organization","site_admin":false},"repo":{"id":71166188,"name":"cjworkbench","full_name":"CJWorkbench/cjworkbench","owner":{"login":"CJWorkbench","id":30188687,"avatar_url":"https://avatars0.githubusercontent.com/u/30188687?v=4","gravatar_id":"","url":"https://api.github.com/users/CJWorkbench","html_url":"https://github.com/CJWorkbench","followers_url":"https://api.github.com/users/CJWorkbench/followers","following_url":"https://api.github.com/users/CJWorkbench/following{/other_user}","gists_url":"https://api.github.com/users/CJWorkbench/gists{/gist_id}","starred_url":"https://api.github.com/users/CJWorkbench/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CJWorkbench/subscriptions","organizations_url":"https://api.github.com/users/CJWorkbench/orgs","repos_url":"https://api.github.com/users/CJWorkbench/repos","events_url":"https://api.github.com/users/CJWorkbench/events{/privacy}","received_events_url":"https://api.github.com/users/CJWorkbench/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/CJWorkbench/cjworkbench","description":"Data science for storytellers","fork":false,"url":"https://api.github.com/repos/CJWorkbench/cjworkbench","forks_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/forks","keys_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/teams","hooks_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/hooks","issue_events_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues/events{/number}","events_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/events","assignees_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/assignees{/user}","branches_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/branches{/branch}","tags_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/tags","blobs_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/refs{/sha}","trees_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/statuses/{sha}","languages_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/languages","stargazers_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/stargazers","contributors_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/contributors","subscribers_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/subscribers","subscription_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/subscription","commits_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/commits{/sha}","git_commits_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/commits{/sha}","comments_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/comments{/number}","issue_comment_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues/comments{/number}","contents_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/contents/{+path}","compare_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/merges","archive_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/downloads","issues_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues{/number}","pulls_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls{/number}","milestones_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/milestones{/number}","notifications_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/labels{/name}","releases_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/releases{/id}","deployments_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/deployments","created_at":"2016-10-17T17:58:31Z","updated_at":"2018-02-05T17:33:19Z","pushed_at":"2018-02-22T21:47:50Z","git_url":"git://github.com/CJWorkbench/cjworkbench.git","ssh_url":"git@github.com:CJWorkbench/cjworkbench.git","clone_url":"https://github.com/CJWorkbench/cjworkbench.git","svn_url":"https://github.com/CJWorkbench/cjworkbench","homepage":"","size":114851,"stargazers_count":38,"watchers_count":38,"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":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0"},"forks":4,"open_issues":2,"watchers":38,"default_branch":"master"}},"base":{"label":"CJWorkbench:master","ref":"master","sha":"3cec1227093e4cea530a4f86f6e22251e93987df","user":{"login":"CJWorkbench","id":30188687,"avatar_url":"https://avatars0.githubusercontent.com/u/30188687?v=4","gravatar_id":"","url":"https://api.github.com/users/CJWorkbench","html_url":"https://github.com/CJWorkbench","followers_url":"https://api.github.com/users/CJWorkbench/followers","following_url":"https://api.github.com/users/CJWorkbench/following{/other_user}","gists_url":"https://api.github.com/users/CJWorkbench/gists{/gist_id}","starred_url":"https://api.github.com/users/CJWorkbench/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CJWorkbench/subscriptions","organizations_url":"https://api.github.com/users/CJWorkbench/orgs","repos_url":"https://api.github.com/users/CJWorkbench/repos","events_url":"https://api.github.com/users/CJWorkbench/events{/privacy}","received_events_url":"https://api.github.com/users/CJWorkbench/received_events","type":"Organization","site_admin":false},"repo":{"id":71166188,"name":"cjworkbench","full_name":"CJWorkbench/cjworkbench","owner":{"login":"CJWorkbench","id":30188687,"avatar_url":"https://avatars0.githubusercontent.com/u/30188687?v=4","gravatar_id":"","url":"https://api.github.com/users/CJWorkbench","html_url":"https://github.com/CJWorkbench","followers_url":"https://api.github.com/users/CJWorkbench/followers","following_url":"https://api.github.com/users/CJWorkbench/following{/other_user}","gists_url":"https://api.github.com/users/CJWorkbench/gists{/gist_id}","starred_url":"https://api.github.com/users/CJWorkbench/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CJWorkbench/subscriptions","organizations_url":"https://api.github.com/users/CJWorkbench/orgs","repos_url":"https://api.github.com/users/CJWorkbench/repos","events_url":"https://api.github.com/users/CJWorkbench/events{/privacy}","received_events_url":"https://api.github.com/users/CJWorkbench/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/CJWorkbench/cjworkbench","description":"Data science for storytellers","fork":false,"url":"https://api.github.com/repos/CJWorkbench/cjworkbench","forks_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/forks","keys_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/teams","hooks_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/hooks","issue_events_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues/events{/number}","events_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/events","assignees_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/assignees{/user}","branches_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/branches{/branch}","tags_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/tags","blobs_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/refs{/sha}","trees_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/statuses/{sha}","languages_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/languages","stargazers_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/stargazers","contributors_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/contributors","subscribers_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/subscribers","subscription_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/subscription","commits_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/commits{/sha}","git_commits_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/git/commits{/sha}","comments_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/comments{/number}","issue_comment_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues/comments{/number}","contents_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/contents/{+path}","compare_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/merges","archive_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/downloads","issues_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues{/number}","pulls_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls{/number}","milestones_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/milestones{/number}","notifications_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/labels{/name}","releases_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/releases{/id}","deployments_url":"https://api.github.com/repos/CJWorkbench/cjworkbench/deployments","created_at":"2016-10-17T17:58:31Z","updated_at":"2018-02-05T17:33:19Z","pushed_at":"2018-02-22T21:47:50Z","git_url":"git://github.com/CJWorkbench/cjworkbench.git","ssh_url":"git@github.com:CJWorkbench/cjworkbench.git","clone_url":"https://github.com/CJWorkbench/cjworkbench.git","svn_url":"https://github.com/CJWorkbench/cjworkbench","homepage":"","size":114851,"stargazers_count":38,"watchers_count":38,"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":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0"},"forks":4,"open_issues":2,"watchers":38,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/31"},"html":{"href":"https://github.com/CJWorkbench/cjworkbench/pull/31"},"issue":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues/31"},"comments":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/issues/31/comments"},"review_comments":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/31/comments"},"review_comment":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/pulls/31/commits"},"statuses":{"href":"https://api.github.com/repos/CJWorkbench/cjworkbench/statuses/f98a05a968153e5ea1cef038c3caaa940095411a"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"jstray"}}