{"action":"created","comment":{"url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/comments/124257285","pull_request_review_id":46529505,"id":124257285,"diff_hunk":"@@ -0,0 +1,378 @@\n+package edu.umich.its.spe;\n+\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+import org.springframework.beans.factory.annotation.Autowired;\n+import org.springframework.stereotype.Component;\n+\n+import com.mashape.unirest.http.Unirest;\n+\n+import java.time.LocalDateTime;\n+import java.time.format.DateTimeFormatter;\n+import java.util.ArrayList;\n+import java.util.HashMap;\n+import java.util.Map;\n+\n+import edu.umich.ctools.esb.utils.WAPIResultWrapper;\n+\n+import org.json.JSONArray;\n+import org.json.JSONObject;\n+import org.json.JSONException;\n+\n+/*\n+ * Master class to run the Spanish Placement Exam script.\n+ * \n+ * See junit test files for sample data.\n+ */\n+\n+// TTD: (informal)\n+\n+// TASKS: (if not listed inline below)\n+// TODO: implement message logging / reporting\n+// TODO: figure out logging configuration. how set log level?\n+// TODO: configuration should separate security and properties.\n+// TODO: test error handling\n+\n+// Spring: make visible for auto wiring.\n+@Component\n+public class SPEMaster {\n+\n+\tstatic final Logger M_log = LoggerFactory.getLogger(SPEMaster.class);\n+\tstatic HashMap<String,String> unirest;\n+\n+\t// Let Spring inject the properties, the esb service, and the persistString implementation.\n+\t@Autowired\n+\tprivate SPEEsb speesb;\n+\n+\t@Autowired\n+\tprivate PersistString persistString;\n+\n+\t@Autowired\n+\tprivate SPEProperties speproperties;\n+\n+\t// If no other timestamp is specified use the current time.\n+\tprivate LocalDateTime startingTime = LocalDateTime.now();\n+\t\n+\tpublic SPEMaster() {\n+\t\tsuper();\n+\t\tM_log.info(\"SPEMaster: this: \"+this.toString());\n+\t}\n+\n+\t// Set global timeouts for EBS calls \n+\tprotected void setUnirestGlobalValues() {\n+\t\t\n+\t\tM_log.info(\"setupUnirestGlobalValues\");\n+\t\tunirest = speproperties.getUnirest();\n+\t\tM_log.info(\"unirest properties: {}\",unirest);\n+\t\t\n+\t\t// Setup values for request timeouts.\n+\t\tlong ct = longFromStringWithDefault(unirest.get(\"connectionTimeout\"), 10000l);\n+\t\tlong st = longFromStringWithDefault(unirest.get(\"socketTimeout\"), 10000l);\n+\t\t\n+\t\tM_log.info(\"unirest timeouts: connectionTimeout: {} socketTimeout: {}\",ct,st);\n+\t\t\n+\t\tUnirest.setTimeouts(ct,st);\n+\t}\n+\n+\t// Get a long value from a string use default if the string is null or empty.\n+\tprotected long longFromStringWithDefault(String longString, Long defaultValue) {\n+\t\tlong longValue = (longString == null ? defaultValue : Long.parseLong(longString));\n+\t\tM_log.info(\"longFromString: {} {}\",longString,longValue);\n+\t\treturn longValue;\n+\t}\n+\n+\t/*********************** Orchestrate the script. *****************/ \n+\t\n+\t/* \n+\t * - configuration is read and injected by spring\n+\t * - get value gradeAfterTime from persist string (default if necessary).\n+\t * - get grades.\n+\t * - translate to format for updates.\n+\t * - send to MPathways.\n+\t * \n+\t */\n+\t\n+\t/* Organize the task and handle errors */\n+\t\n+\tpublic void orchestrator () throws PersistStringException, SPEEsbException {\n+\t\n+\t\tM_log.info(\"Start SPE orchestrator\");\n+\t\n+\t\tsetUnirestGlobalValues();\n+\t\t\n+\t\t// sanity check by renewing token to ensure we can connect to the database.\n+\t\t\n+\t\tif (!verifyESB()) {\n+\t\t\tM_log.error(\"Unable to connect to esb\"); \n+\t\t\tthrow new SPEEsbException(\"Unable to connect to ESB\");\n+\t\t}\n+\t\t\n+\t\t//// Get the relevant grades.\n+\t\tString lastUpdateTime = readLastGradeTransferTime();\n+\t\tM_log.error(\"fake lastUpdateTime\");\n+\t\tlastUpdateTime = \"2017-03-08 15:38:21\";\n+\t\tM_log.info(\"lastUpdateTime: {}\",lastUpdateTime);\n+\t\tString assignmentsFromDW;\n+\t\n+\t\ttry {\n+\t\t\tassignmentsFromDW = getSPEGrades(lastUpdateTime);\n+\t\n+\t\t\t//// Extract grades from JSON the grades for insertion\t\n+\t\n+\t\t\tArrayList<HashMap<String,String>> SPEgradeMaps = null;\n+\t\t\ttry {\n+\t\t\t\tSPEgradeMaps = convertSPEGradesFromDataWarehouseJSON(assignmentsFromDW);\n+\t\t\t} catch (JSONException e) {\n+\t\t\t\tM_log.error(\"exception in converting grades: \"+e);\n+\t\t\t}\n+\t\n+\t\t\t//// Insert the grades.\n+\t\t\tM_log.info(\"Grade count since {} is {}.\",lastUpdateTime,SPEgradeMaps.size());\n+\t\t\tputSPEGrades(SPEgradeMaps);\n+\t\n+\t\t} catch (SPEEsbException e1) {\n+\t\t\tM_log.error(\"Exception processing SPE grades:\",e1);\n+\t\t}\n+\t\tfinally {\n+\t\t\t// Finish up, save data, send reports.\n+\t\t\tcloseUpShop();\n+\t\t}\n+\t}\n+\n+\t/************ Close down processing, create summary ************/\n+\tpublic void closeUpShop() {\n+\t\t// TODO: implement task shutdown.\n+\t\tM_log.error(\"Implement close up shop\");\n+\t}\n+\n+\t/********* esb verify **********/\n+\t// Run sanity check to make sure can talk to ESB and get data.\n+\t\n+\t/*\n+\t * Setup the hash of values needed for the call to verify ESB connection.\n+\t */\n+\tprotected HashMap<String, String> setupESBVerifyCall() {\n+\t\t//M_log.debug(\"spe properties: \"+speproperties);\n+\t\tHashMap<String,String> value = new HashMap<String,String>();\n+\t\tvalue.putAll(speproperties.getEsb());\n+\t\treturn value;\n+\t}\n+\n+\tpublic Boolean verifyESB() {\n+\t\t// TODO: implement verify by renewing access token.\n+\t\tM_log.error(\"verify is not yet used by SPEMaster\");\n+\t\tHashMap<String,String> value = setupESBVerifyCall();\n+\t\treturn speesb.verify(value);\t\n+\t}\n+\n+\t/*************** get grades via ESB **************/\n+\n+\t/*\n+\t * Setup the hash of values needed for the call to get grades.\n+\t */\n+\tprotected HashMap<String, String> setupGetGradesCall(String gradedAfterTime) {\n+\t\tM_log.debug(\"spe properties: \"+speproperties);\n+\t\tHashMap<String,String> value = new HashMap<String,String>();\n+\t\tvalue.putAll(speproperties.getEsb());\n+\t\tvalue.putAll(speproperties.getGetgrades());\n+\t\tvalue.put(\"gradedaftertime\", gradedAfterTime);\n+\t\treturn value;\n+\t}\n+\n+\t/*\n+\t * Get grades as JSON string.  Only grades after the gradeAfterTime\n+\t * timestamp will be returned. An empty result is reasonable.\n+\t * The format of the time stamp is: 2017-04-01 18:00:00.  \n+\t * TODO: timestamp default value?\n+\t */ \n+\n+\tpublic String getSPEGrades(String gradedAfterTime) throws SPEEsbException {\n+\n+\t\tHashMap<String, String> values = setupGetGradesCall(gradedAfterTime);\n+\n+\t\tWAPIResultWrapper grades = speesb.getGradesViaESB(values);\n+\t\t// check for possibility of no new grades.\n+\t\tif (grades.getStatus() == 404) {\n+\t\t\treturn \"[]\";\n+\t\t}\n+\n+\t\treturn grades.getResult().toString();\n+\t}\n+\n+\t//{\"Meta\":{\"Message\":\"COMPLETED\",\"httpStatus\":200},\"Result\":{\"putPlcExamScoreResponse\":{\"putPlcExamScoreResponse\":{\"Status\":\"SUCCESS\",\"Form\":7,\"ID\":\"abc\"},\"@schemaLocation\":\"http://mais.he.umich.edu/schemas/putPlcExamScoreResponse.v1 http://csqa9ib.dsc.umich.edu/PSIGW/PeopleSoftServiceListeningConnector/putPlcExamScoreResponse.v1.xsd\"}}}\n+\n+\t//{\"putPlcExamScoreResponse\":{\"putPlcExamScoreResponse\":{\"Status\":\"SUCCESS\",\"Form\":7,\"ID\":\"abc\"\n+\n+\t/*********** format assignments from the data warehouse ********/\n+\t\n+\t// After getting the JSON from the data warehouse format the SPE grades.\n+\tprotected ArrayList<HashMap<String,String>> convertSPEGradesFromDataWarehouseJSON(String assignmentJSON) {\n+\t\n+\t\tM_log.debug(\"cSGFDWJ: assignmentJSON: {}\",assignmentJSON);\n+\t\t// if nothing in it then return an empty list.\n+\t\tif (assignmentJSON == null || assignmentJSON.length() <=2) {\n+\t\t\tArrayList<HashMap<String,String>> emptyArrayList = new ArrayList<HashMap<String,String>>();\n+\t\t\treturn emptyArrayList;\n+\t\t}\n+\t\n+\t\tJSONArray assignments = parseCanvasAssignmentJSON(assignmentJSON);\n+\t\tArrayList<HashMap<String,String>> gradeMapList = convertAssignmentsToGradeMaps(assignments);\n+\t\tM_log.debug(\"cSGFDWJ: gradeMaplist: {}\",gradeMapList);\n+\t\treturn gradeMapList;\n+\t}\n+\n+\t// convert the list of DataWarehouse assignments to a list of grade maps for MPathways.\n+\tprotected ArrayList<HashMap<String, String>> convertAssignmentsToGradeMaps(JSONArray canvasAssignments) {\n+\t\tArrayList<HashMap<String,String>> gradeMapList = new ArrayList<HashMap<String, String>>();\n+\t\n+\t\t// JSONArray is not iterable so can't use the nice \"for each\" syntax.\n+\t\tfor(int i = 0; i<canvasAssignments.length(); i++) {\n+\t\t\tJSONObject assignment = canvasAssignments.getJSONObject(i);\n+\t\t\tHashMap<String, String> grademap = convertAssignmentToGradeMap(assignment);\n+\t\t\tgradeMapList.add(grademap);\n+\t\t}\n+\t\n+\t\treturn gradeMapList;\n+\t}\n+\n+\t// convert a single JSON version of an assignment to a grademap.\n+\tstatic protected HashMap<String, String> convertAssignmentToGradeMap(JSONObject assignment) throws JSONException {\n+\t\tHashMap<String,String> grademap = new HashMap<String,String>();\n+\t\t// Score may be read as a number instead of a string so pull out as an object and convert to a string.\n+\t\tgrademap.put(\"Score\",JSONObject.valueToString(assignment.get(\"Score\")));\n+\t\tgrademap.put(\"Unique_Name\", assignment.getString(\"Unique_Name\"));\n+\t\treturn grademap;\n+\t}\n+\n+\t// Take the assignment JSON string from the data warehouse and return the array of grades as a parsed JSON array.\n+\tstatic protected JSONArray parseCanvasAssignmentJSON(String gradeJSON) throws JSONException {\n+\t\tJSONObject jo = new JSONObject(gradeJSON);\n+\t\tJSONObject jAI = jo.getJSONObject(\"AssignmentInfo\");\n+\t\n+\t\t// Get the data as a JSON array.\n+\t\tJSONArray jAD = jAI.optJSONArray(\"AssignmentData\");\n+\t\n+\t\t// If there is a single grade it may appear as a single object, so deal with that.\n+\t\tif (jAD == null) {\n+\t\t\tjAD = new JSONArray();\n+\t\t\tjAD.put(jAI.getJSONObject(\"AssignmentData\"));\n+\t\t}\n+\t\n+\t\treturn jAD;\n+\t}\n+\n+\t\n+\t/***************** put grades ************/\n+\t\n+\t/*\n+\t * Setup the hash of values needed for the call to get grades.\n+\t */\n+\t\n+\tprotected HashMap<String, String> setupPutGradeCall(HashMap<?, ?> user) {\n+\t\tM_log.debug(\"spe properties: \"+speproperties);\n+\t\tHashMap<String,String> value = new HashMap<String,String>();\n+\t\tvalue.putAll(speproperties.getEsb());\n+\t\t// if no user that use default values (for testing).\n+\t\tif (user == null || user.isEmpty()) {\n+\t\t\tvalue.putAll(speproperties.getPutgrades());\n+\t\t}\n+\t\telse {\n+\t\t\tvalue.put(\"SCORE\",(String) user.get(\"Score\"));\n+\t\t\tvalue.put(\"UNIQNAME\",(String) user.get(\"Unique_Name\"));\n+\t\t}\n+\t\treturn value;\n+\t}\n+\n+\t//{\"Meta\":{\"Message\":\"COMPLETED\",\"httpStatus\":200},\"Result\":{\"putPlcExamScoreResponse\":{\"putPlcExamScoreResponse\":{\"Status\":\"SUCCESS\",\"Form\":7,\"ID\":\"abc\"},\"@schemaLocation\":\"http://mais.he.umich.edu/schemas/putPlcExamScoreResponse.v1 http://csqa9ib.dsc.umich.edu/PSIGW/PeopleSoftServiceListeningConnector/putPlcExamScoreResponse.v1.xsd\"}}}\n+\t\n+\t//{\"putPlcExamScoreResponse\":{\"putPlcExamScoreResponse\":{\"Status\":\"SUCCESS\",\"Form\":7,\"ID\":\"abc\"\n+\t\n+\t// Print out user for updated grade.\n+\tstatic protected void logPutGrade(WAPIResultWrapper putGrade)  {\n+\t\ttry {\n+\t\t\tJSONObject jo = new JSONObject(putGrade);\n+\t\t\tJSONObject jAI = jo.getJSONObject(\"result\");\n+\t\t\tJSONObject pPESR = jAI.getJSONObject(\"putPlcExamScoreResponse\").getJSONObject(\"putPlcExamScoreResponse\");\n+\t\t\tString user = pPESR.getString(\"ID\");\n+\t\t\tM_log.info(\"putGrade: updated MPathways for user: \"+user);\n+\t\t} catch (JSONException e) {\n+\t\t\tM_log.error(\"error extracting grade update user for: \"+putGrade.toJson());\n+\t\t}\n+\t}\n+\n+\t/********* put in the grades **********/\n+\t\n+\t// Send a list of grades to MPathways.\n+\tpublic void putSPEGrades(ArrayList<HashMap<String, String>> SPEgradeMaps) {\n+\t\tint gradesAdded = 0;\n+\t\tint gradesAttempted = 0;\n+\t\tBoolean success;\n+\t\tfor(HashMap<String, String> singleUser : SPEgradeMaps) {\n+\t\t\tgradesAttempted ++;\n+\t\t\tsuccess = putSPEGrade(singleUser);\n+\t\t\tif (success) {\n+\t\t\t\tgradesAdded++;\n+\t\t\t}\n+\t\t}\n+\t\tM_log.info(\"adding grades: attempted: {} successful: {}\",gradesAttempted,gradesAdded);\n+\t}\n+\t\n+\t// Send a single grade to MPathways.\n+\tpublic boolean putSPEGrade(HashMap<?, ?> user) {\n+\t\tHashMap<String,String> value = setupPutGradeCall(user);\n+\n+\t\tWAPIResultWrapper wrappedResult = speesb.putGradeViaESB(value);\n+\n+\t\tM_log.debug(\"update: {}\",wrappedResult.toJson());\n+\n+\t\tif (wrappedResult.getStatus() == 200) {\n+\t\t\tlogPutGrade(wrappedResult);\n+\t\t\treturn true;\n+\t\t}\n+\n+\t\tM_log.error(\"error updating grade: \"+wrappedResult.toJson());\n+\t\treturn false;\n+\t}\n+\n+\n+\n+\t/***************** manage the timestamp data with PersistString ***********/\n+\t/*\n+\t * Use PersistString class to get a string with a timestamp representing the \n+\t * last time the script updated the grades.\n+\t * \n+\t * If the value isn't available or is corrupt use a default value.  We'll be careful\n+\t * but won't panic about only submitting grades once.\n+\t */\n+\t\n+\t// Format an internal timestamp into the expected string.\n+\tprotected static String formatPersistTimestamp(LocalDateTime ts) {\n+\t\tDateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\");\n+\t\tString s = ts.format(formatter);\n+\t\treturn s;\n+\t}","path":"src/main/java/edu/umich/its/spe/SPEMaster.java","position":354,"original_position":354,"commit_id":"ea3ed4ce9ea1a97d9db22f99f75b8cc2ef0813ed","original_commit_id":"ea3ed4ce9ea1a97d9db22f99f75b8cc2ef0813ed","user":{"login":"pushyamig","id":8579775,"avatar_url":"https://avatars1.githubusercontent.com/u/8579775?v=3","gravatar_id":"","url":"https://api.github.com/users/pushyamig","html_url":"https://github.com/pushyamig","followers_url":"https://api.github.com/users/pushyamig/followers","following_url":"https://api.github.com/users/pushyamig/following{/other_user}","gists_url":"https://api.github.com/users/pushyamig/gists{/gist_id}","starred_url":"https://api.github.com/users/pushyamig/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pushyamig/subscriptions","organizations_url":"https://api.github.com/users/pushyamig/orgs","repos_url":"https://api.github.com/users/pushyamig/repos","events_url":"https://api.github.com/users/pushyamig/events{/privacy}","received_events_url":"https://api.github.com/users/pushyamig/received_events","type":"User","site_admin":false},"body":"May be this method should go in a Utility class, that way Each class retains identity of what is is doing.","created_at":"2017-06-27T12:23:45Z","updated_at":"2017-06-27T12:23:45Z","html_url":"https://github.com/tl-its-umich-edu/spanish-placement-exam/pull/2#discussion_r124257285","pull_request_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/2","_links":{"self":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/comments/124257285"},"html":{"href":"https://github.com/tl-its-umich-edu/spanish-placement-exam/pull/2#discussion_r124257285"},"pull_request":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/2"}}},"pull_request":{"url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/2","id":127230544,"html_url":"https://github.com/tl-its-umich-edu/spanish-placement-exam/pull/2","diff_url":"https://github.com/tl-its-umich-edu/spanish-placement-exam/pull/2.diff","patch_url":"https://github.com/tl-its-umich-edu/spanish-placement-exam/pull/2.patch","issue_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/issues/2","number":2,"state":"open","locked":false,"title":"Tlspe 2 etc: Initial version of script to get SPE grades from datawarehouse to MPathwasy","user":{"login":"dlhaines","id":74063,"avatar_url":"https://avatars3.githubusercontent.com/u/74063?v=3","gravatar_id":"","url":"https://api.github.com/users/dlhaines","html_url":"https://github.com/dlhaines","followers_url":"https://api.github.com/users/dlhaines/followers","following_url":"https://api.github.com/users/dlhaines/following{/other_user}","gists_url":"https://api.github.com/users/dlhaines/gists{/gist_id}","starred_url":"https://api.github.com/users/dlhaines/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dlhaines/subscriptions","organizations_url":"https://api.github.com/users/dlhaines/orgs","repos_url":"https://api.github.com/users/dlhaines/repos","events_url":"https://api.github.com/users/dlhaines/events{/privacy}","received_events_url":"https://api.github.com/users/dlhaines/received_events","type":"User","site_admin":false},"body":"Replacing the current CTools based implementation with Spring Boot based one that pull new grade information from the data warehouse via the ESB and sends it to MPathways via the ESB.","created_at":"2017-06-23T15:21:26Z","updated_at":"2017-06-27T12:23:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"645530484ee87e27c09e5d24d04abe8c64fb9865","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/2/commits","review_comments_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/2/comments","review_comment_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/comments{/number}","comments_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/issues/2/comments","statuses_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/statuses/ea3ed4ce9ea1a97d9db22f99f75b8cc2ef0813ed","head":{"label":"dlhaines:TLSPE-2","ref":"TLSPE-2","sha":"ea3ed4ce9ea1a97d9db22f99f75b8cc2ef0813ed","user":{"login":"dlhaines","id":74063,"avatar_url":"https://avatars3.githubusercontent.com/u/74063?v=3","gravatar_id":"","url":"https://api.github.com/users/dlhaines","html_url":"https://github.com/dlhaines","followers_url":"https://api.github.com/users/dlhaines/followers","following_url":"https://api.github.com/users/dlhaines/following{/other_user}","gists_url":"https://api.github.com/users/dlhaines/gists{/gist_id}","starred_url":"https://api.github.com/users/dlhaines/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dlhaines/subscriptions","organizations_url":"https://api.github.com/users/dlhaines/orgs","repos_url":"https://api.github.com/users/dlhaines/repos","events_url":"https://api.github.com/users/dlhaines/events{/privacy}","received_events_url":"https://api.github.com/users/dlhaines/received_events","type":"User","site_admin":false},"repo":{"id":91125055,"name":"spanish-placement-exam","full_name":"dlhaines/spanish-placement-exam","owner":{"login":"dlhaines","id":74063,"avatar_url":"https://avatars3.githubusercontent.com/u/74063?v=3","gravatar_id":"","url":"https://api.github.com/users/dlhaines","html_url":"https://github.com/dlhaines","followers_url":"https://api.github.com/users/dlhaines/followers","following_url":"https://api.github.com/users/dlhaines/following{/other_user}","gists_url":"https://api.github.com/users/dlhaines/gists{/gist_id}","starred_url":"https://api.github.com/users/dlhaines/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dlhaines/subscriptions","organizations_url":"https://api.github.com/users/dlhaines/orgs","repos_url":"https://api.github.com/users/dlhaines/repos","events_url":"https://api.github.com/users/dlhaines/events{/privacy}","received_events_url":"https://api.github.com/users/dlhaines/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dlhaines/spanish-placement-exam","description":null,"fork":true,"url":"https://api.github.com/repos/dlhaines/spanish-placement-exam","forks_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/forks","keys_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/teams","hooks_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/hooks","issue_events_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/issues/events{/number}","events_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/events","assignees_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/assignees{/user}","branches_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/branches{/branch}","tags_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/tags","blobs_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/git/refs{/sha}","trees_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/statuses/{sha}","languages_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/languages","stargazers_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/stargazers","contributors_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/contributors","subscribers_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/subscribers","subscription_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/subscription","commits_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/commits{/sha}","git_commits_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/git/commits{/sha}","comments_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/comments{/number}","issue_comment_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/issues/comments{/number}","contents_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/contents/{+path}","compare_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/merges","archive_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/downloads","issues_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/issues{/number}","pulls_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/pulls{/number}","milestones_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/milestones{/number}","notifications_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/labels{/name}","releases_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/releases{/id}","deployments_url":"https://api.github.com/repos/dlhaines/spanish-placement-exam/deployments","created_at":"2017-05-12T19:52:18Z","updated_at":"2017-05-12T19:52:19Z","pushed_at":"2017-06-23T18:46:04Z","git_url":"git://github.com/dlhaines/spanish-placement-exam.git","ssh_url":"git@github.com:dlhaines/spanish-placement-exam.git","clone_url":"https://github.com/dlhaines/spanish-placement-exam.git","svn_url":"https://github.com/dlhaines/spanish-placement-exam","homepage":null,"size":40,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"tl-its-umich-edu:TLSPE-2","ref":"TLSPE-2","sha":"d55fa7786b54870835a140d16ad63eb1b03b319e","user":{"login":"tl-its-umich-edu","id":8292960,"avatar_url":"https://avatars0.githubusercontent.com/u/8292960?v=3","gravatar_id":"","url":"https://api.github.com/users/tl-its-umich-edu","html_url":"https://github.com/tl-its-umich-edu","followers_url":"https://api.github.com/users/tl-its-umich-edu/followers","following_url":"https://api.github.com/users/tl-its-umich-edu/following{/other_user}","gists_url":"https://api.github.com/users/tl-its-umich-edu/gists{/gist_id}","starred_url":"https://api.github.com/users/tl-its-umich-edu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tl-its-umich-edu/subscriptions","organizations_url":"https://api.github.com/users/tl-its-umich-edu/orgs","repos_url":"https://api.github.com/users/tl-its-umich-edu/repos","events_url":"https://api.github.com/users/tl-its-umich-edu/events{/privacy}","received_events_url":"https://api.github.com/users/tl-its-umich-edu/received_events","type":"Organization","site_admin":false},"repo":{"id":89261305,"name":"spanish-placement-exam","full_name":"tl-its-umich-edu/spanish-placement-exam","owner":{"login":"tl-its-umich-edu","id":8292960,"avatar_url":"https://avatars0.githubusercontent.com/u/8292960?v=3","gravatar_id":"","url":"https://api.github.com/users/tl-its-umich-edu","html_url":"https://github.com/tl-its-umich-edu","followers_url":"https://api.github.com/users/tl-its-umich-edu/followers","following_url":"https://api.github.com/users/tl-its-umich-edu/following{/other_user}","gists_url":"https://api.github.com/users/tl-its-umich-edu/gists{/gist_id}","starred_url":"https://api.github.com/users/tl-its-umich-edu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tl-its-umich-edu/subscriptions","organizations_url":"https://api.github.com/users/tl-its-umich-edu/orgs","repos_url":"https://api.github.com/users/tl-its-umich-edu/repos","events_url":"https://api.github.com/users/tl-its-umich-edu/events{/privacy}","received_events_url":"https://api.github.com/users/tl-its-umich-edu/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/tl-its-umich-edu/spanish-placement-exam","description":null,"fork":false,"url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam","forks_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/forks","keys_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/teams","hooks_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/hooks","issue_events_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/issues/events{/number}","events_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/events","assignees_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/assignees{/user}","branches_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/branches{/branch}","tags_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/tags","blobs_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/git/refs{/sha}","trees_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/statuses/{sha}","languages_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/languages","stargazers_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/stargazers","contributors_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/contributors","subscribers_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/subscribers","subscription_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/subscription","commits_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/commits{/sha}","git_commits_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/git/commits{/sha}","comments_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/comments{/number}","issue_comment_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/issues/comments{/number}","contents_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/contents/{+path}","compare_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/merges","archive_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/downloads","issues_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/issues{/number}","pulls_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls{/number}","milestones_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/milestones{/number}","notifications_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/labels{/name}","releases_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/releases{/id}","deployments_url":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/deployments","created_at":"2017-04-24T16:10:02Z","updated_at":"2017-05-12T19:38:08Z","pushed_at":"2017-06-23T15:21:27Z","git_url":"git://github.com/tl-its-umich-edu/spanish-placement-exam.git","ssh_url":"git@github.com:tl-its-umich-edu/spanish-placement-exam.git","clone_url":"https://github.com/tl-its-umich-edu/spanish-placement-exam.git","svn_url":"https://github.com/tl-its-umich-edu/spanish-placement-exam","homepage":null,"size":4,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":1,"forks":1,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/2"},"html":{"href":"https://github.com/tl-its-umich-edu/spanish-placement-exam/pull/2"},"issue":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/issues/2"},"comments":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/issues/2/comments"},"review_comments":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/2/comments"},"review_comment":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/pulls/2/commits"},"statuses":{"href":"https://api.github.com/repos/tl-its-umich-edu/spanish-placement-exam/statuses/ea3ed4ce9ea1a97d9db22f99f75b8cc2ef0813ed"}}}}
{"actor":{"display_login":"pushyamig"}}