{"action":"created","comment":{"url":"https://api.github.com/repos/hollowverse/hollowverse/pulls/comments/152174110","pull_request_review_id":77994523,"id":152174110,"diff_hunk":"@@ -0,0 +1,7 @@\n+export type ErrorResult = { error: Error | any };\n+export type SuccessResult<T> = { data: T };\n+export type Result<T> = SuccessResult<T> | ErrorResult;\n+\n+export function isErrorResult<T>(result: Result<T>): result is ErrorResult {\n+  return (result as ErrorResult).error !== undefined;\n+}","path":"src/app/helpers/results.ts","position":7,"original_position":7,"commit_id":"2073714f3f9601d83dfc3aea80eaa58a20644355","original_commit_id":"c8ae3b4f18148b38ac9a8ba20e659b0ae8390041","user":{"login":"forabi","id":1012761,"avatar_url":"https://avatars2.githubusercontent.com/u/1012761?v=4","gravatar_id":"","url":"https://api.github.com/users/forabi","html_url":"https://github.com/forabi","followers_url":"https://api.github.com/users/forabi/followers","following_url":"https://api.github.com/users/forabi/following{/other_user}","gists_url":"https://api.github.com/users/forabi/gists{/gist_id}","starred_url":"https://api.github.com/users/forabi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/forabi/subscriptions","organizations_url":"https://api.github.com/users/forabi/orgs","repos_url":"https://api.github.com/users/forabi/repos","events_url":"https://api.github.com/users/forabi/events{/privacy}","received_events_url":"https://api.github.com/users/forabi/received_events","type":"User","site_admin":false},"body":"> What's the point of the generic `T`?\r\n\r\nThis is currently used in `NotablePerson.tsx`. `isErrorResult` needs to accept the type parameter `T` because `Result` is generic with `T` required, and `Result<T>` is generic because we need to express the shape of data returned by the API query.","created_at":"2017-11-21T03:55:04Z","updated_at":"2017-11-21T03:55:05Z","html_url":"https://github.com/hollowverse/hollowverse/pull/210#discussion_r152174110","pull_request_url":"https://api.github.com/repos/hollowverse/hollowverse/pulls/210","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/hollowverse/hollowverse/pulls/comments/152174110"},"html":{"href":"https://github.com/hollowverse/hollowverse/pull/210#discussion_r152174110"},"pull_request":{"href":"https://api.github.com/repos/hollowverse/hollowverse/pulls/210"}},"in_reply_to_id":152162841},"pull_request":{"url":"https://api.github.com/repos/hollowverse/hollowverse/pulls/210","id":152119307,"html_url":"https://github.com/hollowverse/hollowverse/pull/210","diff_url":"https://github.com/hollowverse/hollowverse/pull/210.diff","patch_url":"https://github.com/hollowverse/hollowverse/pull/210.patch","issue_url":"https://api.github.com/repos/hollowverse/hollowverse/issues/210","number":210,"state":"open","locked":false,"title":"Implement Server Side Rendering","user":{"login":"forabi","id":1012761,"avatar_url":"https://avatars2.githubusercontent.com/u/1012761?v=4","gravatar_id":"","url":"https://api.github.com/users/forabi","html_url":"https://github.com/forabi","followers_url":"https://api.github.com/users/forabi/followers","following_url":"https://api.github.com/users/forabi/following{/other_user}","gists_url":"https://api.github.com/users/forabi/gists{/gist_id}","starred_url":"https://api.github.com/users/forabi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/forabi/subscriptions","organizations_url":"https://api.github.com/users/forabi/orgs","repos_url":"https://api.github.com/users/forabi/repos","events_url":"https://api.github.com/users/forabi/events{/privacy}","received_events_url":"https://api.github.com/users/forabi/received_events","type":"User","site_admin":false},"body":"## How it works\r\nThe basic idea for server-side rendering is to generate two Webpack bundles:\r\n\r\n* _Client bundle for browsers_\r\n* _Server bundle for Node.js:_ this bundle exports a function that returns an Express middleware, so its type signature is:\r\n\r\n    ```typescript\r\n    declare function createServerRenderMiddleware(options: Options): RequestHandler\r\n    ```\r\n\r\n    The middleware returned from this function is a standard Express middleware. When it receives a request, let's say for `/Tom_Hanks`, it has to respond with the server-rendered markup of Tom Hanks' page. To be able to do that, it needs to pass the request URL to React Router. The `App` component, which specifies all React Router routes, is wrapped in `StaticRouter`, which is an in-memory router designed for use in Node.js and unit tests.\r\n\r\n     ```typescript\r\n     <StaticRouter context={context} location={req.url}>\r\n      <App />\r\n     </StaticRouter>\r\n     ```\r\n\r\n    Just like in the browser, the router will look for matching components and render them. From there, it is simply a matter of calling React's `renderToString` to generate the markup.\r\n\r\nThings get way more complicated when using Webpack's code-splitting. Until very recently, mixing SSR with code-splitting was considered an almost impossible task.\r\n\r\n## Why is it so complicated?\r\nHere are the problems that need to be solved for SSR with code-splitting:\r\n\r\n* **Synchronous resolution of components on the server:** to be able to render the page on the server, we need to _synchronously_ resolve all the components that would otherwise be loaded asynchronously on the client.\r\n* **Flushing components required for the initial render to the client**: when JS is loaded on the client, the same components that were used to render on the server must be available immediately so that the initial client render matches the server markup. Otherwise, the client will re-fetch the components asynchronously and throw away all the SSR markup. That's wasteful and might lock up the main thread.\r\n* **Loading the rest of the app on demand:** all other components that were not used on the server, should be loaded asynchronously and only when needed (standard code-splitting).\r\n* **Fetching API data on the server:** in addition to all these problems, there's one important problem to solve when doing SSR: we need to fetch data from the API on the server so that the server-rendering markup contains meaningful content instead of loading placeholders. Without that, SSR would not really be much useful.\r\n* **Chunking CSS and loading it in parallel with JS**: as a bonus, it would be great if we could, instead of bundling the entire app's CSS in one big file, chunk CSS per component and, instead of waiting for JS to be fetched and parsed to reach the CSS require call, load the CSS it _in parallel_ with the JS for that component. Well, it turns out it's possible!\r\n\r\nFortunately, the community has finally found the [code to crack these problems](https://medium.com/faceyspacey/code-cracked-for-code-splitting-ssr-in-reactlandia-react-loadable-webpack-flush-chunks-and-1a6b0112a8b8) individually. Here is a table of the libraries used to solve each problem:\r\n\r\nProblem | Library\r\n ----------|-----------\r\nSynchronous resolution of components on the server | [`react-universal-component`](https://github.com/faceyspacey/react-universal-component)\r\nFlushing components required for the initial render to the client | [`webpack-flush-chunks`](https://github.com/faceyspacey/webpack-flush-chunks/)\r\nLoading the rest of the app on demand | [built-in webpack feature](https://webpack.js.org/guides/code-splitting/)\r\nFetching API data on the server | [`react-resolver`](https://github.com/ericclemmons/react-resolver)\r\nChunking CSS and loading it in parallel with JS | [`extract-css-chunks-webpack-plugin`](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin) + `react-universal-component`\r\n\r\n[This article](https://medium.com/discovery-engineering/component-level-isomorphic-webpack-code-splitting-b98922382cc1) sums up the complexity of server-side rendering with code-splitting and also goes into detail on the same libraries I used in this PR.\r\n\r\n\r\n### Directory structure\r\nThis PR required changes to the directory structure to be able to more easily connect the server rendering middleware with the client bundle.\r\n\r\nOld directory structure:\r\n\r\n```\r\n.\r\n├── client\r\n│   ├── dist\r\n│   └── src\r\n└── server\r\n    ├── dist\r\n    └── src\r\n```\r\n\r\nNew directory strucutre:\r\n\r\n```\r\n.\r\n├── dist\r\n│   ├── appServer.js (serves new app, including the SSR middleware and the client bundle)\r\n│   ├── mainServer.js (redirects to new app or old website according to redirection map)\r\n│   ├── client (webpack's client bundle)\r\n│   └── server (webpack's server bundle)\r\n└── src\r\n    ├── app (new app code)\r\n    ├── appServer.ts\r\n    ├── mainServer.ts\r\n    ├── middleware\r\n    │   ├── redirectToHttps.ts\r\n    │   └── security.ts\r\n    └── webpack (webpack configuration files)\r\n        ├── webpack.config.client.js\r\n        ├── webpack.config.common.js\r\n        └── webpack.config.server.js\r\n```\r\n\r\n### Developer Experience\r\nThis PR does not negatively impact the developer experience. Hot Module Reloading still works as expected and no server restarts are required.\r\n\r\n### Other updates in this PR\r\n* Enable gzip and brotli compression for static assets\r\n* Enable caching for static assets, with `immutable` directive\r\n* Add favicons for desktop and different mobile platforms\r\n* Refactor CSS to use CSS modules\r\n\r\n## Tasks\r\n* [x] Split webpack configuration into server, client and common\r\n  * [x] Create webpack server entry file\r\n  * [x] Configure hot module reloading for server bundle too\r\n* [x] Extract middlewares to separate folder\r\n  * [x] Extract security middlewares\r\n* [x] Reorganize server code into:\r\n  * [x] **App server**: serves the new, server-side rendered app as well as the client assets\r\n    * [x] Make sure to use the security middlewares for the app server too\r\n    * [x] Serve static assets at `/static/` to more easily control caching headers and compression\r\n    * [x] Enable gzip and brotli compression for static assets\r\n    * [x] Enable caching for static assets for a reasonably long time\r\n      * [x] Use the `immutable` directive for `Cache-Control` header to tell browsers to never check again if the static resource has expired\r\n  * [x] **Main server**: routes requests to the new app or the old website according to the redirection rules\r\n  * [x] Do not start a separate server for the new app, instead export a middleware and use it in the main server\r\n* [x] Use `PureComponent`\r\n* [x] Do not use `index.tsx` for component filenames\r\n* [x] Refactor CSS for CSS Modules\r\n* [x] Make sure `postcss-normalize` is only bundled once\r\n* [x] Replace usage of `react-loadable` with `react-universal-component` where it makes sense\r\n* [x] Write script to build server and client on CI\r\n* [x] Make sure all `nodeExternals` are production dependencies\r\n* [x] Support development workflow with hot module reloading for server-side rendering (server restart and rebuilds should not be required)\r\n* [x] Remove unneeded dependencies\r\n* [x] Comment `webpack.config.server.js` and `webpack.config.client.js`\r\n* [x] Comment `babel.js`\r\n* [x] Follow naming convention for components in `pages`\r\n* [x] Fix imports of SVG files\r\n* [x] Generate and use favicons from new logo\r\n* [x] Handle `react-resolver` errors per-component\r\n* [x] Write and contribute type definitions for:\r\n  * [x] `react-resolver` (https://github.com/ericclemmons/react-resolver/pull/133)\r\n  * [x] `react-universal-component` (https://github.com/faceyspacey/react-universal-component/pull/75)\r\n  * [x] `webpack-flush-chunks` (https://github.com/faceyspacey/webpack-flush-chunks/pull/50)\r\n  * [x] `shrink-ray` (https://github.com/aickin/shrink-ray/pull/17)\r\n  * [x] `webpack-hot-server-middleware` (https://github.com/60frames/webpack-hot-server-middleware/pull/49)\r\n  * [ ] ~`webpack-merge`~ (rewrite in progress https://github.com/survivejs/webpack-merge/pull/95)\r\n\r\nCloses #203 \r\nCloses #204 (although we could still investigate the CDN solution in the future)","created_at":"2017-11-12T19:36:03Z","updated_at":"2017-11-21T03:55:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fd092d3d1e3760339ce380ba4887206e1041dc78","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/hollowverse/hollowverse/pulls/210/commits","review_comments_url":"https://api.github.com/repos/hollowverse/hollowverse/pulls/210/comments","review_comment_url":"https://api.github.com/repos/hollowverse/hollowverse/pulls/comments{/number}","comments_url":"https://api.github.com/repos/hollowverse/hollowverse/issues/210/comments","statuses_url":"https://api.github.com/repos/hollowverse/hollowverse/statuses/2073714f3f9601d83dfc3aea80eaa58a20644355","head":{"label":"forabi:ssr","ref":"ssr","sha":"2073714f3f9601d83dfc3aea80eaa58a20644355","user":{"login":"forabi","id":1012761,"avatar_url":"https://avatars2.githubusercontent.com/u/1012761?v=4","gravatar_id":"","url":"https://api.github.com/users/forabi","html_url":"https://github.com/forabi","followers_url":"https://api.github.com/users/forabi/followers","following_url":"https://api.github.com/users/forabi/following{/other_user}","gists_url":"https://api.github.com/users/forabi/gists{/gist_id}","starred_url":"https://api.github.com/users/forabi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/forabi/subscriptions","organizations_url":"https://api.github.com/users/forabi/orgs","repos_url":"https://api.github.com/users/forabi/repos","events_url":"https://api.github.com/users/forabi/events{/privacy}","received_events_url":"https://api.github.com/users/forabi/received_events","type":"User","site_admin":false},"repo":{"id":95765062,"name":"hollowverse","full_name":"forabi/hollowverse","owner":{"login":"forabi","id":1012761,"avatar_url":"https://avatars2.githubusercontent.com/u/1012761?v=4","gravatar_id":"","url":"https://api.github.com/users/forabi","html_url":"https://github.com/forabi","followers_url":"https://api.github.com/users/forabi/followers","following_url":"https://api.github.com/users/forabi/following{/other_user}","gists_url":"https://api.github.com/users/forabi/gists{/gist_id}","starred_url":"https://api.github.com/users/forabi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/forabi/subscriptions","organizations_url":"https://api.github.com/users/forabi/orgs","repos_url":"https://api.github.com/users/forabi/repos","events_url":"https://api.github.com/users/forabi/events{/privacy}","received_events_url":"https://api.github.com/users/forabi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/forabi/hollowverse","description":"The new Hollowverse.com","fork":true,"url":"https://api.github.com/repos/forabi/hollowverse","forks_url":"https://api.github.com/repos/forabi/hollowverse/forks","keys_url":"https://api.github.com/repos/forabi/hollowverse/keys{/key_id}","collaborators_url":"https://api.github.com/repos/forabi/hollowverse/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/forabi/hollowverse/teams","hooks_url":"https://api.github.com/repos/forabi/hollowverse/hooks","issue_events_url":"https://api.github.com/repos/forabi/hollowverse/issues/events{/number}","events_url":"https://api.github.com/repos/forabi/hollowverse/events","assignees_url":"https://api.github.com/repos/forabi/hollowverse/assignees{/user}","branches_url":"https://api.github.com/repos/forabi/hollowverse/branches{/branch}","tags_url":"https://api.github.com/repos/forabi/hollowverse/tags","blobs_url":"https://api.github.com/repos/forabi/hollowverse/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/forabi/hollowverse/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/forabi/hollowverse/git/refs{/sha}","trees_url":"https://api.github.com/repos/forabi/hollowverse/git/trees{/sha}","statuses_url":"https://api.github.com/repos/forabi/hollowverse/statuses/{sha}","languages_url":"https://api.github.com/repos/forabi/hollowverse/languages","stargazers_url":"https://api.github.com/repos/forabi/hollowverse/stargazers","contributors_url":"https://api.github.com/repos/forabi/hollowverse/contributors","subscribers_url":"https://api.github.com/repos/forabi/hollowverse/subscribers","subscription_url":"https://api.github.com/repos/forabi/hollowverse/subscription","commits_url":"https://api.github.com/repos/forabi/hollowverse/commits{/sha}","git_commits_url":"https://api.github.com/repos/forabi/hollowverse/git/commits{/sha}","comments_url":"https://api.github.com/repos/forabi/hollowverse/comments{/number}","issue_comment_url":"https://api.github.com/repos/forabi/hollowverse/issues/comments{/number}","contents_url":"https://api.github.com/repos/forabi/hollowverse/contents/{+path}","compare_url":"https://api.github.com/repos/forabi/hollowverse/compare/{base}...{head}","merges_url":"https://api.github.com/repos/forabi/hollowverse/merges","archive_url":"https://api.github.com/repos/forabi/hollowverse/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/forabi/hollowverse/downloads","issues_url":"https://api.github.com/repos/forabi/hollowverse/issues{/number}","pulls_url":"https://api.github.com/repos/forabi/hollowverse/pulls{/number}","milestones_url":"https://api.github.com/repos/forabi/hollowverse/milestones{/number}","notifications_url":"https://api.github.com/repos/forabi/hollowverse/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/forabi/hollowverse/labels{/name}","releases_url":"https://api.github.com/repos/forabi/hollowverse/releases{/id}","deployments_url":"https://api.github.com/repos/forabi/hollowverse/deployments","created_at":"2017-06-29T10:07:57Z","updated_at":"2017-06-29T10:07:59Z","pushed_at":"2017-11-21T03:54:10Z","git_url":"git://github.com/forabi/hollowverse.git","ssh_url":"git@github.com:forabi/hollowverse.git","clone_url":"https://github.com/forabi/hollowverse.git","svn_url":"https://github.com/forabi/hollowverse","homepage":"https://x.hollowverse.com","size":9816,"stargazers_count":0,"watchers_count":0,"language":"TypeScript","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,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"hollowverse:master","ref":"master","sha":"6bf9c9c830ba226d5f91ee75e0eb463b576c75ae","user":{"login":"hollowverse","id":26698836,"avatar_url":"https://avatars0.githubusercontent.com/u/26698836?v=4","gravatar_id":"","url":"https://api.github.com/users/hollowverse","html_url":"https://github.com/hollowverse","followers_url":"https://api.github.com/users/hollowverse/followers","following_url":"https://api.github.com/users/hollowverse/following{/other_user}","gists_url":"https://api.github.com/users/hollowverse/gists{/gist_id}","starred_url":"https://api.github.com/users/hollowverse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hollowverse/subscriptions","organizations_url":"https://api.github.com/users/hollowverse/orgs","repos_url":"https://api.github.com/users/hollowverse/repos","events_url":"https://api.github.com/users/hollowverse/events{/privacy}","received_events_url":"https://api.github.com/users/hollowverse/received_events","type":"Organization","site_admin":false},"repo":{"id":86410197,"name":"hollowverse","full_name":"hollowverse/hollowverse","owner":{"login":"hollowverse","id":26698836,"avatar_url":"https://avatars0.githubusercontent.com/u/26698836?v=4","gravatar_id":"","url":"https://api.github.com/users/hollowverse","html_url":"https://github.com/hollowverse","followers_url":"https://api.github.com/users/hollowverse/followers","following_url":"https://api.github.com/users/hollowverse/following{/other_user}","gists_url":"https://api.github.com/users/hollowverse/gists{/gist_id}","starred_url":"https://api.github.com/users/hollowverse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hollowverse/subscriptions","organizations_url":"https://api.github.com/users/hollowverse/orgs","repos_url":"https://api.github.com/users/hollowverse/repos","events_url":"https://api.github.com/users/hollowverse/events{/privacy}","received_events_url":"https://api.github.com/users/hollowverse/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/hollowverse/hollowverse","description":"The new Hollowverse.com","fork":false,"url":"https://api.github.com/repos/hollowverse/hollowverse","forks_url":"https://api.github.com/repos/hollowverse/hollowverse/forks","keys_url":"https://api.github.com/repos/hollowverse/hollowverse/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hollowverse/hollowverse/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hollowverse/hollowverse/teams","hooks_url":"https://api.github.com/repos/hollowverse/hollowverse/hooks","issue_events_url":"https://api.github.com/repos/hollowverse/hollowverse/issues/events{/number}","events_url":"https://api.github.com/repos/hollowverse/hollowverse/events","assignees_url":"https://api.github.com/repos/hollowverse/hollowverse/assignees{/user}","branches_url":"https://api.github.com/repos/hollowverse/hollowverse/branches{/branch}","tags_url":"https://api.github.com/repos/hollowverse/hollowverse/tags","blobs_url":"https://api.github.com/repos/hollowverse/hollowverse/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hollowverse/hollowverse/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hollowverse/hollowverse/git/refs{/sha}","trees_url":"https://api.github.com/repos/hollowverse/hollowverse/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hollowverse/hollowverse/statuses/{sha}","languages_url":"https://api.github.com/repos/hollowverse/hollowverse/languages","stargazers_url":"https://api.github.com/repos/hollowverse/hollowverse/stargazers","contributors_url":"https://api.github.com/repos/hollowverse/hollowverse/contributors","subscribers_url":"https://api.github.com/repos/hollowverse/hollowverse/subscribers","subscription_url":"https://api.github.com/repos/hollowverse/hollowverse/subscription","commits_url":"https://api.github.com/repos/hollowverse/hollowverse/commits{/sha}","git_commits_url":"https://api.github.com/repos/hollowverse/hollowverse/git/commits{/sha}","comments_url":"https://api.github.com/repos/hollowverse/hollowverse/comments{/number}","issue_comment_url":"https://api.github.com/repos/hollowverse/hollowverse/issues/comments{/number}","contents_url":"https://api.github.com/repos/hollowverse/hollowverse/contents/{+path}","compare_url":"https://api.github.com/repos/hollowverse/hollowverse/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hollowverse/hollowverse/merges","archive_url":"https://api.github.com/repos/hollowverse/hollowverse/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hollowverse/hollowverse/downloads","issues_url":"https://api.github.com/repos/hollowverse/hollowverse/issues{/number}","pulls_url":"https://api.github.com/repos/hollowverse/hollowverse/pulls{/number}","milestones_url":"https://api.github.com/repos/hollowverse/hollowverse/milestones{/number}","notifications_url":"https://api.github.com/repos/hollowverse/hollowverse/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hollowverse/hollowverse/labels{/name}","releases_url":"https://api.github.com/repos/hollowverse/hollowverse/releases{/id}","deployments_url":"https://api.github.com/repos/hollowverse/hollowverse/deployments","created_at":"2017-03-28T03:21:35Z","updated_at":"2017-11-14T20:30:28Z","pushed_at":"2017-11-21T03:54:11Z","git_url":"git://github.com/hollowverse/hollowverse.git","ssh_url":"git@github.com:hollowverse/hollowverse.git","clone_url":"https://github.com/hollowverse/hollowverse.git","svn_url":"https://github.com/hollowverse/hollowverse","homepage":"","size":8717,"stargazers_count":6,"watchers_count":6,"language":"TypeScript","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"archived":false,"open_issues_count":5,"forks":4,"open_issues":5,"watchers":6,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/hollowverse/hollowverse/pulls/210"},"html":{"href":"https://github.com/hollowverse/hollowverse/pull/210"},"issue":{"href":"https://api.github.com/repos/hollowverse/hollowverse/issues/210"},"comments":{"href":"https://api.github.com/repos/hollowverse/hollowverse/issues/210/comments"},"review_comments":{"href":"https://api.github.com/repos/hollowverse/hollowverse/pulls/210/comments"},"review_comment":{"href":"https://api.github.com/repos/hollowverse/hollowverse/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/hollowverse/hollowverse/pulls/210/commits"},"statuses":{"href":"https://api.github.com/repos/hollowverse/hollowverse/statuses/2073714f3f9601d83dfc3aea80eaa58a20644355"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"forabi"}}