{"action":"created","comment":{"url":"https://api.github.com/repos/osmlab/atlas/pulls/comments/171661109","pull_request_review_id":100529635,"id":171661109,"diff_hunk":"@@ -1,40 +1,223 @@\n package org.openstreetmap.atlas.geography.boundary;\n \n import java.util.List;\n+import java.util.concurrent.BlockingQueue;\n+import java.util.concurrent.LinkedBlockingQueue;\n+import java.util.stream.IntStream;\n \n import org.openstreetmap.atlas.tags.ISOCountryTag;\n-import org.openstreetmap.atlas.utilities.maps.MultiMap;\n+import org.openstreetmap.atlas.utilities.threads.Pool;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n \n import com.vividsolutions.jts.geom.Envelope;\n import com.vividsolutions.jts.geom.Polygon;\n import com.vividsolutions.jts.geom.TopologyException;\n import com.vividsolutions.jts.index.strtree.STRtree;\n \n /**\n- * This builder builds a spatial index using R-tree based on JTS. Instead of equally divided grid\n- * index, dynamic grid index use a 2d kd-tree like structure to generate cells dynamically. This\n- * reduces the number of cells generated and allow us to generate much smaller cells at boundary to\n- * improve search performance by reducing false positive hits.\n+ * This builder builds a spatial index using {@link STRtree} based on JTS. Instead of equally\n+ * divided grid index, dynamic grid index use a 2d kd-tree like structure to generate cells\n+ * dynamically. This reduces the number of cells generated and allow us to generate much smaller\n+ * cells at boundary to improve search performance by reducing false positive hits.\n  *\n  * @author Yiqing Jin\n+ * @author mkalender\n  */\n public class DynamicGridIndexBuilder extends AbstractGridIndexBuilder\n {\n+    /**\n+     * A class to hold units of work while building grid index.\n+     *\n+     * @author mkalender\n+     */\n+    private class GridWorkItem\n+    {\n+        private final double minX;\n+        private final double minY;\n+        private final double maxX;\n+        private final double maxY;\n+        private final Polygon polygon;\n+\n+        /**\n+         * Default constructor\n+         *\n+         * @param minX\n+         *            Lower bound on X-axis\n+         * @param minY\n+         *            Lower bound on Y-axis\n+         * @param maxX\n+         *            Upper bound on X-axis\n+         * @param maxY\n+         *            Upper bound on Y-axis\n+         * @param polygon\n+         *            Boundary in {@link Polygon} format\n+         */\n+        GridWorkItem(final double minX, final double minY, final double maxX, final double maxY,\n+                final Polygon polygon)\n+        {\n+            this.minX = minX;\n+            this.minY = minY;\n+            this.maxX = maxX;\n+            this.maxY = maxY;\n+            this.polygon = polygon;\n+        }\n+    }\n+\n+    /**\n+     * Worker that acts like both producer and consumer. Takes an {@link GridWorkItem} from work\n+     * queue and processes it.\n+     *\n+     * @author mkalender\n+     */\n+    private class Processor implements Runnable\n+    {\n+        private final BlockingQueue<GridWorkItem> queue;\n+        private final STRtree index;\n+        private final STRtree rawIndex;\n+\n+        /**\n+         * Default constructor.\n+         *\n+         * @param queue\n+         *            {@link BlockingQueue} holding {@link GridWorkItem}s to process\n+         * @param index\n+         *            {@link STRtree} to be built\n+         * @param rawIndex\n+         *            {@link STRtree} holding raw boundaries\n+         */\n+        Processor(final BlockingQueue<GridWorkItem> queue, final STRtree index,\n+                final STRtree rawIndex)\n+        {\n+            this.queue = queue;\n+            this.index = index;\n+            this.rawIndex = rawIndex;\n+        }\n+\n+        @Override\n+        public void run()\n+        {\n+            try\n+            {\n+                while (!this.queue.isEmpty())\n+                {\n+                    final GridWorkItem itemToProcess = this.queue.poll();\n+\n+                    // Queue might have been emptied by another thread. That gives an null item.\n+                    // Check for null item to avoid an exception.\n+                    if (itemToProcess != null)\n+                    {\n+                        this.process(itemToProcess);\n+                    }\n+                }\n+","path":"src/main/java/org/openstreetmap/atlas/geography/boundary/DynamicGridIndexBuilder.java","position":118,"original_position":118,"commit_id":"2f20dd187575a9e49e47167665b98955502cbfad","original_commit_id":"2f20dd187575a9e49e47167665b98955502cbfad","user":{"login":"MikeGost","id":18317260,"avatar_url":"https://avatars3.githubusercontent.com/u/18317260?v=4","gravatar_id":"","url":"https://api.github.com/users/MikeGost","html_url":"https://github.com/MikeGost","followers_url":"https://api.github.com/users/MikeGost/followers","following_url":"https://api.github.com/users/MikeGost/following{/other_user}","gists_url":"https://api.github.com/users/MikeGost/gists{/gist_id}","starred_url":"https://api.github.com/users/MikeGost/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MikeGost/subscriptions","organizations_url":"https://api.github.com/users/MikeGost/orgs","repos_url":"https://api.github.com/users/MikeGost/repos","events_url":"https://api.github.com/users/MikeGost/events{/privacy}","received_events_url":"https://api.github.com/users/MikeGost/received_events","type":"User","site_admin":false},"body":"Nit: extra line","created_at":"2018-03-01T19:06:21Z","updated_at":"2018-03-01T19:14:22Z","html_url":"https://github.com/osmlab/atlas/pull/90#discussion_r171661109","pull_request_url":"https://api.github.com/repos/osmlab/atlas/pulls/90","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/osmlab/atlas/pulls/comments/171661109"},"html":{"href":"https://github.com/osmlab/atlas/pull/90#discussion_r171661109"},"pull_request":{"href":"https://api.github.com/repos/osmlab/atlas/pulls/90"}}},"pull_request":{"url":"https://api.github.com/repos/osmlab/atlas/pulls/90","id":171796750,"html_url":"https://github.com/osmlab/atlas/pull/90","diff_url":"https://github.com/osmlab/atlas/pull/90.diff","patch_url":"https://github.com/osmlab/atlas/pull/90.patch","issue_url":"https://api.github.com/repos/osmlab/atlas/issues/90","number":90,"state":"open","locked":false,"title":"Improve CountryBoundaryMap dynamic grid index generation performance and fix serialization","user":{"login":"mertemin","id":597707,"avatar_url":"https://avatars3.githubusercontent.com/u/597707?v=4","gravatar_id":"","url":"https://api.github.com/users/mertemin","html_url":"https://github.com/mertemin","followers_url":"https://api.github.com/users/mertemin/followers","following_url":"https://api.github.com/users/mertemin/following{/other_user}","gists_url":"https://api.github.com/users/mertemin/gists{/gist_id}","starred_url":"https://api.github.com/users/mertemin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mertemin/subscriptions","organizations_url":"https://api.github.com/users/mertemin/orgs","repos_url":"https://api.github.com/users/mertemin/repos","events_url":"https://api.github.com/users/mertemin/events{/privacy}","received_events_url":"https://api.github.com/users/mertemin/received_events","type":"User","site_admin":false},"body":"This PR makes significant updates to `CountryBoundaryMap`. Grid index cells generated by `DynamicGridIndexBuilder` are used in `CountryBoundaryMap` for Atlas slicing operation (slicing features that cross country boundaries). Right now grid index is not properly serialized, hence populated in Atlas generation process. Also `CountryBoundaryMap` API has grown a lot and not easy to work with. `slice` method could be subject to random inconsistency issues, because it is slicing features by the order of results coming from R tree.\r\n\r\nHere is a quick summary of changes:\r\n\r\n**CountryBoundaryMap**\r\n- `CountryBoundaryMap` had several constructors and entry points for clients (existing `CountryBoundaryMap` objects, `Atlas` objects, shp files). These entry points were constrained by the bounds of operation. That resulted in several constructors. Now there is two entry points: default `CountryBoundaryMap` that doesn't have bound limits and one with bounds. In case we have an existing artifact like Atlas files or shp file, these artifacts can go through helper methods.\r\n- Dropped all `createGridIndex` methods and changed them to `initializeGridIndex`.  Additional parameter `saveGridIndexCells` to collect grid cells is dropped as well. Now grid index is initialized with `initializeGridIndex` method and grid index cells can be extracted from `STRtree` without additional data structure. Collecting grid index cells from `STRtree` is done via `collectCells` method.\r\n- `slice` method is updated for consistency. Cells returned from grid index are first sorted by country name before slicing operation to avoid randomness in the slicing results. Country name that comes first alphabetically will be used first for slicing.\r\n- Read and write operations are updated and grid index cells are now saved to files and can be read back to populate grid index.\r\n- Now that read/write operations of grid index cells are fixed, grid index generation operations in `OsmPbfProcessor` and `RawAtlasCountrySlicer` are removed.\r\n- Useful helper methods are added to `CountryBoundaryMap` like `geometries` to read inner geometries of a given geometry collection, `boundariesHelper` to easily filter given geometries (mostly used in query operations.\r\n- `removeDuplicate` is removed and replaced with `stream().distinct()` call.\r\n\r\n**DynamicGridIndexBuilder**\r\n- `GridWorkItem` and `Processor` inner classes introduced to generate grid index cells in parallel.\r\n- Logic that generates grid cells stay the same.\r\n- Extra data structure to cache grid cells is dropped, since now cells can be collected from `STRtree`.\r\n- Test class is updated and new tests are added.\r\n\r\n**Other classes**\r\n- `CountryBoundaryMapCompareCommand` to compare different boundary maps. The order of countries could be different, but that should not affect the tree structure. This command is useful to make sure that.\r\n- Classes that create `CountryBoundaryMap` instances are all updated.\r\n- Boundary files with grid indices are all replaced with new files.\r\n\r\nAfter these changes explained above, grid index generation performance improves significantly on multiple cores (i.e. a shp file with world countries generation time improved ~20x). Integration tests in `OsmPbfToSlicedRawAtlasTest` class is now running 30% faster. Atlas generation performance improves as well given that grid index is pre-populated and ready to use.","created_at":"2018-02-27T21:58:25Z","updated_at":"2018-03-01T19:14:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"05b926bba38e08e517255ceec0bde6d17d428efa","assignee":{"login":"MikeGost","id":18317260,"avatar_url":"https://avatars3.githubusercontent.com/u/18317260?v=4","gravatar_id":"","url":"https://api.github.com/users/MikeGost","html_url":"https://github.com/MikeGost","followers_url":"https://api.github.com/users/MikeGost/followers","following_url":"https://api.github.com/users/MikeGost/following{/other_user}","gists_url":"https://api.github.com/users/MikeGost/gists{/gist_id}","starred_url":"https://api.github.com/users/MikeGost/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MikeGost/subscriptions","organizations_url":"https://api.github.com/users/MikeGost/orgs","repos_url":"https://api.github.com/users/MikeGost/repos","events_url":"https://api.github.com/users/MikeGost/events{/privacy}","received_events_url":"https://api.github.com/users/MikeGost/received_events","type":"User","site_admin":false},"assignees":[{"login":"MikeGost","id":18317260,"avatar_url":"https://avatars3.githubusercontent.com/u/18317260?v=4","gravatar_id":"","url":"https://api.github.com/users/MikeGost","html_url":"https://github.com/MikeGost","followers_url":"https://api.github.com/users/MikeGost/followers","following_url":"https://api.github.com/users/MikeGost/following{/other_user}","gists_url":"https://api.github.com/users/MikeGost/gists{/gist_id}","starred_url":"https://api.github.com/users/MikeGost/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MikeGost/subscriptions","organizations_url":"https://api.github.com/users/MikeGost/orgs","repos_url":"https://api.github.com/users/MikeGost/repos","events_url":"https://api.github.com/users/MikeGost/events{/privacy}","received_events_url":"https://api.github.com/users/MikeGost/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":664543817,"url":"https://api.github.com/repos/osmlab/atlas/labels/Bug","name":"Bug","color":"ee0701","default":false},{"id":664543819,"url":"https://api.github.com/repos/osmlab/atlas/labels/Enhancement","name":"Enhancement","color":"84b6eb","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/osmlab/atlas/pulls/90/commits","review_comments_url":"https://api.github.com/repos/osmlab/atlas/pulls/90/comments","review_comment_url":"https://api.github.com/repos/osmlab/atlas/pulls/comments{/number}","comments_url":"https://api.github.com/repos/osmlab/atlas/issues/90/comments","statuses_url":"https://api.github.com/repos/osmlab/atlas/statuses/2f20dd187575a9e49e47167665b98955502cbfad","head":{"label":"mertemin:feature-x","ref":"feature-x","sha":"2f20dd187575a9e49e47167665b98955502cbfad","user":{"login":"mertemin","id":597707,"avatar_url":"https://avatars3.githubusercontent.com/u/597707?v=4","gravatar_id":"","url":"https://api.github.com/users/mertemin","html_url":"https://github.com/mertemin","followers_url":"https://api.github.com/users/mertemin/followers","following_url":"https://api.github.com/users/mertemin/following{/other_user}","gists_url":"https://api.github.com/users/mertemin/gists{/gist_id}","starred_url":"https://api.github.com/users/mertemin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mertemin/subscriptions","organizations_url":"https://api.github.com/users/mertemin/orgs","repos_url":"https://api.github.com/users/mertemin/repos","events_url":"https://api.github.com/users/mertemin/events{/privacy}","received_events_url":"https://api.github.com/users/mertemin/received_events","type":"User","site_admin":false},"repo":{"id":116298849,"name":"atlas","full_name":"mertemin/atlas","owner":{"login":"mertemin","id":597707,"avatar_url":"https://avatars3.githubusercontent.com/u/597707?v=4","gravatar_id":"","url":"https://api.github.com/users/mertemin","html_url":"https://github.com/mertemin","followers_url":"https://api.github.com/users/mertemin/followers","following_url":"https://api.github.com/users/mertemin/following{/other_user}","gists_url":"https://api.github.com/users/mertemin/gists{/gist_id}","starred_url":"https://api.github.com/users/mertemin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mertemin/subscriptions","organizations_url":"https://api.github.com/users/mertemin/orgs","repos_url":"https://api.github.com/users/mertemin/repos","events_url":"https://api.github.com/users/mertemin/events{/privacy}","received_events_url":"https://api.github.com/users/mertemin/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mertemin/atlas","description":"OSM in memory","fork":true,"url":"https://api.github.com/repos/mertemin/atlas","forks_url":"https://api.github.com/repos/mertemin/atlas/forks","keys_url":"https://api.github.com/repos/mertemin/atlas/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mertemin/atlas/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mertemin/atlas/teams","hooks_url":"https://api.github.com/repos/mertemin/atlas/hooks","issue_events_url":"https://api.github.com/repos/mertemin/atlas/issues/events{/number}","events_url":"https://api.github.com/repos/mertemin/atlas/events","assignees_url":"https://api.github.com/repos/mertemin/atlas/assignees{/user}","branches_url":"https://api.github.com/repos/mertemin/atlas/branches{/branch}","tags_url":"https://api.github.com/repos/mertemin/atlas/tags","blobs_url":"https://api.github.com/repos/mertemin/atlas/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mertemin/atlas/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mertemin/atlas/git/refs{/sha}","trees_url":"https://api.github.com/repos/mertemin/atlas/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mertemin/atlas/statuses/{sha}","languages_url":"https://api.github.com/repos/mertemin/atlas/languages","stargazers_url":"https://api.github.com/repos/mertemin/atlas/stargazers","contributors_url":"https://api.github.com/repos/mertemin/atlas/contributors","subscribers_url":"https://api.github.com/repos/mertemin/atlas/subscribers","subscription_url":"https://api.github.com/repos/mertemin/atlas/subscription","commits_url":"https://api.github.com/repos/mertemin/atlas/commits{/sha}","git_commits_url":"https://api.github.com/repos/mertemin/atlas/git/commits{/sha}","comments_url":"https://api.github.com/repos/mertemin/atlas/comments{/number}","issue_comment_url":"https://api.github.com/repos/mertemin/atlas/issues/comments{/number}","contents_url":"https://api.github.com/repos/mertemin/atlas/contents/{+path}","compare_url":"https://api.github.com/repos/mertemin/atlas/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mertemin/atlas/merges","archive_url":"https://api.github.com/repos/mertemin/atlas/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mertemin/atlas/downloads","issues_url":"https://api.github.com/repos/mertemin/atlas/issues{/number}","pulls_url":"https://api.github.com/repos/mertemin/atlas/pulls{/number}","milestones_url":"https://api.github.com/repos/mertemin/atlas/milestones{/number}","notifications_url":"https://api.github.com/repos/mertemin/atlas/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mertemin/atlas/labels{/name}","releases_url":"https://api.github.com/repos/mertemin/atlas/releases{/id}","deployments_url":"https://api.github.com/repos/mertemin/atlas/deployments","created_at":"2018-01-04T19:23:57Z","updated_at":"2018-01-04T19:24:01Z","pushed_at":"2018-02-28T21:30:39Z","git_url":"git://github.com/mertemin/atlas.git","ssh_url":"git@github.com:mertemin/atlas.git","clone_url":"https://github.com/mertemin/atlas.git","svn_url":"https://github.com/mertemin/atlas","homepage":null,"size":51913,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"dev"}},"base":{"label":"osmlab:dev","ref":"dev","sha":"f65add16825fd30c7d0111c926ae1ac0f28691fb","user":{"login":"osmlab","id":3856374,"avatar_url":"https://avatars3.githubusercontent.com/u/3856374?v=4","gravatar_id":"","url":"https://api.github.com/users/osmlab","html_url":"https://github.com/osmlab","followers_url":"https://api.github.com/users/osmlab/followers","following_url":"https://api.github.com/users/osmlab/following{/other_user}","gists_url":"https://api.github.com/users/osmlab/gists{/gist_id}","starred_url":"https://api.github.com/users/osmlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/osmlab/subscriptions","organizations_url":"https://api.github.com/users/osmlab/orgs","repos_url":"https://api.github.com/users/osmlab/repos","events_url":"https://api.github.com/users/osmlab/events{/privacy}","received_events_url":"https://api.github.com/users/osmlab/received_events","type":"Organization","site_admin":false},"repo":{"id":99717758,"name":"atlas","full_name":"osmlab/atlas","owner":{"login":"osmlab","id":3856374,"avatar_url":"https://avatars3.githubusercontent.com/u/3856374?v=4","gravatar_id":"","url":"https://api.github.com/users/osmlab","html_url":"https://github.com/osmlab","followers_url":"https://api.github.com/users/osmlab/followers","following_url":"https://api.github.com/users/osmlab/following{/other_user}","gists_url":"https://api.github.com/users/osmlab/gists{/gist_id}","starred_url":"https://api.github.com/users/osmlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/osmlab/subscriptions","organizations_url":"https://api.github.com/users/osmlab/orgs","repos_url":"https://api.github.com/users/osmlab/repos","events_url":"https://api.github.com/users/osmlab/events{/privacy}","received_events_url":"https://api.github.com/users/osmlab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/osmlab/atlas","description":"OSM in memory","fork":false,"url":"https://api.github.com/repos/osmlab/atlas","forks_url":"https://api.github.com/repos/osmlab/atlas/forks","keys_url":"https://api.github.com/repos/osmlab/atlas/keys{/key_id}","collaborators_url":"https://api.github.com/repos/osmlab/atlas/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/osmlab/atlas/teams","hooks_url":"https://api.github.com/repos/osmlab/atlas/hooks","issue_events_url":"https://api.github.com/repos/osmlab/atlas/issues/events{/number}","events_url":"https://api.github.com/repos/osmlab/atlas/events","assignees_url":"https://api.github.com/repos/osmlab/atlas/assignees{/user}","branches_url":"https://api.github.com/repos/osmlab/atlas/branches{/branch}","tags_url":"https://api.github.com/repos/osmlab/atlas/tags","blobs_url":"https://api.github.com/repos/osmlab/atlas/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/osmlab/atlas/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/osmlab/atlas/git/refs{/sha}","trees_url":"https://api.github.com/repos/osmlab/atlas/git/trees{/sha}","statuses_url":"https://api.github.com/repos/osmlab/atlas/statuses/{sha}","languages_url":"https://api.github.com/repos/osmlab/atlas/languages","stargazers_url":"https://api.github.com/repos/osmlab/atlas/stargazers","contributors_url":"https://api.github.com/repos/osmlab/atlas/contributors","subscribers_url":"https://api.github.com/repos/osmlab/atlas/subscribers","subscription_url":"https://api.github.com/repos/osmlab/atlas/subscription","commits_url":"https://api.github.com/repos/osmlab/atlas/commits{/sha}","git_commits_url":"https://api.github.com/repos/osmlab/atlas/git/commits{/sha}","comments_url":"https://api.github.com/repos/osmlab/atlas/comments{/number}","issue_comment_url":"https://api.github.com/repos/osmlab/atlas/issues/comments{/number}","contents_url":"https://api.github.com/repos/osmlab/atlas/contents/{+path}","compare_url":"https://api.github.com/repos/osmlab/atlas/compare/{base}...{head}","merges_url":"https://api.github.com/repos/osmlab/atlas/merges","archive_url":"https://api.github.com/repos/osmlab/atlas/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/osmlab/atlas/downloads","issues_url":"https://api.github.com/repos/osmlab/atlas/issues{/number}","pulls_url":"https://api.github.com/repos/osmlab/atlas/pulls{/number}","milestones_url":"https://api.github.com/repos/osmlab/atlas/milestones{/number}","notifications_url":"https://api.github.com/repos/osmlab/atlas/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/osmlab/atlas/labels{/name}","releases_url":"https://api.github.com/repos/osmlab/atlas/releases{/id}","deployments_url":"https://api.github.com/repos/osmlab/atlas/deployments","created_at":"2017-08-08T17:14:27Z","updated_at":"2018-02-26T23:34:34Z","pushed_at":"2018-03-01T07:23:52Z","git_url":"git://github.com/osmlab/atlas.git","ssh_url":"git@github.com:osmlab/atlas.git","clone_url":"https://github.com/osmlab/atlas.git","svn_url":"https://github.com/osmlab/atlas","homepage":null,"size":51275,"stargazers_count":52,"watchers_count":52,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":20,"mirror_url":null,"archived":false,"open_issues_count":9,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":20,"open_issues":9,"watchers":52,"default_branch":"dev"}},"_links":{"self":{"href":"https://api.github.com/repos/osmlab/atlas/pulls/90"},"html":{"href":"https://github.com/osmlab/atlas/pull/90"},"issue":{"href":"https://api.github.com/repos/osmlab/atlas/issues/90"},"comments":{"href":"https://api.github.com/repos/osmlab/atlas/issues/90/comments"},"review_comments":{"href":"https://api.github.com/repos/osmlab/atlas/pulls/90/comments"},"review_comment":{"href":"https://api.github.com/repos/osmlab/atlas/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/osmlab/atlas/pulls/90/commits"},"statuses":{"href":"https://api.github.com/repos/osmlab/atlas/statuses/2f20dd187575a9e49e47167665b98955502cbfad"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"MikeGost"}}