{"action":"created","comment":{"url":"https://api.github.com/repos/scala-ide/scala-ide/pulls/comments/37132964","id":37132964,"diff_hunk":"@@ -0,0 +1,135 @@\n+package org.scalaide.debug.internal.async\n+\n+import scala.collection.JavaConverters._\n+import scala.collection.mutable\n+import org.scalaide.debug.internal.BaseDebuggerActor\n+import org.scalaide.debug.internal.model.JdiRequestFactory\n+import org.scalaide.debug.internal.model.ScalaDebugTarget\n+import org.scalaide.debug.internal.model.ScalaValue\n+import org.scalaide.logging.HasLogger\n+import com.sun.jdi.ObjectReference\n+import com.sun.jdi.ReferenceType\n+import com.sun.jdi.StackFrame\n+import com.sun.jdi.ThreadReference\n+import com.sun.jdi.event._\n+import scala.util.Try\n+import scala.util.Success\n+import java.util.concurrent.atomic.AtomicInteger\n+import org.scalaide.debug.internal.model.ScalaObjectReference\n+\n+/**\n+ * Installs breakpoints in key places and collect stack frames.\n+ */\n+class RetainedStackManager(debugTarget: ScalaDebugTarget) extends HasLogger {\n+  import RetainedStackManager._\n+  type AsyncStackTraceKey = (ObjectReference, Int)\n+  final val MaxEntries = 20000\n+  private val stackFrames: mutable.Map[AsyncStackTraceKey, AsyncStackTrace] = new LRUMap(MaxEntries)\n+  private val messageOrdinal = new AtomicInteger\n+\n+  object actor extends BaseDebuggerActor {\n+    override protected def behavior = {\n+      // JDI event triggered when a class has been loaded\n+      case classPrepareEvent: ClassPrepareEvent =>\n+        val refType = classPrepareEvent.referenceType()\n+        // find the right app to install\n+        programPoints.find(_.className == refType.name()) foreach { installMethodBreakpoint(refType, _) }\n+        reply(false)\n+\n+      // JDI event triggered when a breakpoint is hit\n+      case breakpointEvent: BreakpointEvent =>\n+        appHit(breakpointEvent.thread, breakpointEvent.request().getProperty(\"app\").asInstanceOf[AsyncProgramPoint], messageOrdinal.getAndIncrement)\n+        reply(false) // don't suspend this thread\n+    }\n+  }\n+\n+  private def appHit(thread: ThreadReference, app: AsyncProgramPoint, messageOrdinal: Int): Unit = {\n+    val topFrame = thread.frame(0)\n+    val args = topFrame.getArgumentValues()\n+\n+    val body = args.get(app.paramIdx)\n+    val frames = thread.frames().asScala.toList\n+    stackFrames += (body.asInstanceOf[ObjectReference], messageOrdinal) -> mkStackTrace(frames, messageOrdinal)\n+  }\n+\n+  private def mkStackTrace(frames: Seq[StackFrame], ordinal: Int): AsyncStackTrace = {\n+    import collection.JavaConverters._\n+\n+    val asyncFrames = frames.map { frame =>\n+      Try {\n+        val names = frame.visibleVariables()\n+        val values = frame.getValues(names)\n+        val locals = values.asScala.map {\n+          case (lvar, lval) => AsyncLocalVariable(lvar.name(), ScalaValue(lval, debugTarget), ordinal)(debugTarget)\n+        }\n+        val location = frame.location()\n+        AsyncStackFrame(locals.toSeq, Location(location.sourceName, location.declaringType.name, location.lineNumber))(debugTarget)\n+      }\n+    } collect {\n+      case Success(asyncStackTrace) => asyncStackTrace\n+    }\n+\n+    AsyncStackTrace(asyncFrames)\n+  }\n+\n+  private def installMethodBreakpoint(tpe: ReferenceType, app: AsyncProgramPoint): Unit = {\n+    val method = AsyncUtils.findAsyncProgramPoint(app, tpe)\n+    method.foreach { meth =>\n+      val req = JdiRequestFactory.createMethodEntryBreakpoint(method.get, debugTarget)\n+      debugTarget.eventDispatcher.setActorFor(actor, req)\n+      req.putProperty(\"app\", app)\n+      req.enable()\n+\n+      logger.debug(s\"Installed method breakpoint for ${method.get.declaringType()}.${method.get.name}\")\n+    }\n+  }\n+\n+  private val programPoints = List(\n+    AsyncProgramPoint(\"scala.concurrent.Future$\", \"apply\", 0),\n+    AsyncProgramPoint(\"scala.concurrent.package$\", \"future\", 0),\n+    AsyncProgramPoint(\"play.api.libs.iteratee.Cont$\", \"apply\", 0),\n+    AsyncProgramPoint(\"akka.actor.LocalActorRef\", \"$bang\", 0),\n+    AsyncProgramPoint(\"akka.actor.RepointableActorRef\", \"$bang\", 0),\n+    AsyncProgramPoint(\"scala.actors.InternalReplyReactor$class\", \"$bang\", 1))\n+\n+  /** Return the saved stackframes for the given future body (if any). */\n+  def getStackFrameForFuture(future: ObjectReference, messageOrdinal: Int): Option[AsyncStackTrace] =\n+    stackFrames.get(previousKeyWhenIsGiven(future, messageOrdinal))\n+\n+  private def keysForObjectReferenceAndOrdinal(future: ObjectReference, ordinal: Int): PartialFunction[AsyncStackTraceKey, AsyncStackTraceKey] = {\n+    case k @ (objRef, ord) if objRef == future && ord < ordinal => k\n+  }\n+\n+  private def keysForObjectReference(future: ObjectReference): PartialFunction[AsyncStackTraceKey, AsyncStackTraceKey] = {\n+    case k @ (objRef, _) if objRef == future => k\n+  }\n+\n+  private def keysSelection(future: ObjectReference): PartialFunction[Int, PartialFunction[AsyncStackTraceKey, AsyncStackTraceKey]] = {\n+    case ordinal if ordinal != OrdinalNotSet => keysForObjectReferenceAndOrdinal(future, ordinal)\n+    case OrdinalNotSet => keysForObjectReference(future)\n+  }\n+\n+  private def previousKeyWhenIsGiven(future: ObjectReference, ordinal: Int): AsyncStackTraceKey = {\n+    val olderTracesKeys = stackFrames.keys.collect(keysSelection(future)(ordinal))","path":"org.scala-ide.sdt.debug/src/org/scalaide/debug/internal/async/RetainedStackManager.scala","position":113,"original_position":113,"commit_id":"b4036c574103b609d92a97c1e9c30b5f1f58d81a","original_commit_id":"b4036c574103b609d92a97c1e9c30b5f1f58d81a","user":{"login":"wpopielarski","id":11613003,"avatar_url":"https://avatars.githubusercontent.com/u/11613003?v=3","gravatar_id":"","url":"https://api.github.com/users/wpopielarski","html_url":"https://github.com/wpopielarski","followers_url":"https://api.github.com/users/wpopielarski/followers","following_url":"https://api.github.com/users/wpopielarski/following{/other_user}","gists_url":"https://api.github.com/users/wpopielarski/gists{/gist_id}","starred_url":"https://api.github.com/users/wpopielarski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wpopielarski/subscriptions","organizations_url":"https://api.github.com/users/wpopielarski/orgs","repos_url":"https://api.github.com/users/wpopielarski/repos","events_url":"https://api.github.com/users/wpopielarski/events{/privacy}","received_events_url":"https://api.github.com/users/wpopielarski/received_events","type":"User","site_admin":false},"body":"you right, I try something like Map[ObjectReference, AsyncStackTraces]\nwhere AsyncStackTraces(listOfOrdinals: List[Int], asyncStackTracesMap[Int,\nAsyncStackTrace])\nusage:\n\nval asyncStackTrace = map(objRef)(ordinal)\n\nclass AsyncStackTraces(listOfOrdinals: List[Int], asyncStackTracesMap[Int,\nAsyncStackTrace]) {\n  def apply(index: Int) = {\nif (listOfOrdinals.tail == Nil) asyncStackTraces(listOfOrdinals.head) else\nasyncStackTraces(findPreviousIndex(listOfOrdinals, index)) }\n\nthis should be fine I guess. It's almost constant searching for map and log\nn  for indices on list. Is it ok?\n\n2015-08-14 16:58 GMT+02:00 Wieslaw Popielarski <wpopielarski@gmail.com>:\n\n> just lightning thought: [ObjectReference, List[<something>]] is a good\n> trace?\n>\n> 2015-08-14 16:46 GMT+02:00 Wieslaw Popielarski <wpopielarski@gmail.com>:\n>\n>> but I see now concept is clear :)\n>>\n>> 2015-08-14 16:46 GMT+02:00 Wieslaw Popielarski <wpopielarski@gmail.com>:\n>>\n>>> got is and will ponder it. generally if something is unique or not we\n>>> know in moment of insertion and than we can decide how to handle it.\n>>>\n>>> 2015-08-14 16:18 GMT+02:00 Iulian Dragos <notifications@github.com>:\n>>>\n>>>> In\n>>>> org.scala-ide.sdt.debug/src/org/scalaide/debug/internal/async/RetainedStackManager.scala\n>>>> <https://github.com/scala-ide/scala-ide/pull/992#discussion_r37080232>:\n>>>>\n>>>> > +\n>>>> > +  private def keysForObjectReferenceAndOrdinal(future: ObjectReference, ordinal: Int): PartialFunction[AsyncStackTraceKey, AsyncStackTraceKey] = {\n>>>> > +    case k @ (objRef, ord) if objRef == future && ord < ordinal => k\n>>>> > +  }\n>>>> > +\n>>>> > +  private def keysForObjectReference(future: ObjectReference): PartialFunction[AsyncStackTraceKey, AsyncStackTraceKey] = {\n>>>> > +    case k @ (objRef, _) if objRef == future => k\n>>>> > +  }\n>>>> > +\n>>>> > +  private def keysSelection(future: ObjectReference): PartialFunction[Int, PartialFunction[AsyncStackTraceKey, AsyncStackTraceKey]] = {\n>>>> > +    case ordinal if ordinal != OrdinalNotSet => keysForObjectReferenceAndOrdinal(future, ordinal)\n>>>> > +    case OrdinalNotSet => keysForObjectReference(future)\n>>>> > +  }\n>>>> > +\n>>>> > +  private def previousKeyWhenIsGiven(future: ObjectReference, ordinal: Int): AsyncStackTraceKey = {\n>>>> > +    val olderTracesKeys = stackFrames.keys.collect(keysSelection(future)(ordinal))\n>>>>\n>>>> I don't like that, for the special-case of objects, we start doing a\n>>>> linear search for everybody, instead of a hashmap lookup. There should be a\n>>>> fast-path for objects that are unique. If there's only one entry for some\n>>>> future (we also need to rename this, because it's not a future, it can\n>>>> be a message as well), there's no need to look further. So maybe go back to\n>>>> a Map[ObjectReference, <something else here>], and have a fast-path\n>>>> when there's only one of those, and otherwise use the ordinal to\n>>>> disambiguate.\n>>>>\n>>>> Also, please add an explanation in the scaladoc comment of\n>>>> getStackFrameForFuture (also, let's rename it to reflect that it's not\n>>>> only for futures... maybe simply getAsyncStackFrame).\n>>>>\n>>>> —\n>>>> Reply to this email directly or view it on GitHub\n>>>> <https://github.com/scala-ide/scala-ide/pull/992/files#r37080232>.\n>>>>\n>>>\n>>>\n>>\n>\n","created_at":"2015-08-15T04:00:23Z","updated_at":"2015-08-15T04:00:23Z","html_url":"https://github.com/scala-ide/scala-ide/pull/992#discussion_r37132964","pull_request_url":"https://api.github.com/repos/scala-ide/scala-ide/pulls/992","_links":{"self":{"href":"https://api.github.com/repos/scala-ide/scala-ide/pulls/comments/37132964"},"html":{"href":"https://github.com/scala-ide/scala-ide/pull/992#discussion_r37132964"},"pull_request":{"href":"https://api.github.com/repos/scala-ide/scala-ide/pulls/992"}}},"pull_request":{"url":"https://api.github.com/repos/scala-ide/scala-ide/pulls/992","id":42244588,"html_url":"https://github.com/scala-ide/scala-ide/pull/992","diff_url":"https://github.com/scala-ide/scala-ide/pull/992.diff","patch_url":"https://github.com/scala-ide/scala-ide/pull/992.patch","issue_url":"https://api.github.com/repos/scala-ide/scala-ide/issues/992","number":992,"state":"open","locked":false,"title":"[WIP] Async debugger actor","user":{"login":"wpopielarski","id":11613003,"avatar_url":"https://avatars.githubusercontent.com/u/11613003?v=3","gravatar_id":"","url":"https://api.github.com/users/wpopielarski","html_url":"https://github.com/wpopielarski","followers_url":"https://api.github.com/users/wpopielarski/followers","following_url":"https://api.github.com/users/wpopielarski/following{/other_user}","gists_url":"https://api.github.com/users/wpopielarski/gists{/gist_id}","starred_url":"https://api.github.com/users/wpopielarski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wpopielarski/subscriptions","organizations_url":"https://api.github.com/users/wpopielarski/orgs","repos_url":"https://api.github.com/users/wpopielarski/repos","events_url":"https://api.github.com/users/wpopielarski/events{/privacy}","received_events_url":"https://api.github.com/users/wpopielarski/received_events","type":"User","site_admin":false},"body":"It implements very basic functionality of async debugger.\r\nThe purpose of async debugger is to ease debugging of applications\r\nwhere objects exchange messages rather than call synchroniously\r\nmethods. Right now it is possible to track messages exchanged by Akka\r\nactors, old scala actors and futures.\r\n\r\n- [x] check if looped actor message handling is correctly shown in Async Stack\r\n- [ ] some tests to cover basic use cases","created_at":"2015-08-12T14:18:08Z","updated_at":"2015-08-15T04:00:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"070fff826fd5fb8f88a558875b32aae651b13cbf","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/scala-ide/scala-ide/pulls/992/commits","review_comments_url":"https://api.github.com/repos/scala-ide/scala-ide/pulls/992/comments","review_comment_url":"https://api.github.com/repos/scala-ide/scala-ide/pulls/comments{/number}","comments_url":"https://api.github.com/repos/scala-ide/scala-ide/issues/992/comments","statuses_url":"https://api.github.com/repos/scala-ide/scala-ide/statuses/b4036c574103b609d92a97c1e9c30b5f1f58d81a","head":{"label":"wpopielarski:async-debugger-actor","ref":"async-debugger-actor","sha":"b4036c574103b609d92a97c1e9c30b5f1f58d81a","user":{"login":"wpopielarski","id":11613003,"avatar_url":"https://avatars.githubusercontent.com/u/11613003?v=3","gravatar_id":"","url":"https://api.github.com/users/wpopielarski","html_url":"https://github.com/wpopielarski","followers_url":"https://api.github.com/users/wpopielarski/followers","following_url":"https://api.github.com/users/wpopielarski/following{/other_user}","gists_url":"https://api.github.com/users/wpopielarski/gists{/gist_id}","starred_url":"https://api.github.com/users/wpopielarski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wpopielarski/subscriptions","organizations_url":"https://api.github.com/users/wpopielarski/orgs","repos_url":"https://api.github.com/users/wpopielarski/repos","events_url":"https://api.github.com/users/wpopielarski/events{/privacy}","received_events_url":"https://api.github.com/users/wpopielarski/received_events","type":"User","site_admin":false},"repo":{"id":32731990,"name":"scala-ide","full_name":"wpopielarski/scala-ide","owner":{"login":"wpopielarski","id":11613003,"avatar_url":"https://avatars.githubusercontent.com/u/11613003?v=3","gravatar_id":"","url":"https://api.github.com/users/wpopielarski","html_url":"https://github.com/wpopielarski","followers_url":"https://api.github.com/users/wpopielarski/followers","following_url":"https://api.github.com/users/wpopielarski/following{/other_user}","gists_url":"https://api.github.com/users/wpopielarski/gists{/gist_id}","starred_url":"https://api.github.com/users/wpopielarski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wpopielarski/subscriptions","organizations_url":"https://api.github.com/users/wpopielarski/orgs","repos_url":"https://api.github.com/users/wpopielarski/repos","events_url":"https://api.github.com/users/wpopielarski/events{/privacy}","received_events_url":"https://api.github.com/users/wpopielarski/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/wpopielarski/scala-ide","description":"Scala IDE for Eclipse","fork":true,"url":"https://api.github.com/repos/wpopielarski/scala-ide","forks_url":"https://api.github.com/repos/wpopielarski/scala-ide/forks","keys_url":"https://api.github.com/repos/wpopielarski/scala-ide/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wpopielarski/scala-ide/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wpopielarski/scala-ide/teams","hooks_url":"https://api.github.com/repos/wpopielarski/scala-ide/hooks","issue_events_url":"https://api.github.com/repos/wpopielarski/scala-ide/issues/events{/number}","events_url":"https://api.github.com/repos/wpopielarski/scala-ide/events","assignees_url":"https://api.github.com/repos/wpopielarski/scala-ide/assignees{/user}","branches_url":"https://api.github.com/repos/wpopielarski/scala-ide/branches{/branch}","tags_url":"https://api.github.com/repos/wpopielarski/scala-ide/tags","blobs_url":"https://api.github.com/repos/wpopielarski/scala-ide/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wpopielarski/scala-ide/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wpopielarski/scala-ide/git/refs{/sha}","trees_url":"https://api.github.com/repos/wpopielarski/scala-ide/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wpopielarski/scala-ide/statuses/{sha}","languages_url":"https://api.github.com/repos/wpopielarski/scala-ide/languages","stargazers_url":"https://api.github.com/repos/wpopielarski/scala-ide/stargazers","contributors_url":"https://api.github.com/repos/wpopielarski/scala-ide/contributors","subscribers_url":"https://api.github.com/repos/wpopielarski/scala-ide/subscribers","subscription_url":"https://api.github.com/repos/wpopielarski/scala-ide/subscription","commits_url":"https://api.github.com/repos/wpopielarski/scala-ide/commits{/sha}","git_commits_url":"https://api.github.com/repos/wpopielarski/scala-ide/git/commits{/sha}","comments_url":"https://api.github.com/repos/wpopielarski/scala-ide/comments{/number}","issue_comment_url":"https://api.github.com/repos/wpopielarski/scala-ide/issues/comments{/number}","contents_url":"https://api.github.com/repos/wpopielarski/scala-ide/contents/{+path}","compare_url":"https://api.github.com/repos/wpopielarski/scala-ide/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wpopielarski/scala-ide/merges","archive_url":"https://api.github.com/repos/wpopielarski/scala-ide/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wpopielarski/scala-ide/downloads","issues_url":"https://api.github.com/repos/wpopielarski/scala-ide/issues{/number}","pulls_url":"https://api.github.com/repos/wpopielarski/scala-ide/pulls{/number}","milestones_url":"https://api.github.com/repos/wpopielarski/scala-ide/milestones{/number}","notifications_url":"https://api.github.com/repos/wpopielarski/scala-ide/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wpopielarski/scala-ide/labels{/name}","releases_url":"https://api.github.com/repos/wpopielarski/scala-ide/releases{/id}","created_at":"2015-03-23T12:51:34Z","updated_at":"2015-04-21T07:14:47Z","pushed_at":"2015-08-14T13:28:49Z","git_url":"git://github.com/wpopielarski/scala-ide.git","ssh_url":"git@github.com:wpopielarski/scala-ide.git","clone_url":"https://github.com/wpopielarski/scala-ide.git","svn_url":"https://github.com/wpopielarski/scala-ide","homepage":"www.scala-ide.org","size":145498,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"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":"scala-ide:master","ref":"master","sha":"271df1690521e3db4ed1c1a5ab71850ff836d569","user":{"login":"scala-ide","id":1026788,"avatar_url":"https://avatars.githubusercontent.com/u/1026788?v=3","gravatar_id":"","url":"https://api.github.com/users/scala-ide","html_url":"https://github.com/scala-ide","followers_url":"https://api.github.com/users/scala-ide/followers","following_url":"https://api.github.com/users/scala-ide/following{/other_user}","gists_url":"https://api.github.com/users/scala-ide/gists{/gist_id}","starred_url":"https://api.github.com/users/scala-ide/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scala-ide/subscriptions","organizations_url":"https://api.github.com/users/scala-ide/orgs","repos_url":"https://api.github.com/users/scala-ide/repos","events_url":"https://api.github.com/users/scala-ide/events{/privacy}","received_events_url":"https://api.github.com/users/scala-ide/received_events","type":"Organization","site_admin":false},"repo":{"id":2510011,"name":"scala-ide","full_name":"scala-ide/scala-ide","owner":{"login":"scala-ide","id":1026788,"avatar_url":"https://avatars.githubusercontent.com/u/1026788?v=3","gravatar_id":"","url":"https://api.github.com/users/scala-ide","html_url":"https://github.com/scala-ide","followers_url":"https://api.github.com/users/scala-ide/followers","following_url":"https://api.github.com/users/scala-ide/following{/other_user}","gists_url":"https://api.github.com/users/scala-ide/gists{/gist_id}","starred_url":"https://api.github.com/users/scala-ide/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scala-ide/subscriptions","organizations_url":"https://api.github.com/users/scala-ide/orgs","repos_url":"https://api.github.com/users/scala-ide/repos","events_url":"https://api.github.com/users/scala-ide/events{/privacy}","received_events_url":"https://api.github.com/users/scala-ide/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/scala-ide/scala-ide","description":"Scala IDE for Eclipse","fork":false,"url":"https://api.github.com/repos/scala-ide/scala-ide","forks_url":"https://api.github.com/repos/scala-ide/scala-ide/forks","keys_url":"https://api.github.com/repos/scala-ide/scala-ide/keys{/key_id}","collaborators_url":"https://api.github.com/repos/scala-ide/scala-ide/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/scala-ide/scala-ide/teams","hooks_url":"https://api.github.com/repos/scala-ide/scala-ide/hooks","issue_events_url":"https://api.github.com/repos/scala-ide/scala-ide/issues/events{/number}","events_url":"https://api.github.com/repos/scala-ide/scala-ide/events","assignees_url":"https://api.github.com/repos/scala-ide/scala-ide/assignees{/user}","branches_url":"https://api.github.com/repos/scala-ide/scala-ide/branches{/branch}","tags_url":"https://api.github.com/repos/scala-ide/scala-ide/tags","blobs_url":"https://api.github.com/repos/scala-ide/scala-ide/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/scala-ide/scala-ide/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/scala-ide/scala-ide/git/refs{/sha}","trees_url":"https://api.github.com/repos/scala-ide/scala-ide/git/trees{/sha}","statuses_url":"https://api.github.com/repos/scala-ide/scala-ide/statuses/{sha}","languages_url":"https://api.github.com/repos/scala-ide/scala-ide/languages","stargazers_url":"https://api.github.com/repos/scala-ide/scala-ide/stargazers","contributors_url":"https://api.github.com/repos/scala-ide/scala-ide/contributors","subscribers_url":"https://api.github.com/repos/scala-ide/scala-ide/subscribers","subscription_url":"https://api.github.com/repos/scala-ide/scala-ide/subscription","commits_url":"https://api.github.com/repos/scala-ide/scala-ide/commits{/sha}","git_commits_url":"https://api.github.com/repos/scala-ide/scala-ide/git/commits{/sha}","comments_url":"https://api.github.com/repos/scala-ide/scala-ide/comments{/number}","issue_comment_url":"https://api.github.com/repos/scala-ide/scala-ide/issues/comments{/number}","contents_url":"https://api.github.com/repos/scala-ide/scala-ide/contents/{+path}","compare_url":"https://api.github.com/repos/scala-ide/scala-ide/compare/{base}...{head}","merges_url":"https://api.github.com/repos/scala-ide/scala-ide/merges","archive_url":"https://api.github.com/repos/scala-ide/scala-ide/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/scala-ide/scala-ide/downloads","issues_url":"https://api.github.com/repos/scala-ide/scala-ide/issues{/number}","pulls_url":"https://api.github.com/repos/scala-ide/scala-ide/pulls{/number}","milestones_url":"https://api.github.com/repos/scala-ide/scala-ide/milestones{/number}","notifications_url":"https://api.github.com/repos/scala-ide/scala-ide/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/scala-ide/scala-ide/labels{/name}","releases_url":"https://api.github.com/repos/scala-ide/scala-ide/releases{/id}","created_at":"2011-10-04T05:56:23Z","updated_at":"2015-08-09T15:54:31Z","pushed_at":"2015-08-14T13:28:50Z","git_url":"git://github.com/scala-ide/scala-ide.git","ssh_url":"git@github.com:scala-ide/scala-ide.git","clone_url":"https://github.com/scala-ide/scala-ide.git","svn_url":"https://github.com/scala-ide/scala-ide","homepage":"www.scala-ide.org","size":158071,"stargazers_count":399,"watchers_count":399,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":209,"mirror_url":null,"open_issues_count":6,"forks":209,"open_issues":6,"watchers":399,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/scala-ide/scala-ide/pulls/992"},"html":{"href":"https://github.com/scala-ide/scala-ide/pull/992"},"issue":{"href":"https://api.github.com/repos/scala-ide/scala-ide/issues/992"},"comments":{"href":"https://api.github.com/repos/scala-ide/scala-ide/issues/992/comments"},"review_comments":{"href":"https://api.github.com/repos/scala-ide/scala-ide/pulls/992/comments"},"review_comment":{"href":"https://api.github.com/repos/scala-ide/scala-ide/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/scala-ide/scala-ide/pulls/992/commits"},"statuses":{"href":"https://api.github.com/repos/scala-ide/scala-ide/statuses/b4036c574103b609d92a97c1e9c30b5f1f58d81a"}}}}