{"action":"created","comment":{"url":"https://api.github.com/repos/slamdata/purescript-routing/pulls/comments/173861277","pull_request_review_id":103120079,"id":173861277,"diff_hunk":"@@ -0,0 +1,247 @@\n+module Routing.PushState\n+  ( PushStateEffects\n+  , PushStateInterface\n+  , LocationState\n+  , Basename(..)\n+  , Path(..)\n+  , makeInterface\n+  , foldLocations\n+  , locations\n+  , foldPaths\n+  , paths\n+  , matches\n+  , matchesWith\n+  ) where\n+\n+import Prelude\n+\n+import Control.Monad.Eff (Eff)\n+import Control.Monad.Eff.Ref (REF, modifyRef, newRef, readRef, writeRef)\n+import DOM (DOM)\n+import DOM.Event.EventTarget (addEventListener, eventListener) as DOM\n+import DOM.HTML (window) as DOM\n+import DOM.HTML.Event.EventTypes (popstate) as DOM\n+import DOM.HTML.History (DocumentTitle(..), URL(..), pushState, replaceState, state) as DOM\n+import DOM.HTML.Location (hash, pathname, search) as DOM\n+import DOM.HTML.Types (HISTORY)\n+import DOM.HTML.Types (htmlDocumentToDocument, windowToEventTarget) as DOM\n+import DOM.HTML.Window (document, history, location) as DOM\n+import DOM.Node.Document (createTextNode) as DOM\n+import DOM.Node.MutationObserver (mutationObserver, observe) as DOM\n+import DOM.Node.Node (setNodeValue) as DOM\n+import DOM.Node.Types (textToNode) as DOM\n+import Data.Array as Array\n+import Data.Foldable (class Foldable, for_, indexl, traverse_)\n+import Data.Foreign (Foreign)\n+import Data.Maybe (Maybe(..), fromMaybe, maybe)\n+import Data.Newtype (class Newtype, unwrap)\n+import Data.StrMap as StrMap\n+import Data.String as String\n+import Routing (match)\n+import Routing.Match (Match)\n+\n+type PushStateEffects eff =\n+  ( history :: HISTORY\n+  , dom :: DOM\n+  , ref :: REF\n+  | eff\n+  )\n+\n+newtype Basename = Basename String\n+\n+derive newtype instance eqBasename :: Eq Basename\n+derive newtype instance ordBasename :: Ord Basename\n+derive instance newtypeBasename :: Newtype Basename _\n+\n+newtype Path = Path String\n+\n+derive newtype instance eqPath :: Eq Path\n+derive newtype instance ordPath :: Ord Path\n+derive instance newtypePath :: Newtype Path _\n+\n+-- | A `PushStateInterface` is a localized instance for making location changes\n+-- | and consuming the events. Since the DOM API does not provide a general\n+-- | event type for push state (only pop), you must use the coupled effects\n+-- | along with `listen` to receive events on all location changes.\n+-- |\n+-- | * `pushState` – pushes a new location state and path onto the history stack.\n+-- | * `replaceState` – replaces the location state and path in the history stack.\n+-- | * `locationState` – Dereferences the current history state\n+-- | * `listen` – Subscribes to location changes (both push and pop). Returns\n+-- |   an effect which removes the listener.\n+type PushStateInterface eff =\n+  { pushState :: Foreign -> Path -> Eff eff Unit\n+  , replaceState :: Foreign -> Path -> Eff eff Unit\n+  , locationState :: Eff eff LocationState\n+  , listen :: (LocationState -> Eff eff Unit) -> Eff eff (Eff eff Unit)\n+  }\n+\n+-- | Creates a new `PushStateInterface` given a `Basename`. The `Basename` is\n+-- | used as an implicit prefix for the paths supplied to the instance, being\n+-- | automatically added and stripped as necessary.\n+makeInterface :: forall eff. Basename -> Eff (PushStateEffects eff) (PushStateInterface (PushStateEffects eff))\n+makeInterface basename = do\n+  argsRef <- newRef []\n+  freshRef <- newRef 0\n+  listenersRef <- newRef StrMap.empty\n+\n+  let\n+    notify ev =\n+      traverse_ (_ $ ev) =<< readRef listenersRef\n+\n+    listen k = do\n+      fresh <- readRef freshRef\n+      writeRef freshRef (fresh + 1)\n+      modifyRef listenersRef $ StrMap.insert (show fresh) k\n+      pure $ modifyRef listenersRef $ StrMap.delete (show fresh)\n+\n+    locationState = do\n+      loc <- DOM.window >>= DOM.location\n+      state <- DOM.window >>= DOM.history >>= DOM.state\n+      pathname <- fromMaybe <*> String.stripPrefix (String.Pattern (unwrap basename)) <$> DOM.pathname loc\n+      search <- DOM.search loc\n+      hash <- DOM.hash loc\n+      let path = pathname <> search <> hash\n+      pure { state, pathname, search, hash, path }\n+\n+  -- The hashchange interface is asynchronous, since hashchange events are\n+  -- fired on the next tick of the event loop. We want the push-state\n+  -- interface to behave as similarly as possible, so we use the microtask\n+  -- queue via MutationObserver to schedule callbacks. Alternatively we could\n+  -- just use a setTimeout, but it would not be as prompt. We use a fresh\n+  -- counter so that the text change mutation always fires.\n+  schedule <- do\n+    obsvNode <-\n+      DOM.window\n+        >>= DOM.document\n+        >>> map DOM.htmlDocumentToDocument\n+        >>= DOM.createTextNode \"\"\n+        >>> map DOM.textToNode\n+    observer <- DOM.mutationObserver \\_ _ -> do\n+      argsQueue <- readRef argsRef\n+      writeRef argsRef []\n+      for_ argsQueue notify\n+    DOM.observe obsvNode { characterData: true } observer\n+    pure \\args -> do\n+      argsQueue <- readRef argsRef\n+      writeRef argsRef (Array.snoc argsQueue args)\n+      when (Array.null argsQueue) do\n+        fresh ← readRef freshRef\n+        writeRef freshRef (fresh + 1)\n+        DOM.setNodeValue (show fresh) obsvNode\n+\n+  let\n+    stateFn op state path = do\n+      let\n+        loc = normalizeLocation state path\n+        url = DOM.URL $ unwrap basename <> loc.pathname <> loc.search <> loc.hash\n+      DOM.window\n+        >>= DOM.history\n+        >>= op state (DOM.DocumentTitle \"\") url\n+      schedule loc\n+\n+    listener =\n+      DOM.eventListener \\_ -> notify =<< locationState\n+\n+  DOM.window\n+    >>= DOM.windowToEventTarget\n+    >>> DOM.addEventListener DOM.popstate listener false\n+\n+  pure\n+    { pushState: stateFn DOM.pushState\n+    , replaceState: stateFn DOM.replaceState\n+    , locationState\n+    , listen\n+    }\n+\n+type LocationState =\n+  { state :: Foreign\n+  , path :: String","path":"src/Routing/PushState.purs","position":159,"original_position":159,"commit_id":"595c393e5df27a631517f24ebe6a389af8f155aa","original_commit_id":"595c393e5df27a631517f24ebe6a389af8f155aa","user":{"login":"cryogenian","id":10245930,"avatar_url":"https://avatars3.githubusercontent.com/u/10245930?v=4","gravatar_id":"","url":"https://api.github.com/users/cryogenian","html_url":"https://github.com/cryogenian","followers_url":"https://api.github.com/users/cryogenian/followers","following_url":"https://api.github.com/users/cryogenian/following{/other_user}","gists_url":"https://api.github.com/users/cryogenian/gists{/gist_id}","starred_url":"https://api.github.com/users/cryogenian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cryogenian/subscriptions","organizations_url":"https://api.github.com/users/cryogenian/orgs","repos_url":"https://api.github.com/users/cryogenian/repos","events_url":"https://api.github.com/users/cryogenian/events{/privacy}","received_events_url":"https://api.github.com/users/cryogenian/received_events","type":"User","site_admin":false},"body":":+1: for strings if there is no ambiguity","created_at":"2018-03-12T16:31:47Z","updated_at":"2018-03-12T16:31:47Z","html_url":"https://github.com/slamdata/purescript-routing/pull/51#discussion_r173861277","pull_request_url":"https://api.github.com/repos/slamdata/purescript-routing/pulls/51","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/slamdata/purescript-routing/pulls/comments/173861277"},"html":{"href":"https://github.com/slamdata/purescript-routing/pull/51#discussion_r173861277"},"pull_request":{"href":"https://api.github.com/repos/slamdata/purescript-routing/pulls/51"}},"in_reply_to_id":173770154},"pull_request":{"url":"https://api.github.com/repos/slamdata/purescript-routing/pulls/51","id":160665105,"html_url":"https://github.com/slamdata/purescript-routing/pull/51","diff_url":"https://github.com/slamdata/purescript-routing/pull/51.diff","patch_url":"https://github.com/slamdata/purescript-routing/pull/51.patch","issue_url":"https://api.github.com/repos/slamdata/purescript-routing/issues/51","number":51,"state":"open","locked":false,"title":"Push state","user":{"login":"natefaubion","id":144058,"avatar_url":"https://avatars1.githubusercontent.com/u/144058?v=4","gravatar_id":"","url":"https://api.github.com/users/natefaubion","html_url":"https://github.com/natefaubion","followers_url":"https://api.github.com/users/natefaubion/followers","following_url":"https://api.github.com/users/natefaubion/following{/other_user}","gists_url":"https://api.github.com/users/natefaubion/gists{/gist_id}","starred_url":"https://api.github.com/users/natefaubion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/natefaubion/subscriptions","organizations_url":"https://api.github.com/users/natefaubion/orgs","repos_url":"https://api.github.com/users/natefaubion/repos","events_url":"https://api.github.com/users/natefaubion/events{/privacy}","received_events_url":"https://api.github.com/users/natefaubion/received_events","type":"User","site_admin":false},"body":"Branched off of #50 \r\nRelies on https://github.com/purescript-web/purescript-dom/pull/139\r\nFixes #29 ","created_at":"2018-01-02T00:03:08Z","updated_at":"2018-03-12T16:31:47Z","closed_at":null,"merged_at":null,"merge_commit_sha":"868457cc6c3c741de6985b1a4b9d9a0a3b3bb758","assignee":null,"assignees":[],"requested_reviewers":[{"login":"garyb","id":693642,"avatar_url":"https://avatars0.githubusercontent.com/u/693642?v=4","gravatar_id":"","url":"https://api.github.com/users/garyb","html_url":"https://github.com/garyb","followers_url":"https://api.github.com/users/garyb/followers","following_url":"https://api.github.com/users/garyb/following{/other_user}","gists_url":"https://api.github.com/users/garyb/gists{/gist_id}","starred_url":"https://api.github.com/users/garyb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/garyb/subscriptions","organizations_url":"https://api.github.com/users/garyb/orgs","repos_url":"https://api.github.com/users/garyb/repos","events_url":"https://api.github.com/users/garyb/events{/privacy}","received_events_url":"https://api.github.com/users/garyb/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/slamdata/purescript-routing/pulls/51/commits","review_comments_url":"https://api.github.com/repos/slamdata/purescript-routing/pulls/51/comments","review_comment_url":"https://api.github.com/repos/slamdata/purescript-routing/pulls/comments{/number}","comments_url":"https://api.github.com/repos/slamdata/purescript-routing/issues/51/comments","statuses_url":"https://api.github.com/repos/slamdata/purescript-routing/statuses/595c393e5df27a631517f24ebe6a389af8f155aa","head":{"label":"natefaubion:push-state","ref":"push-state","sha":"595c393e5df27a631517f24ebe6a389af8f155aa","user":{"login":"natefaubion","id":144058,"avatar_url":"https://avatars1.githubusercontent.com/u/144058?v=4","gravatar_id":"","url":"https://api.github.com/users/natefaubion","html_url":"https://github.com/natefaubion","followers_url":"https://api.github.com/users/natefaubion/followers","following_url":"https://api.github.com/users/natefaubion/following{/other_user}","gists_url":"https://api.github.com/users/natefaubion/gists{/gist_id}","starred_url":"https://api.github.com/users/natefaubion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/natefaubion/subscriptions","organizations_url":"https://api.github.com/users/natefaubion/orgs","repos_url":"https://api.github.com/users/natefaubion/repos","events_url":"https://api.github.com/users/natefaubion/events{/privacy}","received_events_url":"https://api.github.com/users/natefaubion/received_events","type":"User","site_admin":false},"repo":{"id":112051676,"name":"purescript-routing","full_name":"natefaubion/purescript-routing","owner":{"login":"natefaubion","id":144058,"avatar_url":"https://avatars1.githubusercontent.com/u/144058?v=4","gravatar_id":"","url":"https://api.github.com/users/natefaubion","html_url":"https://github.com/natefaubion","followers_url":"https://api.github.com/users/natefaubion/followers","following_url":"https://api.github.com/users/natefaubion/following{/other_user}","gists_url":"https://api.github.com/users/natefaubion/gists{/gist_id}","starred_url":"https://api.github.com/users/natefaubion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/natefaubion/subscriptions","organizations_url":"https://api.github.com/users/natefaubion/orgs","repos_url":"https://api.github.com/users/natefaubion/repos","events_url":"https://api.github.com/users/natefaubion/events{/privacy}","received_events_url":"https://api.github.com/users/natefaubion/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/natefaubion/purescript-routing","description":"A clean, type-safe routing library for PureScript.","fork":true,"url":"https://api.github.com/repos/natefaubion/purescript-routing","forks_url":"https://api.github.com/repos/natefaubion/purescript-routing/forks","keys_url":"https://api.github.com/repos/natefaubion/purescript-routing/keys{/key_id}","collaborators_url":"https://api.github.com/repos/natefaubion/purescript-routing/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/natefaubion/purescript-routing/teams","hooks_url":"https://api.github.com/repos/natefaubion/purescript-routing/hooks","issue_events_url":"https://api.github.com/repos/natefaubion/purescript-routing/issues/events{/number}","events_url":"https://api.github.com/repos/natefaubion/purescript-routing/events","assignees_url":"https://api.github.com/repos/natefaubion/purescript-routing/assignees{/user}","branches_url":"https://api.github.com/repos/natefaubion/purescript-routing/branches{/branch}","tags_url":"https://api.github.com/repos/natefaubion/purescript-routing/tags","blobs_url":"https://api.github.com/repos/natefaubion/purescript-routing/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/natefaubion/purescript-routing/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/natefaubion/purescript-routing/git/refs{/sha}","trees_url":"https://api.github.com/repos/natefaubion/purescript-routing/git/trees{/sha}","statuses_url":"https://api.github.com/repos/natefaubion/purescript-routing/statuses/{sha}","languages_url":"https://api.github.com/repos/natefaubion/purescript-routing/languages","stargazers_url":"https://api.github.com/repos/natefaubion/purescript-routing/stargazers","contributors_url":"https://api.github.com/repos/natefaubion/purescript-routing/contributors","subscribers_url":"https://api.github.com/repos/natefaubion/purescript-routing/subscribers","subscription_url":"https://api.github.com/repos/natefaubion/purescript-routing/subscription","commits_url":"https://api.github.com/repos/natefaubion/purescript-routing/commits{/sha}","git_commits_url":"https://api.github.com/repos/natefaubion/purescript-routing/git/commits{/sha}","comments_url":"https://api.github.com/repos/natefaubion/purescript-routing/comments{/number}","issue_comment_url":"https://api.github.com/repos/natefaubion/purescript-routing/issues/comments{/number}","contents_url":"https://api.github.com/repos/natefaubion/purescript-routing/contents/{+path}","compare_url":"https://api.github.com/repos/natefaubion/purescript-routing/compare/{base}...{head}","merges_url":"https://api.github.com/repos/natefaubion/purescript-routing/merges","archive_url":"https://api.github.com/repos/natefaubion/purescript-routing/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/natefaubion/purescript-routing/downloads","issues_url":"https://api.github.com/repos/natefaubion/purescript-routing/issues{/number}","pulls_url":"https://api.github.com/repos/natefaubion/purescript-routing/pulls{/number}","milestones_url":"https://api.github.com/repos/natefaubion/purescript-routing/milestones{/number}","notifications_url":"https://api.github.com/repos/natefaubion/purescript-routing/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/natefaubion/purescript-routing/labels{/name}","releases_url":"https://api.github.com/repos/natefaubion/purescript-routing/releases{/id}","deployments_url":"https://api.github.com/repos/natefaubion/purescript-routing/deployments","created_at":"2017-11-26T03:03:16Z","updated_at":"2017-11-26T03:03:18Z","pushed_at":"2018-03-11T21:36:53Z","git_url":"git://github.com/natefaubion/purescript-routing.git","ssh_url":"git@github.com:natefaubion/purescript-routing.git","clone_url":"https://github.com/natefaubion/purescript-routing.git","svn_url":"https://github.com/natefaubion/purescript-routing","homepage":null,"size":107,"stargazers_count":0,"watchers_count":0,"language":"PureScript","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"slamdata:master","ref":"master","sha":"b4cf23b5e5115055014a13d863c3384cd422e02a","user":{"login":"slamdata","id":5385602,"avatar_url":"https://avatars0.githubusercontent.com/u/5385602?v=4","gravatar_id":"","url":"https://api.github.com/users/slamdata","html_url":"https://github.com/slamdata","followers_url":"https://api.github.com/users/slamdata/followers","following_url":"https://api.github.com/users/slamdata/following{/other_user}","gists_url":"https://api.github.com/users/slamdata/gists{/gist_id}","starred_url":"https://api.github.com/users/slamdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slamdata/subscriptions","organizations_url":"https://api.github.com/users/slamdata/orgs","repos_url":"https://api.github.com/users/slamdata/repos","events_url":"https://api.github.com/users/slamdata/events{/privacy}","received_events_url":"https://api.github.com/users/slamdata/received_events","type":"Organization","site_admin":false},"repo":{"id":31926788,"name":"purescript-routing","full_name":"slamdata/purescript-routing","owner":{"login":"slamdata","id":5385602,"avatar_url":"https://avatars0.githubusercontent.com/u/5385602?v=4","gravatar_id":"","url":"https://api.github.com/users/slamdata","html_url":"https://github.com/slamdata","followers_url":"https://api.github.com/users/slamdata/followers","following_url":"https://api.github.com/users/slamdata/following{/other_user}","gists_url":"https://api.github.com/users/slamdata/gists{/gist_id}","starred_url":"https://api.github.com/users/slamdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slamdata/subscriptions","organizations_url":"https://api.github.com/users/slamdata/orgs","repos_url":"https://api.github.com/users/slamdata/repos","events_url":"https://api.github.com/users/slamdata/events{/privacy}","received_events_url":"https://api.github.com/users/slamdata/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/slamdata/purescript-routing","description":"A clean, type-safe routing library for PureScript.","fork":false,"url":"https://api.github.com/repos/slamdata/purescript-routing","forks_url":"https://api.github.com/repos/slamdata/purescript-routing/forks","keys_url":"https://api.github.com/repos/slamdata/purescript-routing/keys{/key_id}","collaborators_url":"https://api.github.com/repos/slamdata/purescript-routing/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/slamdata/purescript-routing/teams","hooks_url":"https://api.github.com/repos/slamdata/purescript-routing/hooks","issue_events_url":"https://api.github.com/repos/slamdata/purescript-routing/issues/events{/number}","events_url":"https://api.github.com/repos/slamdata/purescript-routing/events","assignees_url":"https://api.github.com/repos/slamdata/purescript-routing/assignees{/user}","branches_url":"https://api.github.com/repos/slamdata/purescript-routing/branches{/branch}","tags_url":"https://api.github.com/repos/slamdata/purescript-routing/tags","blobs_url":"https://api.github.com/repos/slamdata/purescript-routing/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/slamdata/purescript-routing/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/slamdata/purescript-routing/git/refs{/sha}","trees_url":"https://api.github.com/repos/slamdata/purescript-routing/git/trees{/sha}","statuses_url":"https://api.github.com/repos/slamdata/purescript-routing/statuses/{sha}","languages_url":"https://api.github.com/repos/slamdata/purescript-routing/languages","stargazers_url":"https://api.github.com/repos/slamdata/purescript-routing/stargazers","contributors_url":"https://api.github.com/repos/slamdata/purescript-routing/contributors","subscribers_url":"https://api.github.com/repos/slamdata/purescript-routing/subscribers","subscription_url":"https://api.github.com/repos/slamdata/purescript-routing/subscription","commits_url":"https://api.github.com/repos/slamdata/purescript-routing/commits{/sha}","git_commits_url":"https://api.github.com/repos/slamdata/purescript-routing/git/commits{/sha}","comments_url":"https://api.github.com/repos/slamdata/purescript-routing/comments{/number}","issue_comment_url":"https://api.github.com/repos/slamdata/purescript-routing/issues/comments{/number}","contents_url":"https://api.github.com/repos/slamdata/purescript-routing/contents/{+path}","compare_url":"https://api.github.com/repos/slamdata/purescript-routing/compare/{base}...{head}","merges_url":"https://api.github.com/repos/slamdata/purescript-routing/merges","archive_url":"https://api.github.com/repos/slamdata/purescript-routing/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/slamdata/purescript-routing/downloads","issues_url":"https://api.github.com/repos/slamdata/purescript-routing/issues{/number}","pulls_url":"https://api.github.com/repos/slamdata/purescript-routing/pulls{/number}","milestones_url":"https://api.github.com/repos/slamdata/purescript-routing/milestones{/number}","notifications_url":"https://api.github.com/repos/slamdata/purescript-routing/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/slamdata/purescript-routing/labels{/name}","releases_url":"https://api.github.com/repos/slamdata/purescript-routing/releases{/id}","deployments_url":"https://api.github.com/repos/slamdata/purescript-routing/deployments","created_at":"2015-03-09T22:46:54Z","updated_at":"2018-03-12T15:12:11Z","pushed_at":"2018-03-11T21:36:55Z","git_url":"git://github.com/slamdata/purescript-routing.git","ssh_url":"git@github.com:slamdata/purescript-routing.git","clone_url":"https://github.com/slamdata/purescript-routing.git","svn_url":"https://github.com/slamdata/purescript-routing","homepage":null,"size":96,"stargazers_count":44,"watchers_count":44,"language":"PureScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":21,"mirror_url":null,"archived":false,"open_issues_count":9,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":21,"open_issues":9,"watchers":44,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/slamdata/purescript-routing/pulls/51"},"html":{"href":"https://github.com/slamdata/purescript-routing/pull/51"},"issue":{"href":"https://api.github.com/repos/slamdata/purescript-routing/issues/51"},"comments":{"href":"https://api.github.com/repos/slamdata/purescript-routing/issues/51/comments"},"review_comments":{"href":"https://api.github.com/repos/slamdata/purescript-routing/pulls/51/comments"},"review_comment":{"href":"https://api.github.com/repos/slamdata/purescript-routing/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/slamdata/purescript-routing/pulls/51/commits"},"statuses":{"href":"https://api.github.com/repos/slamdata/purescript-routing/statuses/595c393e5df27a631517f24ebe6a389af8f155aa"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"cryogenian"}}