{"action":"created","comment":{"url":"https://api.github.com/repos/linkedin/photon-ml/pulls/comments/83041830","pull_request_review_id":3908256,"id":83041830,"diff_hunk":"@@ -0,0 +1,307 @@\n+/*\n+ * Copyright 2016 LinkedIn Corp. All rights reserved.\n+ * Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n+ * not use this file except in compliance with the License. You may obtain a\n+ * copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n+ * License for the specific language governing permissions and limitations\n+ * under the License.\n+ */\n+package com.linkedin.photon.ml.data\n+\n+import com.linkedin.photon.ml.util.{DefaultIndexMapLoader, IndexMap, IndexMapLoader, Utils}\n+\n+import com.databricks.spark.avro._\n+import org.apache.spark.SparkContext\n+import org.apache.spark.mllib.linalg.{SparseVector, VectorUDT}\n+import org.apache.spark.sql.{DataFrame, Row, SQLContext}\n+import org.apache.spark.sql.functions.{col, array, udf}\n+import org.apache.spark.sql.types.{StructField, StructType}\n+\n+/**\n+ * A DataReader implementation that reads the Avro format\n+ */\n+class AvroDataReader(sc: SparkContext) extends DataReader {\n+\n+  import AvroDataReader._\n+\n+  /**\n+   * Internal sql context\n+   */\n+  private val sqlContext = new SQLContext(sc)\n+\n+  /**\n+   * Reads the avro file at the given path into a DataFrame, generating a default index map for feature names\n+   *\n+   * @param path the path to the avro file or folder\n+   * @param featureColumnMap a map that specifies how the feature columns should be merged. The keys specify the name\n+   *   of the merged destination column, and the values are sets of source columns to merge, e.g.:\n+   *\n+   *     Map(\"userFeatures\" -> Set(\"profileFeatures\", \"titleFeatures\"))\n+   *\n+   *   This configuration merges the \"profileFeatures\" and \"titleFeatures\" columns into a single column named\n+   *   \"userFeatures\".\n+   * @return the loaded and transformed DataFrame\n+   */\n+  override def read(\n+      path: String,\n+      featureColumnMap: Map[String, Set[String]]): (DataFrame, Map[String, IndexMapLoader]) = {\n+\n+    val data = sqlContext.read.avro(path)\n+    val merged = mergeColumns(data, featureColumnMap)\n+    val indexMapLoaders = generateIndexMapLoaders(merged, featureColumnMap.keys.toSet)\n+\n+    val transformed = vectorize(\n+      merged,\n+      indexMapLoaders)\n+\n+    (transformed, indexMapLoaders)\n+  }\n+\n+  /**\n+   * Reads the avro file at the given path into a DataFrame, using the given index map for feature names\n+   *\n+   * @param path the path to the avro file or folder\n+   * @param indexMapLoaders a map of index map loaders, containing one loader for each feature column\n+   * @param featureColumnMap a map that specifies how the feature columns should be merged. The keys specify the name\n+   *   of the merged destination column, and the values are sets of source columns to merge, e.g.:\n+   *\n+   *     Map(\"userFeatures\" -> Set(\"profileFeatures\", \"titleFeatures\"))\n+   *\n+   *   This configuration merges the \"profileFeatures\" and \"titleFeatures\" columns into a single column named\n+   *   \"userFeatures\".\n+   * @return the loaded and transformed DataFrame\n+   */\n+  override def read(\n+      path: String,\n+      indexMapLoaders: Map[String, IndexMapLoader],\n+      featureColumnMap: Map[String, Set[String]]): DataFrame = {\n+\n+    val data = sqlContext.read.avro(path)\n+\n+    vectorize(\n+      mergeColumns(data, featureColumnMap),\n+      indexMapLoaders)\n+  }\n+\n+  /**\n+   * Generates a temporary column name\n+   *\n+   * @param name the base name for the column\n+   * @return the temporary column name\n+   */\n+  protected def tempColumnName(name: String): String = s\"__${name}__${System.currentTimeMillis}__\"\n+\n+  /**\n+   * Read a feature tuple from the name, term, and value DataFrame row\n+   *\n+   * @param row the row from which to read the name, term, value tuple\n+   * @return the feature tuple\n+   */\n+  protected def readFeature = (feature: Row) => {","path":"photon-ml/src/main/scala/com/linkedin/photon/ml/data/AvroDataReader.scala","position":106,"original_position":106,"commit_id":"87dffa68ae2b384e18df1039e2846d60ae1189b9","original_commit_id":"7630fb4f113e3d4ecbc77938a0d88fff2cbc4e7b","user":{"login":"joshvfleming","id":212140,"avatar_url":"https://avatars.githubusercontent.com/u/212140?v=3","gravatar_id":"","url":"https://api.github.com/users/joshvfleming","html_url":"https://github.com/joshvfleming","followers_url":"https://api.github.com/users/joshvfleming/followers","following_url":"https://api.github.com/users/joshvfleming/following{/other_user}","gists_url":"https://api.github.com/users/joshvfleming/gists{/gist_id}","starred_url":"https://api.github.com/users/joshvfleming/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joshvfleming/subscriptions","organizations_url":"https://api.github.com/users/joshvfleming/orgs","repos_url":"https://api.github.com/users/joshvfleming/repos","events_url":"https://api.github.com/users/joshvfleming/events{/privacy}","received_events_url":"https://api.github.com/users/joshvfleming/received_events","type":"User","site_admin":false},"body":"I've done it this way so I can include the function in the closure on line 133 rather than serializing the entire object. As I write this, though, I realize that I could accomplish the same thing by making this function a member of the companion object. I think I'll do that instead.","created_at":"2016-10-12T16:14:59Z","updated_at":"2016-10-12T16:14:59Z","html_url":"https://github.com/linkedin/photon-ml/pull/179#discussion_r83041830","pull_request_url":"https://api.github.com/repos/linkedin/photon-ml/pulls/179","_links":{"self":{"href":"https://api.github.com/repos/linkedin/photon-ml/pulls/comments/83041830"},"html":{"href":"https://github.com/linkedin/photon-ml/pull/179#discussion_r83041830"},"pull_request":{"href":"https://api.github.com/repos/linkedin/photon-ml/pulls/179"}}},"pull_request":{"url":"https://api.github.com/repos/linkedin/photon-ml/pulls/179","id":88742112,"html_url":"https://github.com/linkedin/photon-ml/pull/179","diff_url":"https://github.com/linkedin/photon-ml/pull/179.diff","patch_url":"https://github.com/linkedin/photon-ml/pull/179.patch","issue_url":"https://api.github.com/repos/linkedin/photon-ml/issues/179","number":179,"state":"open","locked":false,"title":"Add DataReader, AvroDataReader, and integrate with GAME drivers","user":{"login":"joshvfleming","id":212140,"avatar_url":"https://avatars.githubusercontent.com/u/212140?v=3","gravatar_id":"","url":"https://api.github.com/users/joshvfleming","html_url":"https://github.com/joshvfleming","followers_url":"https://api.github.com/users/joshvfleming/followers","following_url":"https://api.github.com/users/joshvfleming/following{/other_user}","gists_url":"https://api.github.com/users/joshvfleming/gists{/gist_id}","starred_url":"https://api.github.com/users/joshvfleming/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joshvfleming/subscriptions","organizations_url":"https://api.github.com/users/joshvfleming/orgs","repos_url":"https://api.github.com/users/joshvfleming/repos","events_url":"https://api.github.com/users/joshvfleming/events{/privacy}","received_events_url":"https://api.github.com/users/joshvfleming/received_events","type":"User","site_admin":false},"body":"This is an incremental step towards the new client API. This change introduces a new interface -- **DataReader**, whose concrete implementations are responsible for reading data files of various formats and producing a DataFrame (and optionally an IndexMap). \r\n\r\n| DataReader |\r\n| --- |\r\n| `read(path: String, featureColumnMap: Map[String, Set[String]]): (DataFrame, Map[String, IndexMapLoader])` |\r\n| `read(path: String, indexMapLoaders: Map[String, IndexMapLoader], featureColumnMap: Map[String, Set[String]]): DataFrame` |\r\n| `read(path: String): (DataFrame, IndexMapLoader)` |\r\n| `read(path: String, indexMapLoaders: Map[String, IndexMapLoader]): DataFrame` |\r\n| `read(paths: Seq[String], featureColumnMap: Map[String, Set[String]]): (DataFrame, Map[String, IndexMapLoader])` |\r\n| `read(paths: Seq[String], indexMapLoaders: Map[String, IndexMapLoader], featureColumnMap: Map[String, Set[String]]): DataFrame` |\r\n| `read(paths: Seq[String]): (DataFrame, IndexMapLoader)` |\r\n| `read(paths: Seq[String], indexMapLoaders: Map[String, IndexMapLoader]): DataFrame` |\r\n\r\nThe first such implementation is **AvroDataReader**, which has been integrated here into the GAME training and scoring drivers to replace the legacy Avro code. The current approach is to provide a converter that transforms a DataFrame into a GAMEDataSet, but eventually the GAME and Photon api will consume DataFrame / Dataset directly.\r\n\r\n**Note:** This change requires Spark 1.6+, and has been tested on the grid with 1.6.1.\r\n\r\n### Performance Comparison\r\nThe following documents a performance comparison on an identical proprietary training set before and after this PR.\r\n\r\n| Code | AUC | Runtime |\r\n| --- | --- | --- |\r\n| Before | 0.7796065687206302 | 39.55 m |\r\n| After | 0.7801638770709362 | 40.38 m |\r\n\r\n### Fixed effect model\r\n| Code | Count | Mean | Variance | L2 norm |\r\n| --- | --- | --- | --- | --- |\r\n| Before | 22468 | 1.985378978052645E-4 | 0.001589526313337537 | 5.976016508476237 |\r\n| After | 22468 |-1.82578704936172E-4 | 0.001650688565248512 | 6.089890718711416 |\r\n\r\n### Random effect model 1\r\n| Code | Count | Mean | Std Dev | Max | Min |\r\n| --- | --- | --- | --- | --- | --- |\r\n| Before | 2370903 | 0.317850 | 0.203167 | 3.132743 | 0.000040 |\r\n| After | 2370903 | 0.317734 | 0.203154 | 3.137519 | 0.000037 |\r\n\r\n### Random effect model 2\r\n| Code | Count | Mean | Std Dev | Max | Min |\r\n| --- | --- | --- | --- | --- | --- |\r\n| Before | 967254 | 0.136670 | 0.154361 | 2.722700 | 0.000027 |\r\n| After | 967254 | 0.136611 | 0.154208 | 2.719635 | 0.000027 |\r\n\r\n","created_at":"2016-10-10T22:31:36Z","updated_at":"2016-10-12T16:14:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"504d45fc38ccbb961abdbaffdfa2300f6d75cd47","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/linkedin/photon-ml/pulls/179/commits","review_comments_url":"https://api.github.com/repos/linkedin/photon-ml/pulls/179/comments","review_comment_url":"https://api.github.com/repos/linkedin/photon-ml/pulls/comments{/number}","comments_url":"https://api.github.com/repos/linkedin/photon-ml/issues/179/comments","statuses_url":"https://api.github.com/repos/linkedin/photon-ml/statuses/87dffa68ae2b384e18df1039e2846d60ae1189b9","head":{"label":"joshvfleming:wip.data-frame","ref":"wip.data-frame","sha":"87dffa68ae2b384e18df1039e2846d60ae1189b9","user":{"login":"joshvfleming","id":212140,"avatar_url":"https://avatars.githubusercontent.com/u/212140?v=3","gravatar_id":"","url":"https://api.github.com/users/joshvfleming","html_url":"https://github.com/joshvfleming","followers_url":"https://api.github.com/users/joshvfleming/followers","following_url":"https://api.github.com/users/joshvfleming/following{/other_user}","gists_url":"https://api.github.com/users/joshvfleming/gists{/gist_id}","starred_url":"https://api.github.com/users/joshvfleming/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joshvfleming/subscriptions","organizations_url":"https://api.github.com/users/joshvfleming/orgs","repos_url":"https://api.github.com/users/joshvfleming/repos","events_url":"https://api.github.com/users/joshvfleming/events{/privacy}","received_events_url":"https://api.github.com/users/joshvfleming/received_events","type":"User","site_admin":false},"repo":{"id":56254851,"name":"photon-ml","full_name":"joshvfleming/photon-ml","owner":{"login":"joshvfleming","id":212140,"avatar_url":"https://avatars.githubusercontent.com/u/212140?v=3","gravatar_id":"","url":"https://api.github.com/users/joshvfleming","html_url":"https://github.com/joshvfleming","followers_url":"https://api.github.com/users/joshvfleming/followers","following_url":"https://api.github.com/users/joshvfleming/following{/other_user}","gists_url":"https://api.github.com/users/joshvfleming/gists{/gist_id}","starred_url":"https://api.github.com/users/joshvfleming/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joshvfleming/subscriptions","organizations_url":"https://api.github.com/users/joshvfleming/orgs","repos_url":"https://api.github.com/users/joshvfleming/repos","events_url":"https://api.github.com/users/joshvfleming/events{/privacy}","received_events_url":"https://api.github.com/users/joshvfleming/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/joshvfleming/photon-ml","description":"A scalable machine learning library on Apache Spark","fork":true,"url":"https://api.github.com/repos/joshvfleming/photon-ml","forks_url":"https://api.github.com/repos/joshvfleming/photon-ml/forks","keys_url":"https://api.github.com/repos/joshvfleming/photon-ml/keys{/key_id}","collaborators_url":"https://api.github.com/repos/joshvfleming/photon-ml/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/joshvfleming/photon-ml/teams","hooks_url":"https://api.github.com/repos/joshvfleming/photon-ml/hooks","issue_events_url":"https://api.github.com/repos/joshvfleming/photon-ml/issues/events{/number}","events_url":"https://api.github.com/repos/joshvfleming/photon-ml/events","assignees_url":"https://api.github.com/repos/joshvfleming/photon-ml/assignees{/user}","branches_url":"https://api.github.com/repos/joshvfleming/photon-ml/branches{/branch}","tags_url":"https://api.github.com/repos/joshvfleming/photon-ml/tags","blobs_url":"https://api.github.com/repos/joshvfleming/photon-ml/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/joshvfleming/photon-ml/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/joshvfleming/photon-ml/git/refs{/sha}","trees_url":"https://api.github.com/repos/joshvfleming/photon-ml/git/trees{/sha}","statuses_url":"https://api.github.com/repos/joshvfleming/photon-ml/statuses/{sha}","languages_url":"https://api.github.com/repos/joshvfleming/photon-ml/languages","stargazers_url":"https://api.github.com/repos/joshvfleming/photon-ml/stargazers","contributors_url":"https://api.github.com/repos/joshvfleming/photon-ml/contributors","subscribers_url":"https://api.github.com/repos/joshvfleming/photon-ml/subscribers","subscription_url":"https://api.github.com/repos/joshvfleming/photon-ml/subscription","commits_url":"https://api.github.com/repos/joshvfleming/photon-ml/commits{/sha}","git_commits_url":"https://api.github.com/repos/joshvfleming/photon-ml/git/commits{/sha}","comments_url":"https://api.github.com/repos/joshvfleming/photon-ml/comments{/number}","issue_comment_url":"https://api.github.com/repos/joshvfleming/photon-ml/issues/comments{/number}","contents_url":"https://api.github.com/repos/joshvfleming/photon-ml/contents/{+path}","compare_url":"https://api.github.com/repos/joshvfleming/photon-ml/compare/{base}...{head}","merges_url":"https://api.github.com/repos/joshvfleming/photon-ml/merges","archive_url":"https://api.github.com/repos/joshvfleming/photon-ml/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/joshvfleming/photon-ml/downloads","issues_url":"https://api.github.com/repos/joshvfleming/photon-ml/issues{/number}","pulls_url":"https://api.github.com/repos/joshvfleming/photon-ml/pulls{/number}","milestones_url":"https://api.github.com/repos/joshvfleming/photon-ml/milestones{/number}","notifications_url":"https://api.github.com/repos/joshvfleming/photon-ml/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/joshvfleming/photon-ml/labels{/name}","releases_url":"https://api.github.com/repos/joshvfleming/photon-ml/releases{/id}","deployments_url":"https://api.github.com/repos/joshvfleming/photon-ml/deployments","created_at":"2016-04-14T16:55:25Z","updated_at":"2016-04-14T16:55:27Z","pushed_at":"2016-10-11T19:04:48Z","git_url":"git://github.com/joshvfleming/photon-ml.git","ssh_url":"git@github.com:joshvfleming/photon-ml.git","clone_url":"https://github.com/joshvfleming/photon-ml.git","svn_url":"https://github.com/joshvfleming/photon-ml","homepage":"","size":46851,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"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":"linkedin:master","ref":"master","sha":"bcf1c34c58d081a7c7030d9ad3bed456462be7bf","user":{"login":"linkedin","id":357098,"avatar_url":"https://avatars.githubusercontent.com/u/357098?v=3","gravatar_id":"","url":"https://api.github.com/users/linkedin","html_url":"https://github.com/linkedin","followers_url":"https://api.github.com/users/linkedin/followers","following_url":"https://api.github.com/users/linkedin/following{/other_user}","gists_url":"https://api.github.com/users/linkedin/gists{/gist_id}","starred_url":"https://api.github.com/users/linkedin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/linkedin/subscriptions","organizations_url":"https://api.github.com/users/linkedin/orgs","repos_url":"https://api.github.com/users/linkedin/repos","events_url":"https://api.github.com/users/linkedin/events{/privacy}","received_events_url":"https://api.github.com/users/linkedin/received_events","type":"Organization","site_admin":false},"repo":{"id":50964104,"name":"photon-ml","full_name":"linkedin/photon-ml","owner":{"login":"linkedin","id":357098,"avatar_url":"https://avatars.githubusercontent.com/u/357098?v=3","gravatar_id":"","url":"https://api.github.com/users/linkedin","html_url":"https://github.com/linkedin","followers_url":"https://api.github.com/users/linkedin/followers","following_url":"https://api.github.com/users/linkedin/following{/other_user}","gists_url":"https://api.github.com/users/linkedin/gists{/gist_id}","starred_url":"https://api.github.com/users/linkedin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/linkedin/subscriptions","organizations_url":"https://api.github.com/users/linkedin/orgs","repos_url":"https://api.github.com/users/linkedin/repos","events_url":"https://api.github.com/users/linkedin/events{/privacy}","received_events_url":"https://api.github.com/users/linkedin/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/linkedin/photon-ml","description":"A scalable machine learning library on Apache Spark","fork":false,"url":"https://api.github.com/repos/linkedin/photon-ml","forks_url":"https://api.github.com/repos/linkedin/photon-ml/forks","keys_url":"https://api.github.com/repos/linkedin/photon-ml/keys{/key_id}","collaborators_url":"https://api.github.com/repos/linkedin/photon-ml/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/linkedin/photon-ml/teams","hooks_url":"https://api.github.com/repos/linkedin/photon-ml/hooks","issue_events_url":"https://api.github.com/repos/linkedin/photon-ml/issues/events{/number}","events_url":"https://api.github.com/repos/linkedin/photon-ml/events","assignees_url":"https://api.github.com/repos/linkedin/photon-ml/assignees{/user}","branches_url":"https://api.github.com/repos/linkedin/photon-ml/branches{/branch}","tags_url":"https://api.github.com/repos/linkedin/photon-ml/tags","blobs_url":"https://api.github.com/repos/linkedin/photon-ml/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/linkedin/photon-ml/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/linkedin/photon-ml/git/refs{/sha}","trees_url":"https://api.github.com/repos/linkedin/photon-ml/git/trees{/sha}","statuses_url":"https://api.github.com/repos/linkedin/photon-ml/statuses/{sha}","languages_url":"https://api.github.com/repos/linkedin/photon-ml/languages","stargazers_url":"https://api.github.com/repos/linkedin/photon-ml/stargazers","contributors_url":"https://api.github.com/repos/linkedin/photon-ml/contributors","subscribers_url":"https://api.github.com/repos/linkedin/photon-ml/subscribers","subscription_url":"https://api.github.com/repos/linkedin/photon-ml/subscription","commits_url":"https://api.github.com/repos/linkedin/photon-ml/commits{/sha}","git_commits_url":"https://api.github.com/repos/linkedin/photon-ml/git/commits{/sha}","comments_url":"https://api.github.com/repos/linkedin/photon-ml/comments{/number}","issue_comment_url":"https://api.github.com/repos/linkedin/photon-ml/issues/comments{/number}","contents_url":"https://api.github.com/repos/linkedin/photon-ml/contents/{+path}","compare_url":"https://api.github.com/repos/linkedin/photon-ml/compare/{base}...{head}","merges_url":"https://api.github.com/repos/linkedin/photon-ml/merges","archive_url":"https://api.github.com/repos/linkedin/photon-ml/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/linkedin/photon-ml/downloads","issues_url":"https://api.github.com/repos/linkedin/photon-ml/issues{/number}","pulls_url":"https://api.github.com/repos/linkedin/photon-ml/pulls{/number}","milestones_url":"https://api.github.com/repos/linkedin/photon-ml/milestones{/number}","notifications_url":"https://api.github.com/repos/linkedin/photon-ml/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/linkedin/photon-ml/labels{/name}","releases_url":"https://api.github.com/repos/linkedin/photon-ml/releases{/id}","deployments_url":"https://api.github.com/repos/linkedin/photon-ml/deployments","created_at":"2016-02-03T01:12:07Z","updated_at":"2016-10-12T06:25:21Z","pushed_at":"2016-10-12T15:21:26Z","git_url":"git://github.com/linkedin/photon-ml.git","ssh_url":"git@github.com:linkedin/photon-ml.git","clone_url":"https://github.com/linkedin/photon-ml.git","svn_url":"https://github.com/linkedin/photon-ml","homepage":"","size":47084,"stargazers_count":358,"watchers_count":358,"language":"Scala","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":75,"mirror_url":null,"open_issues_count":26,"forks":75,"open_issues":26,"watchers":358,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/linkedin/photon-ml/pulls/179"},"html":{"href":"https://github.com/linkedin/photon-ml/pull/179"},"issue":{"href":"https://api.github.com/repos/linkedin/photon-ml/issues/179"},"comments":{"href":"https://api.github.com/repos/linkedin/photon-ml/issues/179/comments"},"review_comments":{"href":"https://api.github.com/repos/linkedin/photon-ml/pulls/179/comments"},"review_comment":{"href":"https://api.github.com/repos/linkedin/photon-ml/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/linkedin/photon-ml/pulls/179/commits"},"statuses":{"href":"https://api.github.com/repos/linkedin/photon-ml/statuses/87dffa68ae2b384e18df1039e2846d60ae1189b9"}}}}
{"actor":{"display_login":"joshvfleming"}}