{"action":"created","comment":{"url":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/comments/150319499","pull_request_review_id":75859183,"id":150319499,"diff_hunk":"@@ -0,0 +1,307 @@\n+#include <mbgl/text/placement.hpp>\n+#include <mbgl/renderer/render_layer.hpp>\n+#include <mbgl/renderer/layers/render_symbol_layer.hpp>\n+#include <mbgl/renderer/render_tile.hpp>\n+#include <mbgl/tile/geometry_tile.cpp>\n+#include <mbgl/renderer/buckets/symbol_bucket.hpp>\n+#include <mbgl/renderer/bucket.hpp>\n+\n+namespace mbgl {\n+\n+OpacityState::OpacityState(bool placed_) : opacity(0), placed(placed_) {}\n+\n+OpacityState::OpacityState(const OpacityState& prevState, float increment, bool placed_) :\n+    opacity(std::fmax(0, std::fmin(1, prevState.opacity + (prevState.placed ? increment : -increment)))),\n+    placed(placed_) {}\n+\n+bool OpacityState::isHidden() const {\n+    return opacity == 0 && !placed;\n+}\n+\n+JointOpacityState::JointOpacityState(bool placedIcon, bool placedText) :\n+    icon(OpacityState(placedIcon)),\n+    text(OpacityState(placedText)) {}\n+\n+JointOpacityState::JointOpacityState(const JointOpacityState& prevOpacityState, float increment, bool placedIcon, bool placedText) :\n+    icon(OpacityState(prevOpacityState.icon, increment, placedIcon)),\n+    text(OpacityState(prevOpacityState.text, increment, placedText)) {}\n+\n+bool JointOpacityState::isHidden() const {\n+    return icon.isHidden() && text.isHidden();\n+}\n+\n+Placement::Placement(const TransformState& state_, MapMode mapMode_)\n+    : collisionIndex(state_)\n+    , state(state_)\n+    , mapMode(mapMode_)\n+    , recentUntil(TimePoint::min())\n+{}\n+\n+void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatrix, bool showCollisionBoxes) {\n+\n+    std::unordered_set<uint32_t> seenCrossTileIDs;\n+\n+    for (RenderTile& renderTile : symbolLayer.renderTiles) {\n+\n+        if (!renderTile.tile.isRenderable()) {\n+            continue;\n+        }\n+\n+        auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl);\n+        assert(dynamic_cast<SymbolBucket*>(bucket));\n+        SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);\n+\n+        auto& layout = symbolBucket.layout;\n+\n+        const float pixelsToTileUnits = renderTile.id.pixelsToTileUnits(1, state.getZoom());\n+\n+        const float scale = std::pow(2, state.getZoom() - renderTile.tile.id.overscaledZ);\n+        const float textPixelRatio = util::EXTENT / (util::tileSize * renderTile.tile.id.overscaleFactor());\n+\n+        mat4 posMatrix;\n+        state.matrixFor(posMatrix, renderTile.id);\n+        matrix::multiply(posMatrix, projMatrix, posMatrix);\n+\n+        mat4 textLabelPlaneMatrix = getLabelPlaneMatrix(posMatrix,\n+                layout.get<TextPitchAlignment>() == style::AlignmentType::Map,\n+                layout.get<TextRotationAlignment>() == style::AlignmentType::Map,\n+                state,\n+                pixelsToTileUnits);\n+\n+        mat4 iconLabelPlaneMatrix = getLabelPlaneMatrix(posMatrix,\n+                layout.get<IconPitchAlignment>() == style::AlignmentType::Map,\n+                layout.get<IconRotationAlignment>() == style::AlignmentType::Map,\n+                state,\n+                pixelsToTileUnits);\n+\n+        placeLayerBucket(symbolBucket, posMatrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, textPixelRatio, showCollisionBoxes, seenCrossTileIDs);\n+    }\n+}\n+\n+void Placement::placeLayerBucket(\n+        SymbolBucket& bucket,\n+        const mat4& posMatrix,\n+        const mat4& textLabelPlaneMatrix,\n+        const mat4& iconLabelPlaneMatrix,\n+        const float scale,\n+        const float textPixelRatio,\n+        const bool showCollisionBoxes,\n+        std::unordered_set<uint32_t>& seenCrossTileIDs) {\n+\n+    auto partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom());\n+    auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom());\n+\n+    const bool iconWithoutText = !bucket.hasTextData() || bucket.layout.get<TextOptional>();\n+    const bool textWithoutIcon = !bucket.hasIconData() || bucket.layout.get<IconOptional>();\n+\n+    for (auto& symbolInstance : bucket.symbolInstances) {\n+\n+        if (seenCrossTileIDs.count(symbolInstance.crossTileID) == 0) {\n+            bool placeText = false;\n+            bool placeIcon = false;\n+\n+            if (symbolInstance.placedTextIndex) {\n+                PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*symbolInstance.placedTextIndex);\n+                const float fontSize = evaluateSizeForFeature(partiallyEvaluatedTextSize, placedSymbol);","path":"src/mbgl/text/placement.cpp","position":105,"original_position":105,"commit_id":"ab03d5b4742d4b46d7813eb28595bbab9249bb3f","original_commit_id":"9adb7351d688b875e5e6d3fe0f39a67bc2eb99b2","user":{"login":"ChrisLoer","id":375121,"avatar_url":"https://avatars2.githubusercontent.com/u/375121?v=4","gravatar_id":"","url":"https://api.github.com/users/ChrisLoer","html_url":"https://github.com/ChrisLoer","followers_url":"https://api.github.com/users/ChrisLoer/followers","following_url":"https://api.github.com/users/ChrisLoer/following{/other_user}","gists_url":"https://api.github.com/users/ChrisLoer/gists{/gist_id}","starred_url":"https://api.github.com/users/ChrisLoer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ChrisLoer/subscriptions","organizations_url":"https://api.github.com/users/ChrisLoer/orgs","repos_url":"https://api.github.com/users/ChrisLoer/repos","events_url":"https://api.github.com/users/ChrisLoer/events{/privacy}","received_events_url":"https://api.github.com/users/ChrisLoer/received_events","type":"User","site_admin":false},"body":"🤷‍♂️ I'm not sure. It seems like a minor fidelity win in exchange for a minor performance cost.","created_at":"2017-11-10T19:31:26Z","updated_at":"2017-11-10T19:31:26Z","html_url":"https://github.com/mapbox/mapbox-gl-native/pull/10436#discussion_r150319499","pull_request_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/10436","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/comments/150319499"},"html":{"href":"https://github.com/mapbox/mapbox-gl-native/pull/10436#discussion_r150319499"},"pull_request":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/10436"}},"in_reply_to_id":150308584},"pull_request":{"url":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/10436","id":151791275,"html_url":"https://github.com/mapbox/mapbox-gl-native/pull/10436","diff_url":"https://github.com/mapbox/mapbox-gl-native/pull/10436.diff","patch_url":"https://github.com/mapbox/mapbox-gl-native/pull/10436.patch","issue_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues/10436","number":10436,"state":"open","locked":false,"title":"Global/Viewport Collision Detection","user":{"login":"ChrisLoer","id":375121,"avatar_url":"https://avatars2.githubusercontent.com/u/375121?v=4","gravatar_id":"","url":"https://api.github.com/users/ChrisLoer","html_url":"https://github.com/ChrisLoer","followers_url":"https://api.github.com/users/ChrisLoer/followers","following_url":"https://api.github.com/users/ChrisLoer/following{/other_user}","gists_url":"https://api.github.com/users/ChrisLoer/gists{/gist_id}","starred_url":"https://api.github.com/users/ChrisLoer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ChrisLoer/subscriptions","organizations_url":"https://api.github.com/users/ChrisLoer/orgs","repos_url":"https://api.github.com/users/ChrisLoer/repos","events_url":"https://api.github.com/users/ChrisLoer/events{/privacy}","received_events_url":"https://api.github.com/users/ChrisLoer/received_events","type":"User","site_admin":false},"body":"This is the native port of https://github.com/mapbox/mapbox-gl-js/pull/5150: it switches us to doing collision detection globally, in a grid based on viewport coordinates instead of tile coordinates. This allows us to solve many problems, but mainly boils down to (1) more accurate collision detection, and thus denser/more-stable labeling, and (2) cross-source collision detection.\r\n\r\nThis is a squashed/rebased version of WIP PR #10103.\r\n\r\n## Differences from JS\r\nThe core collision detection algorithm is a very close port of the JS code, and the shader code is fully shared. The biggest differences are in the `CrossTileSymbolIndex` code and the render thread placement logic. These differences were partly driven by the requirements of native, but mostly by us trying to make improvements based on hindsight.\r\n\r\n- `CrossTileSymbolIndex` uses the same logic to find duplicates, but instead of trying to update opacity information directly, it now just tags duplicates with a shared `crossTileID`. The foreground placement code then runs placement and updates opacities using those IDs to handle duplicates. This approach makes it easier to separate opacity updates from the actual placement logic, which makes it so that we can add tiles to the render tree w/ transparent labels without blocking waiting for a full placement to complete.\r\n- All placements are \"full placements\" in this PR -- we don't have an \"interruptible\" concept as in JS. @ansis made a branch, `start-collision-async` that successfully runs placement on a background thread, but so far it doesn't look like a significant performance win (less foreground CPU, more total CPU, same frame-rate), so we haven't merged it.\r\n\r\n## TODO\r\n\r\n- [ ] Implement `MapMode::Tile` to support single-tile `api-gl` use case\r\n- [x] Diagnose two remaining intermittent test failures on CI (`viewport-text-depthmodetest` and `viewport-overzoomed-single-glyph`)\r\n\r\n## Performance\r\n`mbgl-benchmark` looks pretty similar, with the exception of `API_renderStill_reuse_map`, which takes about twice as long (this makes sense because we do full placement for each still frame, wheres before we could re-use the already-completed tile placements).\r\n   - [ ] Store results somewhere public?\r\n\r\nI've done the bulk of performance testing using the iOS bench app running on my iPhone 5s and an ancient iPad. I've modified the bench app to include two challenging scenes:\r\n\r\n - A ten second pitched rotation animation looking at LA city streets\r\n - A ten second animation zooming into LA city streets\r\n\r\nI added printf-style timing logs to the render code to collect detailed frame timing information for analysis in a spreadsheet.\r\n   - [ ] Store results somewhere public?\r\n\r\nBoth `master` and `viewport-collision` clocked in at 60 FPS for the zoom animation. Delving into the individual frame timing data, I could see that there _were_ frames in which the cost of placement drove the frame time over 16ms -- but most of the skipped frames were driven by time spent in the render pass, so that overall the two branches looked pretty similar.\r\n\r\n`viewport-collision` was far superior to `master` in the pitched rotation animation, coming in at 58-59 FPS vs 41-43 FPS. Again, although placement showed up as a significant cost in some frames, render time was far more important. My guess is that frequently re-uploading static symbol buffers is responsible for trashing the performance on `master` (@mourner?).\r\n\r\n/cc @ansis @jfirebaugh @kkaefer @anandthakker @mollymerp ","created_at":"2017-11-09T23:33:15Z","updated_at":"2017-11-10T19:31:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cbb81a61a5e1ae5ac96d74a008f95b00bb572373","assignee":null,"assignees":[],"requested_reviewers":[{"login":"jfirebaugh","id":98601,"avatar_url":"https://avatars2.githubusercontent.com/u/98601?v=4","gravatar_id":"","url":"https://api.github.com/users/jfirebaugh","html_url":"https://github.com/jfirebaugh","followers_url":"https://api.github.com/users/jfirebaugh/followers","following_url":"https://api.github.com/users/jfirebaugh/following{/other_user}","gists_url":"https://api.github.com/users/jfirebaugh/gists{/gist_id}","starred_url":"https://api.github.com/users/jfirebaugh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jfirebaugh/subscriptions","organizations_url":"https://api.github.com/users/jfirebaugh/orgs","repos_url":"https://api.github.com/users/jfirebaugh/repos","events_url":"https://api.github.com/users/jfirebaugh/events{/privacy}","received_events_url":"https://api.github.com/users/jfirebaugh/received_events","type":"User","site_admin":false},{"login":"ansis","id":1421652,"avatar_url":"https://avatars0.githubusercontent.com/u/1421652?v=4","gravatar_id":"","url":"https://api.github.com/users/ansis","html_url":"https://github.com/ansis","followers_url":"https://api.github.com/users/ansis/followers","following_url":"https://api.github.com/users/ansis/following{/other_user}","gists_url":"https://api.github.com/users/ansis/gists{/gist_id}","starred_url":"https://api.github.com/users/ansis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ansis/subscriptions","organizations_url":"https://api.github.com/users/ansis/orgs","repos_url":"https://api.github.com/users/ansis/repos","events_url":"https://api.github.com/users/ansis/events{/privacy}","received_events_url":"https://api.github.com/users/ansis/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/10436/commits","review_comments_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/10436/comments","review_comment_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues/10436/comments","statuses_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/statuses/ab03d5b4742d4b46d7813eb28595bbab9249bb3f","head":{"label":"mapbox:viewport-collision","ref":"viewport-collision","sha":"ab03d5b4742d4b46d7813eb28595bbab9249bb3f","user":{"login":"mapbox","id":600935,"avatar_url":"https://avatars1.githubusercontent.com/u/600935?v=4","gravatar_id":"","url":"https://api.github.com/users/mapbox","html_url":"https://github.com/mapbox","followers_url":"https://api.github.com/users/mapbox/followers","following_url":"https://api.github.com/users/mapbox/following{/other_user}","gists_url":"https://api.github.com/users/mapbox/gists{/gist_id}","starred_url":"https://api.github.com/users/mapbox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mapbox/subscriptions","organizations_url":"https://api.github.com/users/mapbox/orgs","repos_url":"https://api.github.com/users/mapbox/repos","events_url":"https://api.github.com/users/mapbox/events{/privacy}","received_events_url":"https://api.github.com/users/mapbox/received_events","type":"Organization","site_admin":false},"repo":{"id":16286131,"name":"mapbox-gl-native","full_name":"mapbox/mapbox-gl-native","owner":{"login":"mapbox","id":600935,"avatar_url":"https://avatars1.githubusercontent.com/u/600935?v=4","gravatar_id":"","url":"https://api.github.com/users/mapbox","html_url":"https://github.com/mapbox","followers_url":"https://api.github.com/users/mapbox/followers","following_url":"https://api.github.com/users/mapbox/following{/other_user}","gists_url":"https://api.github.com/users/mapbox/gists{/gist_id}","starred_url":"https://api.github.com/users/mapbox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mapbox/subscriptions","organizations_url":"https://api.github.com/users/mapbox/orgs","repos_url":"https://api.github.com/users/mapbox/repos","events_url":"https://api.github.com/users/mapbox/events{/privacy}","received_events_url":"https://api.github.com/users/mapbox/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mapbox/mapbox-gl-native","description":"Interactive, thoroughly customizable maps in native Android, iOS, macOS, Node.js, and Qt applications, powered by vector tiles and OpenGL","fork":false,"url":"https://api.github.com/repos/mapbox/mapbox-gl-native","forks_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/forks","keys_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/teams","hooks_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/hooks","issue_events_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues/events{/number}","events_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/events","assignees_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/assignees{/user}","branches_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/branches{/branch}","tags_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/tags","blobs_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/refs{/sha}","trees_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/statuses/{sha}","languages_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/languages","stargazers_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/stargazers","contributors_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/contributors","subscribers_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/subscribers","subscription_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/subscription","commits_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/commits{/sha}","git_commits_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/commits{/sha}","comments_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/comments{/number}","issue_comment_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues/comments{/number}","contents_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/contents/{+path}","compare_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/merges","archive_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/downloads","issues_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues{/number}","pulls_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls{/number}","milestones_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/milestones{/number}","notifications_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/labels{/name}","releases_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/releases{/id}","deployments_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/deployments","created_at":"2014-01-27T17:14:48Z","updated_at":"2017-11-09T15:26:49Z","pushed_at":"2017-11-10T19:25:46Z","git_url":"git://github.com/mapbox/mapbox-gl-native.git","ssh_url":"git@github.com:mapbox/mapbox-gl-native.git","clone_url":"https://github.com/mapbox/mapbox-gl-native.git","svn_url":"https://github.com/mapbox/mapbox-gl-native","homepage":"https://mapbox.com/mobile","size":179895,"stargazers_count":2224,"watchers_count":2224,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":692,"mirror_url":null,"archived":false,"open_issues_count":627,"forks":692,"open_issues":627,"watchers":2224,"default_branch":"master"}},"base":{"label":"mapbox:master","ref":"master","sha":"6b5afaab7611cc59c86f749fd9130edb512b4945","user":{"login":"mapbox","id":600935,"avatar_url":"https://avatars1.githubusercontent.com/u/600935?v=4","gravatar_id":"","url":"https://api.github.com/users/mapbox","html_url":"https://github.com/mapbox","followers_url":"https://api.github.com/users/mapbox/followers","following_url":"https://api.github.com/users/mapbox/following{/other_user}","gists_url":"https://api.github.com/users/mapbox/gists{/gist_id}","starred_url":"https://api.github.com/users/mapbox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mapbox/subscriptions","organizations_url":"https://api.github.com/users/mapbox/orgs","repos_url":"https://api.github.com/users/mapbox/repos","events_url":"https://api.github.com/users/mapbox/events{/privacy}","received_events_url":"https://api.github.com/users/mapbox/received_events","type":"Organization","site_admin":false},"repo":{"id":16286131,"name":"mapbox-gl-native","full_name":"mapbox/mapbox-gl-native","owner":{"login":"mapbox","id":600935,"avatar_url":"https://avatars1.githubusercontent.com/u/600935?v=4","gravatar_id":"","url":"https://api.github.com/users/mapbox","html_url":"https://github.com/mapbox","followers_url":"https://api.github.com/users/mapbox/followers","following_url":"https://api.github.com/users/mapbox/following{/other_user}","gists_url":"https://api.github.com/users/mapbox/gists{/gist_id}","starred_url":"https://api.github.com/users/mapbox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mapbox/subscriptions","organizations_url":"https://api.github.com/users/mapbox/orgs","repos_url":"https://api.github.com/users/mapbox/repos","events_url":"https://api.github.com/users/mapbox/events{/privacy}","received_events_url":"https://api.github.com/users/mapbox/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mapbox/mapbox-gl-native","description":"Interactive, thoroughly customizable maps in native Android, iOS, macOS, Node.js, and Qt applications, powered by vector tiles and OpenGL","fork":false,"url":"https://api.github.com/repos/mapbox/mapbox-gl-native","forks_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/forks","keys_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/teams","hooks_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/hooks","issue_events_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues/events{/number}","events_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/events","assignees_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/assignees{/user}","branches_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/branches{/branch}","tags_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/tags","blobs_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/refs{/sha}","trees_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/statuses/{sha}","languages_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/languages","stargazers_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/stargazers","contributors_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/contributors","subscribers_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/subscribers","subscription_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/subscription","commits_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/commits{/sha}","git_commits_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/git/commits{/sha}","comments_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/comments{/number}","issue_comment_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues/comments{/number}","contents_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/contents/{+path}","compare_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/merges","archive_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/downloads","issues_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues{/number}","pulls_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls{/number}","milestones_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/milestones{/number}","notifications_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/labels{/name}","releases_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/releases{/id}","deployments_url":"https://api.github.com/repos/mapbox/mapbox-gl-native/deployments","created_at":"2014-01-27T17:14:48Z","updated_at":"2017-11-09T15:26:49Z","pushed_at":"2017-11-10T19:25:46Z","git_url":"git://github.com/mapbox/mapbox-gl-native.git","ssh_url":"git@github.com:mapbox/mapbox-gl-native.git","clone_url":"https://github.com/mapbox/mapbox-gl-native.git","svn_url":"https://github.com/mapbox/mapbox-gl-native","homepage":"https://mapbox.com/mobile","size":179895,"stargazers_count":2224,"watchers_count":2224,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":692,"mirror_url":null,"archived":false,"open_issues_count":627,"forks":692,"open_issues":627,"watchers":2224,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/10436"},"html":{"href":"https://github.com/mapbox/mapbox-gl-native/pull/10436"},"issue":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues/10436"},"comments":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/issues/10436/comments"},"review_comments":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/10436/comments"},"review_comment":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/pulls/10436/commits"},"statuses":{"href":"https://api.github.com/repos/mapbox/mapbox-gl-native/statuses/ab03d5b4742d4b46d7813eb28595bbab9249bb3f"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"ChrisLoer"}}