Update to iD v2.0.0
authorBryan Housel <bryan@mapbox.com>
Tue, 15 Nov 2016 15:16:34 +0000 (10:16 -0500)
committerBryan Housel <bryan@mapbox.com>
Tue, 15 Nov 2016 15:16:34 +0000 (10:16 -0500)
90 files changed:
Vendorfile
app/assets/javascripts/id.js
app/views/site/_id.html.erb
app/views/site/id.html.erb
vendor/assets/iD/iD.css.erb
vendor/assets/iD/iD.js
vendor/assets/iD/iD/img/iD-sprite.svg
vendor/assets/iD/iD/img/maki-sprite.svg
vendor/assets/iD/iD/locales/af.json
vendor/assets/iD/iD/locales/ar-AA.json
vendor/assets/iD/iD/locales/ar.json
vendor/assets/iD/iD/locales/ast.json
vendor/assets/iD/iD/locales/bg-BG.json
vendor/assets/iD/iD/locales/bn.json
vendor/assets/iD/iD/locales/bs.json
vendor/assets/iD/iD/locales/ca.json
vendor/assets/iD/iD/locales/cs.json
vendor/assets/iD/iD/locales/da.json
vendor/assets/iD/iD/locales/de.json
vendor/assets/iD/iD/locales/el.json
vendor/assets/iD/iD/locales/en-GB.json
vendor/assets/iD/iD/locales/en.json
vendor/assets/iD/iD/locales/eo.json
vendor/assets/iD/iD/locales/es.json
vendor/assets/iD/iD/locales/et.json
vendor/assets/iD/iD/locales/fa.json
vendor/assets/iD/iD/locales/fi.json
vendor/assets/iD/iD/locales/fr.json
vendor/assets/iD/iD/locales/gl.json
vendor/assets/iD/iD/locales/gu.json
vendor/assets/iD/iD/locales/hi.json
vendor/assets/iD/iD/locales/hr.json
vendor/assets/iD/iD/locales/hu.json
vendor/assets/iD/iD/locales/hy.json
vendor/assets/iD/iD/locales/id.json
vendor/assets/iD/iD/locales/is.json
vendor/assets/iD/iD/locales/it.json
vendor/assets/iD/iD/locales/ja.json
vendor/assets/iD/iD/locales/kn.json
vendor/assets/iD/iD/locales/ko.json
vendor/assets/iD/iD/locales/ku.json [new file with mode: 0644]
vendor/assets/iD/iD/locales/lij.json
vendor/assets/iD/iD/locales/lt.json
vendor/assets/iD/iD/locales/lv.json
vendor/assets/iD/iD/locales/ml.json
vendor/assets/iD/iD/locales/nl.json
vendor/assets/iD/iD/locales/no.json
vendor/assets/iD/iD/locales/pl.json
vendor/assets/iD/iD/locales/pt-BR.json
vendor/assets/iD/iD/locales/pt.json
vendor/assets/iD/iD/locales/ro.json
vendor/assets/iD/iD/locales/ru.json
vendor/assets/iD/iD/locales/sc.json
vendor/assets/iD/iD/locales/si.json
vendor/assets/iD/iD/locales/sk.json
vendor/assets/iD/iD/locales/sl.json
vendor/assets/iD/iD/locales/sq.json
vendor/assets/iD/iD/locales/sr.json
vendor/assets/iD/iD/locales/sv.json
vendor/assets/iD/iD/locales/ta.json
vendor/assets/iD/iD/locales/te.json
vendor/assets/iD/iD/locales/th.json
vendor/assets/iD/iD/locales/tl.json
vendor/assets/iD/iD/locales/tr.json
vendor/assets/iD/iD/locales/uk.json
vendor/assets/iD/iD/locales/vi.json
vendor/assets/iD/iD/locales/yue.json
vendor/assets/iD/iD/locales/zh-CN.json
vendor/assets/iD/iD/locales/zh-HK.json
vendor/assets/iD/iD/locales/zh-TW.json
vendor/assets/iD/iD/locales/zh.json
vendor/assets/iD/iD/mapillary-js/arrow-up-white.svg [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/cover-logo.svg [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/mapillary.js [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/mapillary.js.map [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/mapillary.min.css [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/mapillary.min.js [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/pano-indicator.svg [new file with mode: 0755]
vendor/assets/iD/iD/mapillary-js/pano.svg [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/pointer-wheat.svg [new file with mode: 0755]
vendor/assets/iD/iD/mapillary-js/pointer-white.svg [new file with mode: 0755]
vendor/assets/iD/iD/mapillary-js/spinner.svg [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/stepper-left.svg [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/stepper-play.svg [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/stepper-right.svg [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/stepper-stop.svg [new file with mode: 0644]
vendor/assets/iD/iD/mapillary-js/turn-around.svg [new file with mode: 0755]
vendor/assets/iD/iD/mapillary-js/turn.svg [new file with mode: 0755]
vendor/assets/iD/imagery.js [deleted file]
vendor/assets/iD/presets.js [deleted file]

index 9a951d5..4fbefcf 100644 (file)
@@ -50,6 +50,7 @@ folder 'vendor/assets' do
       folder 'iD/img', 'dist/img'
       folder 'iD/locales', 'dist/locales'
       folder 'iD/traffico', 'dist/traffico'
+      folder 'iD/mapillary-js', 'dist/mapillary-js'
 
       file 'iD.css.erb', 'dist/iD.css' do |path|
         rewrite(path) do |content|
@@ -66,8 +67,6 @@ folder 'vendor/assets' do
       File.delete('vendor/assets/iD/iD/traffico/stylesheets/traffico.css')
 
       file 'iD.js', 'dist/iD.js'
-      file 'presets.js', 'dist/presets.js'
-      file 'imagery.js', 'dist/imagery.js'
     end
   end
 
index 86d2df7..185717b 100644 (file)
@@ -1,3 +1 @@
 //= require iD
-//= require presets
-//= require imagery
index ed36385..374cdbb 100644 (file)
       params.id = mapParams.object.type[0] + mapParams.object.id;
       mapParams = OSM.parseHash(location.hash);
       if (mapParams.center) {
-        params.map = mapParams.zoom + '/' + mapParams.center.lng + '/' + mapParams.center.lat;
+        params.map = mapParams.zoom + '/' + mapParams.center.lat + '/' + mapParams.center.lon;
       }
     } else {
 <% if @lat && @lon -%>
-      params.map = '16/<%= @lon %>/<%= @lat %>';
+      params.map = '16/<%= @lat %>/<%= @lng %>';
 <% else -%>
-      params.map = (mapParams.zoom || 17) + '/' + mapParams.lon + '/' + mapParams.lat;
+      params.map = (mapParams.zoom || 17) + '/' + mapParams.lat + '/' + mapParams.lon;
 <% end -%>
     }
 
index ba8f7da..d1ac6b0 100644 (file)
 <body>
 <div id='id-container'></div>
 <script>
-  if (typeof iD == 'undefined' || !iD.detect().support) {
+  if (typeof iD == 'undefined' || !iD.Detect().support) {
     document.getElementById('id-container').innerHTML = 'This editor is supported ' +
-      'in Firefox, Chrome, Safari, Opera, and Internet Explorer 11 and above. ' +
+      'in Firefox, Chrome, Safari, Opera, Edge, and Internet Explorer 11. ' +
       'Please upgrade your browser or use Potlatch 2 to edit the map.';
     document.getElementById('id-container').className = 'unsupported';
   } else {
     <% locale = ID::LOCALES.preferred(preferred_languages).to_s %>
 
-    var id = iD()
-      .presets(iD.data.presets)
-      .imagery(iD.data.imagery)
-      .taginfo(iD.services.taginfo())
+    var id = iD.Context()
       .embed(true)
       .assetPath("iD/")
       .assetMap(<%= assets("iD").to_json.html_safe %>)
       .locale("<%= locale %>", "<%= asset_path("iD/locales/#{locale}.json") %>")
       .preauth({
         <% token = @user.access_token(ID_KEY) %>
-        url: "<%= request.protocol + request.host_with_port %>",
+        urlroot: "<%= request.protocol + request.host_with_port %>",
         oauth_consumer_key: "<%= token.client_application.key %>",
         oauth_secret: "<%= token.client_application.secret %>",
         oauth_token: "<%= token.token %>",
@@ -64,8 +61,7 @@
       }, 0);
     });
 
-    d3.select('#id-container')
-      .call(id.ui());
+    id.ui()(document.getElementById("id-container"));
   }
 </script>
 </body>
index f0a1441..2f22d24 100644 (file)
@@ -200,6 +200,7 @@ g.point .shadow {
     stroke-opacity: 0;
 }
 
+g.point.related:not(.selected) .shadow,
 g.point.hover:not(.selected) .shadow {
     stroke-opacity: 0.5;
 }
@@ -267,7 +268,9 @@ g.vertex.vertex-hover {
     display: block;
 }
 
+g.vertex.related:not(.selected) .shadow,
 g.vertex.hover:not(.selected) .shadow,
+g.midpoint.related:not(.selected) .shadow,
 g.midpoint.hover:not(.selected) .shadow {
     fill-opacity: 0.5;
 }
@@ -307,6 +310,7 @@ path.shadow {
     stroke-opacity: 0;
 }
 
+path.shadow.related:not(.selected),
 path.shadow.hover:not(.selected) {
     stroke-opacity: 0.4;
 }
@@ -571,6 +575,18 @@ path.stroke.tag-landuse-farmland {
     background-color: rgba(140, 208, 95, 0.2);
 }
 
+path.stroke.tag-landuse-farmyard {
+    stroke: rgb(245, 220, 186);
+}
+path.fill.tag-landuse-farmyard {
+    stroke: rgba(245, 220, 186, 0.3);
+    fill: rgba(245, 220, 186, 0.3);
+}
+.preset-icon-fill-area.tag-landuse-farmyard {
+    border-color: rgb(245, 220, 186);
+    background: rgba(245, 220, 186, 0.3);
+}
+
 .pattern-color-cemetery,
 .pattern-color-orchard {
     fill: rgba(140, 208, 95, 0.2);
@@ -1473,24 +1489,21 @@ text.pointlabel-halo,
 text.arealabel,
 text.linelabel,
 text.pointlabel {
+    dominant-baseline: middle;
+    text-anchor: middle;
     font-size: 12px;
     font-weight: bold;
     fill: #333;
-    text-anchor: middle;
     pointer-events: none;
     -webkit-transition: opacity 100ms linear;
     transition: opacity 100ms linear;
     -moz-transition: opacity 100ms linear;
 }
 
+/* Opera doesn't support dominant-baseline. See #715 */
+/* Safari 10 seems to have regressed too */
 .linelabel-halo .textpath,
 .linelabel .textpath {
-  dominant-baseline: middle;
-}
-
-/* Opera doesn't support dominant-baseline. See #715 */
-.opera .linelabel-halo .textpath,
-.opera .linelabel .textpath {
   baseline-shift: -33%;
   dominant-baseline: auto;
 }
@@ -1507,7 +1520,7 @@ text.proximate {
 }
 
 text.point {
-  font-size: 10px;
+    font-size: 10px;
 }
 
 /* Turns */
@@ -1695,7 +1708,7 @@ text.gpx {
     pointer-events: none;
 }
 
-.layer-mapillary-signs .icon-sign body {
+.layer-mapillary-signs .icon-sign .icon-sign-body {
     min-width: 20px;
     height: 28px;
     width: 28px;
@@ -1704,14 +1717,15 @@ text.gpx {
     cursor: pointer; /* Opera */
     cursor: url(<%= asset_path("iD/img/cursor-select-mapillary.png") %>) 6 1, pointer; /* FF */
     z-index: 70;
+    overflow: visible;
 }
 
-.layer-mapillary-signs .icon-sign:hover body {
+.layer-mapillary-signs .icon-sign:hover .icon-sign-body {
     border: 2px solid rgba(255,198,0,0.8);
     z-index: 80;
  }
 
-.layer-mapillary-signs .icon-sign.selected body {
+.layer-mapillary-signs .icon-sign.selected .icon-sign-body {
     border: 2px solid rgba(255,0,0,0.8);
     z-index: 80;
  }
@@ -1719,7 +1733,6 @@ text.gpx {
 .layer-mapillary-signs .icon-sign .t {
     font-size: 28px;
     z-index: 70;
-    position: absolute;
 }
 
 .layer-mapillary-signs .icon-sign:hover .t,
@@ -1766,6 +1779,7 @@ text.gpx {
     stroke-width: 8;
 }
 
+.fill-wireframe path.shadow.related:not(.selected),
 .fill-wireframe path.shadow.hover:not(.selected) {
     stroke-opacity: 0.4;
 }
@@ -2510,9 +2524,24 @@ button.save.has-count .count::before {
     border-radius: 0;
 }
 
+.feature-list-item {
+    background-color: white;
+    font-weight: bold;
+    height: 40px;
+    line-height: 20px;
+}
+
+.feature-list-item:hover {
+    background-color: #ececec;
+}
+
+.feature-list-item button {
+    background: transparent;
+}
+
 .feature-list-item .label {
     text-align: left;
-    padding: 5px 10px;
+    padding: 10px 10px;
     white-space: nowrap;
     text-overflow: ellipsis;
     overflow: hidden;
@@ -2523,8 +2552,13 @@ button.save.has-count .count::before {
     opacity: .5;
 }
 
-.feature-list-item:hover .label {
-    background-color: #ececec;
+.feature-list-item .close {
+    float: right;
+    padding: 10px;
+}
+
+.feature-list-item .close .icon {
+    opacity: 1;
 }
 
 .feature-list-item .entity-type {
@@ -2931,8 +2965,10 @@ button.save.has-count .count::before {
     font-weight: bold;
 }
 
-.more-fields label { padding: 5px 10px 5px 0; }
-.more-fields input { width: 50%;}
+.more-fields input {
+    margin-left: 10px;
+    width: 50%;
+}
 
 /* preset form access */
 
@@ -4367,12 +4403,20 @@ img.tile-removing {
     text-align: right;
     width: 100%;
     padding: 0px 10px;
+    color: #eee;
 }
 
 .api-status.offline,
 .api-status.readonly,
 .api-status.error {
-    background: red;
+    background: #a22;
+}
+
+.api-status-login {
+    color: #aaf;
+}
+.api-status-login:hover {
+    color: #ccf;
 }
 
 /* Modals
@@ -5011,11 +5055,12 @@ img.tile-removing {
     background: #8cd05f;
 }
 
-.intro-nav-wrap button.step .icon {
+.intro-nav-wrap button.step .status {
+    margin-left: 3px;
     display: none;
 }
 
-.intro-nav-wrap button.step.finished .icon {
+.intro-nav-wrap button.step.finished .status {
     display: inline-block;
 }
 
@@ -5083,8 +5128,6 @@ img.tile-removing {
     margin: auto;
 }
 
-/* Mapillary
-------------------------------------------------------- */
 .mapillary-wrap {
     position: absolute;
     bottom: 30px;
@@ -5098,15 +5141,6 @@ img.tile-removing {
     visibility: hidden;
 }
 
-.mapillary-wrap .uil-ripple-css {
-  top: -9px;
-  left: -15px;
-}
-
-.mapillary-wrap .uil-ripple-css div {
-    top: 38px;
-}
-
 .mapillary-wrap button.thumb-hide {
     border-radius: 0;
     padding: 5px;
@@ -5117,9 +5151,334 @@ img.tile-removing {
 }
 
 .mly-wrapper {
-  visibility: hidden;
+    visibility: hidden;
+    width: 100%;
+    height: 100%;
 }
 
 .mly-wrapper.active {
-  visibility: visible;
+    visibility: visible;
+}
+
+/* Right-to-left localization settings */
+
+[dir='rtl'] #sidebar {
+  float: right;
+}
+
+[dir='rtl'] #sidebar .search-header .icon {
+  left: auto;
+  right: 10px;
+}
+
+/* header */
+[dir='rtl'] .header h3 {
+  text-align: right;
+  padding: 20px 40px 20px 20px;
+}
+
+[dir='rtl'] .entity-editor-pane .header button.preset-choose {
+  left: auto;
+  right: 0;
+}
+
+[dir='rtl'] .entity-editor-pane .header button.preset-close, [dir='rtl'] .preset-list-pane .header button.preset-choose {
+  left: 0;
+  right: auto;
+}
+
+[dir='rtl'] .preset-icon-fill-area {
+  left: auto;
+  right: 10px;
+}
+
+[dir='rtl'] .map-data-control .layer-list button, [dir='rtl'] .background-control .layer-list button {
+  float: left;
+  border-left: none;
+  border-right: 1px solid #CCC;
+}
+
+[dir='rtl'] .map-data-control .layer-list button:first-of-type, [dir='rtl'] .background-control .layer-list button:first-of-type {
+  border-radius: 3px 0 0 3px;
+}
+
+/* search */
+[dir='rtl'] .feature-list-item .label {
+  text-align: right;
+}
+
+[dir='rtl'] .feature-list-item .entity-name {
+  padding-left: 0;
+  padding-right: 10px;
+}
+
+/* preset form */
+[dir='rtl'] .form-label {
+  padding: 5px 10px 5px 0;
+}
+
+[dir='rtl'] .form-label button {
+  border-left: none;
+  border-right: 1px solid #CCC;
+}
+
+[dir='rtl'] .more-fields label {
+  padding: 5px 0 5px 10px;
+}
+
+[dir='rtl'] .form-label-button-wrap {
+  text-align: left;
+}
+
+[dir='rtl'] button.minor {
+  left: 0;
+  right: auto;
+}
+
+[dir='rtl'] .form-field .localized-main {
+  padding-left: 10%;
+  padding-right: 10px;
+}
+
+[dir='rtl'] .combobox-caret {
+  margin-left: 0;
+  margin-right: -30px;
+}
+
+[dir='rtl'] .form-field .button-input-action {
+  margin-left: 0;
+  margin-right: -10%;
+}
+
+[dir='rtl'] .icon.pre-text {
+  margin-left: 3px;
+  margin-right: 0;
+}
+
+[dir='rtl'] .notice .zoom-to .icon {
+  margin-left: 10px;
+  margin-right: 0;
+}
+
+[dir='rtl'] .preset-list-button .label {
+  text-align: right;
+  left: 0;
+  right: 60px;
+  border-left: none;
+  border-right: 1px solid rgba(0, 0, 0, .1);
+  border-radius: 3px 0 0 3px;
+}
+
+[dir='rtl'] .preset-icon-frame {
+  left: auto;
+  right: 7px;
+}
+
+[dir='rtl'] .preset-list-item button.tag-reference-button {
+  left: 0;
+  right: auto;
+  border-radius: 3px 0 0 3px;
+}
+
+[dir='rtl'] .preset-list-button-wrap .preset-icon {
+  left: auto;
+  right: auto;
+}
+
+[dir='rtl'] .preset-list-button-wrap .preset-icon-32 {
+  right: 15px;
+}
+
+[dir='rtl'] .form-field .maxspeed-unit {
+  border-radius: 0 0 0 4px;
+}
+
+[dir='rtl'] input[type="checkbox"], [dir='rtl'] input[type="radio"] {
+  float: right;
+  margin-left: 5px;
+  margin-right: 0;
+}
+
+[dir='rtl'] .preset-input-wrap .col6 {
+  float: right;
+}
+
+/* tags form */
+[dir='rtl'] .tag-row .key-wrap,
+[dir='rtl'] .tag-row .input-wrap-position {
+  float: right;
+}
+
+[dir='rtl'] .tag-row input {
+  border-left: none;
+  border-right: 1px solid #CCC;
+}
+
+[dir='rtl'] .tag-row:first-child input.key {
+  border-top-left-radius: 0;
+  border-top-right-radius: 4px;
+}
+
+[dir='rtl'] .tag-row button {
+  left: 10%;
+  border-left-width: 1px;
+}
+
+[dir='rtl'] .tag-row .tag-reference-button {
+  left: auto;
+  right: auto;
+  margin-right: 35px;
+  border-left-width: 1px;
+  border-right-width: 0;
+}
+
+[dir='rtl'] .tag-row:first-child .tag-reference-button {
+  border-top-left-radius: 4px;
+  border-top-right-radius: 0;
+}
+
+[dir='rtl'] .tag-row:last-child .tag-reference-button {
+  border-bottom-left-radius: 4px;
+  border-bottom-right-radius: 0;
+}
+
+/* map control buttons */
+[dir='rtl'] .map-controls {
+  left: 0;
+  right: auto;
+}
+
+[dir='rtl'] .background-control button,
+[dir='rtl'] .zoombuttons button.zoom-in {
+  border-radius: 0 4px 0 0;
+}
+
+[dir='rtl'] .help-control button,
+[dir='rtl'] .geolocate-control button {
+  border-radius: 0 0 4px 0;
+}
+
+[dir='rtl'] .list-item-gpx-browse svg {
+  transform: rotateY(180deg);
+}
+
+/* map control button overlays */
+[dir='rtl'] .map-overlay {
+  padding: 20px 20px 20px 50px;
+  left: 0;
+  right: auto !important;
+}
+
+[dir='rtl'] .opacity-options {
+  left: 50px;
+  right: auto;
+}
+
+[dir='rtl'] .hide-toggle {
+  padding-left: 0;
+  padding-right: 12px;
+}
+
+[dir='rtl'] .hide-toggle:before {
+  left: auto;
+  right: 0;
+  border-left: none;
+  border-right: 8px solid #7092ff;
+}
+
+[dir='rtl'] .hide-toggle.expanded:before {
+  border-left: 4px solid transparent;
+  border-right: 4px solid transparent;
+}
+
+/* navbar */
+[dir='rtl'] #bar .spacer,
+[dir='rtl'] #bar .button-wrap,
+[dir='rtl'] #bar .button-wrap button {
+  float: right;
+}
+
+[dir='rtl'] .add-point .tooltip {
+  left: inherit !important;
+}
+
+[dir='rtl'] .button-wrap:last-of-type {
+  padding-left: 0;
+  padding-right: 10px;
+}
+
+[dir='rtl'] button.save.has-count .count {
+  margin-left: auto;
+  margin-right: 8%;
+}
+
+[dir='rtl'] button.save.has-count .count::before {
+  border-left: 6px solid rgba(255,255,255,.5);
+  border-right: none;
+  left: auto;
+  right: -6px;
+}
+
+[dir='rtl'] .joined button {
+  border-left: 1px solid rgba(0,0,0,.5);
+  border-right: none;
+}
+
+[dir='rtl'] .joined button:first-child {
+  border-radius: 0 4px 4px 0;
+}
+
+[dir='rtl'] .joined button:last-child {
+  border-radius: 4px 0 0 4px;
+}
+
+/* footer */
+[dir='rtl'] #scale-block {
+  float: right;
+  clear: right;
+}
+
+[dir='rtl'] #info-block {
+  clear: left;
+}
+
+[dir='rtl'] #about-list {
+  text-align: left;
+  clear: left;
+  margin-left: 10px;
+  margin-right: 0;
+}
+
+[dir='rtl'] #about-list li {
+  float: left;
+  border-left: none;
+  border-right: 1px solid rgba(255,255,255,.5);
+  margin-left: 0;
+  margin-right: 5px;
+  padding: 5px 5px 5px 0;
+}
+
+[dir='rtl'] #about-list li:last-child {
+  border-right: none;
+}
+
+[dir='rtl'] #scale text {
+  text-anchor: end;
+}
+
+/* increment / decrement control - code by Naoufel Razouane */
+
+[dir='rtl'] .spin-control{
+  margin-left: 0;
+  margin-right: -20%;
+}
+[dir='rtl'] .spin-control button{
+  border-left: 0;
+  border-right: 1px solid #CCC;
+}
+[dir='rtl'] .spin-control button.decrement{
+  border-bottom-right-radius: 0;
+}
+[dir='rtl'] .spin-control button.increment{
+  border-bottom-left-radius: 3px;
 }
index 8f8f661..69c1b43 100644 (file)
-(function(exports) {
+(function () {
+function actionAddEntity(way) {
+    return function(graph) {
+        return graph.replace(way);
+    };
+}
 
-  var bootstrap = (typeof exports.bootstrap === "object") ?
-    exports.bootstrap :
-    (exports.bootstrap = {});
+var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
 
-  bootstrap.tooltip = function() {
+function commonjsRequire () {
+       throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
+}
 
-    var tooltip = function(selection) {
-        selection.each(setup);
-      },
-      animation = d3.functor(false),
-      html = d3.functor(false),
-      title = function() {
-        var title = this.getAttribute("data-original-title");
-        if (title) {
-          return title;
-        } else {
-          title = this.getAttribute("title");
-          this.removeAttribute("title");
-          this.setAttribute("data-original-title", title);
-        }
-        return title;
-      },
-      over = "mouseenter.tooltip",
-      out = "mouseleave.tooltip",
-      placements = "top left bottom right".split(" "),
-      placement = d3.functor("top");
-
-    tooltip.title = function(_) {
-      if (arguments.length) {
-        title = d3.functor(_);
-        return tooltip;
-      } else {
-        return title;
-      }
-    };
 
-    tooltip.html = function(_) {
-      if (arguments.length) {
-        html = d3.functor(_);
-        return tooltip;
-      } else {
-        return html;
-      }
-    };
 
-    tooltip.placement = function(_) {
-      if (arguments.length) {
-        placement = d3.functor(_);
-        return tooltip;
-      } else {
-        return placement;
-      }
-    };
+function createCommonjsModule(fn, module) {
+       return module = { exports: {} }, fn(module, module.exports), module.exports;
+}
 
-    tooltip.show = function(selection) {
-      selection.each(show);
-    };
+var lodash = createCommonjsModule(function (module, exports) {
+/**
+ * @license
+ * Lodash <https://lodash.com/>
+ * Copyright JS Foundation and other contributors <https://js.foundation/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+(function() {
 
-    tooltip.hide = function(selection) {
-      selection.each(hide);
-    };
+  /** Used as a safe reference for `undefined` in pre-ES5 environments. */
+  var undefined;
 
-    tooltip.toggle = function(selection) {
-      selection.each(toggle);
-    };
+  /** Used as the semantic version number. */
+  var VERSION = '4.17.0';
 
-    tooltip.destroy = function(selection) {
-      selection
-        .on(over, null)
-        .on(out, null)
-        .attr("title", function() {
-          return this.getAttribute("data-original-title") || this.getAttribute("title");
-        })
-        .attr("data-original-title", null)
-        .select(".tooltip")
-        .remove();
-    };
+  /** Used as the size to enable large array optimizations. */
+  var LARGE_ARRAY_SIZE = 200;
 
-    function setup() {
-      var root = d3.select(this),
-          animate = animation.apply(this, arguments),
-          tip = root.append("div")
-            .attr("class", "tooltip");
+  /** Error message constants. */
+  var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
+      FUNC_ERROR_TEXT = 'Expected a function';
 
-      if (animate) {
-        tip.classed("fade", true);
-      }
+  /** Used to stand-in for `undefined` hash values. */
+  var HASH_UNDEFINED = '__lodash_hash_undefined__';
 
-      // TODO "inside" checks?
+  /** Used as the maximum memoize cache size. */
+  var MAX_MEMOIZE_SIZE = 500;
 
-      tip.append("div")
-        .attr("class", "tooltip-arrow");
-      tip.append("div")
-        .attr("class", "tooltip-inner");
+  /** Used as the internal argument placeholder. */
+  var PLACEHOLDER = '__lodash_placeholder__';
 
-      var place = placement.apply(this, arguments);
-      tip.classed(place, true);
+  /** Used to compose bitmasks for cloning. */
+  var CLONE_DEEP_FLAG = 1,
+      CLONE_FLAT_FLAG = 2,
+      CLONE_SYMBOLS_FLAG = 4;
+
+  /** Used to compose bitmasks for value comparisons. */
+  var COMPARE_PARTIAL_FLAG = 1,
+      COMPARE_UNORDERED_FLAG = 2;
+
+  /** Used to compose bitmasks for function metadata. */
+  var WRAP_BIND_FLAG = 1,
+      WRAP_BIND_KEY_FLAG = 2,
+      WRAP_CURRY_BOUND_FLAG = 4,
+      WRAP_CURRY_FLAG = 8,
+      WRAP_CURRY_RIGHT_FLAG = 16,
+      WRAP_PARTIAL_FLAG = 32,
+      WRAP_PARTIAL_RIGHT_FLAG = 64,
+      WRAP_ARY_FLAG = 128,
+      WRAP_REARG_FLAG = 256,
+      WRAP_FLIP_FLAG = 512;
+
+  /** Used as default options for `_.truncate`. */
+  var DEFAULT_TRUNC_LENGTH = 30,
+      DEFAULT_TRUNC_OMISSION = '...';
 
-      root.on(over, show);
-      root.on(out, hide);
-    }
+  /** Used to detect hot functions by number of calls within a span of milliseconds. */
+  var HOT_COUNT = 800,
+      HOT_SPAN = 16;
 
-    function show() {
-      var root = d3.select(this),
-          content = title.apply(this, arguments),
-          tip = root.select(".tooltip")
-            .classed("in", true),
-          markup = html.apply(this, arguments),
-          innercontent = tip.select(".tooltip-inner")[markup ? "html" : "text"](content),
-          place = placement.apply(this, arguments),
-          outer = getPosition(root.node()),
-          inner = getPosition(tip.node()),
-          pos;
+  /** Used to indicate the type of lazy iteratees. */
+  var LAZY_FILTER_FLAG = 1,
+      LAZY_MAP_FLAG = 2,
+      LAZY_WHILE_FLAG = 3;
 
-      switch (place) {
-        case "top":
-          pos = {x: outer.x + (outer.w - inner.w) / 2, y: outer.y - inner.h};
-          break;
-        case "right":
-          pos = {x: outer.x + outer.w, y: outer.y + (outer.h - inner.h) / 2};
-          break;
-        case "left":
-          pos = {x: outer.x - inner.w, y: outer.y + (outer.h - inner.h) / 2};
-          break;
-        case "bottom":
-          pos = {x: Math.max(0, outer.x + (outer.w - inner.w) / 2), y: outer.y + outer.h};
-          break;
-      }
+  /** Used as references for various `Number` constants. */
+  var INFINITY = 1 / 0,
+      MAX_SAFE_INTEGER = 9007199254740991,
+      MAX_INTEGER = 1.7976931348623157e+308,
+      NAN = 0 / 0;
 
-      tip.style(pos ?
-        {left: ~~pos.x + "px", top: ~~pos.y + "px"} :
-        {left: null, top: null});
+  /** Used as references for the maximum length and index of an array. */
+  var MAX_ARRAY_LENGTH = 4294967295,
+      MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+      HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+  /** Used to associate wrap methods with their bit flags. */
+  var wrapFlags = [
+    ['ary', WRAP_ARY_FLAG],
+    ['bind', WRAP_BIND_FLAG],
+    ['bindKey', WRAP_BIND_KEY_FLAG],
+    ['curry', WRAP_CURRY_FLAG],
+    ['curryRight', WRAP_CURRY_RIGHT_FLAG],
+    ['flip', WRAP_FLIP_FLAG],
+    ['partial', WRAP_PARTIAL_FLAG],
+    ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
+    ['rearg', WRAP_REARG_FLAG]
+  ];
 
-      this.tooltipVisible = true;
-    }
+  /** `Object#toString` result references. */
+  var argsTag = '[object Arguments]',
+      arrayTag = '[object Array]',
+      asyncTag = '[object AsyncFunction]',
+      boolTag = '[object Boolean]',
+      dateTag = '[object Date]',
+      domExcTag = '[object DOMException]',
+      errorTag = '[object Error]',
+      funcTag = '[object Function]',
+      genTag = '[object GeneratorFunction]',
+      mapTag = '[object Map]',
+      numberTag = '[object Number]',
+      nullTag = '[object Null]',
+      objectTag = '[object Object]',
+      promiseTag = '[object Promise]',
+      proxyTag = '[object Proxy]',
+      regexpTag = '[object RegExp]',
+      setTag = '[object Set]',
+      stringTag = '[object String]',
+      symbolTag = '[object Symbol]',
+      undefinedTag = '[object Undefined]',
+      weakMapTag = '[object WeakMap]',
+      weakSetTag = '[object WeakSet]';
 
-    function hide() {
-      d3.select(this).select(".tooltip")
-        .classed("in", false);
+  var arrayBufferTag = '[object ArrayBuffer]',
+      dataViewTag = '[object DataView]',
+      float32Tag = '[object Float32Array]',
+      float64Tag = '[object Float64Array]',
+      int8Tag = '[object Int8Array]',
+      int16Tag = '[object Int16Array]',
+      int32Tag = '[object Int32Array]',
+      uint8Tag = '[object Uint8Array]',
+      uint8ClampedTag = '[object Uint8ClampedArray]',
+      uint16Tag = '[object Uint16Array]',
+      uint32Tag = '[object Uint32Array]';
 
-      this.tooltipVisible = false;
-    }
+  /** Used to match empty string literals in compiled template source. */
+  var reEmptyStringLeading = /\b__p \+= '';/g,
+      reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
 
-    function toggle() {
-      if (this.tooltipVisible) {
-        hide.apply(this, arguments);
-      } else {
-        show.apply(this, arguments);
-      }
-    }
+  /** Used to match HTML entities and HTML characters. */
+  var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
+      reUnescapedHtml = /[&<>"']/g,
+      reHasEscapedHtml = RegExp(reEscapedHtml.source),
+      reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
 
-    return tooltip;
-  };
+  /** Used to match template delimiters. */
+  var reEscape = /<%-([\s\S]+?)%>/g,
+      reEvaluate = /<%([\s\S]+?)%>/g,
+      reInterpolate = /<%=([\s\S]+?)%>/g;
 
-  function getPosition(node) {
-    var mode = d3.select(node).style('position');
-    if (mode === 'absolute' || mode === 'static') {
-      return {
-        x: node.offsetLeft,
-        y: node.offsetTop,
-        w: node.offsetWidth,
-        h: node.offsetHeight
-      };
-    } else {
-      return {
-        x: 0,
-        y: 0,
-        w: node.offsetWidth,
-        h: node.offsetHeight
-      };
-    }
-  }
+  /** Used to match property names within property paths. */
+  var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
+      reIsPlainProp = /^\w*$/,
+      reLeadingDot = /^\./,
+      rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
 
-})(this);
-!function(){
-  var d3 = {version: "3.5.5"}; // semver
-d3.ascending = d3_ascending;
+  /**
+   * Used to match `RegExp`
+   * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+   */
+  var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
+      reHasRegExpChar = RegExp(reRegExpChar.source);
 
-function d3_ascending(a, b) {
-  return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
-}
-d3.descending = function(a, b) {
-  return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
-};
-d3.min = function(array, f) {
-  var i = -1,
-      n = array.length,
-      a,
-      b;
-  if (arguments.length === 1) {
-    while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
-    while (++i < n) if ((b = array[i]) != null && a > b) a = b;
-  } else {
-    while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = b; break; }
-    while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
-  }
-  return a;
-};
-d3.max = function(array, f) {
-  var i = -1,
-      n = array.length,
-      a,
-      b;
-  if (arguments.length === 1) {
-    while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
-    while (++i < n) if ((b = array[i]) != null && b > a) a = b;
-  } else {
-    while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = b; break; }
-    while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
-  }
-  return a;
-};
-d3.extent = function(array, f) {
-  var i = -1,
-      n = array.length,
-      a,
-      b,
-      c;
-  if (arguments.length === 1) {
-    while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; }
-    while (++i < n) if ((b = array[i]) != null) {
-      if (a > b) a = b;
-      if (c < b) c = b;
-    }
-  } else {
-    while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = c = b; break; }
-    while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
-      if (a > b) a = b;
-      if (c < b) c = b;
-    }
-  }
-  return [a, c];
-};
-function d3_number(x) {
-  return x === null ? NaN : +x;
-}
+  /** Used to match leading and trailing whitespace. */
+  var reTrim = /^\s+|\s+$/g,
+      reTrimStart = /^\s+/,
+      reTrimEnd = /\s+$/;
 
-function d3_numeric(x) {
-  return !isNaN(x);
-}
+  /** Used to match wrap detail comments. */
+  var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
+      reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
+      reSplitDetails = /,? & /;
 
-d3.sum = function(array, f) {
-  var s = 0,
-      n = array.length,
-      a,
-      i = -1;
-  if (arguments.length === 1) {
-    while (++i < n) if (d3_numeric(a = +array[i])) s += a; // zero and null are equivalent
-  } else {
-    while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
-  }
-  return s;
-};
+  /** Used to match words composed of alphanumeric characters. */
+  var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
 
-d3.mean = function(array, f) {
-  var s = 0,
-      n = array.length,
-      a,
-      i = -1,
-      j = n;
-  if (arguments.length === 1) {
-    while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j;
-  } else {
-    while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j;
-  }
-  if (j) return s / j;
-};
-// R-7 per <http://en.wikipedia.org/wiki/Quantile>
-d3.quantile = function(values, p) {
-  var H = (values.length - 1) * p + 1,
-      h = Math.floor(H),
-      v = +values[h - 1],
-      e = H - h;
-  return e ? v + e * (values[h] - v) : v;
-};
+  /** Used to match backslashes in property paths. */
+  var reEscapeChar = /\\(\\)?/g;
 
-d3.median = function(array, f) {
-  var numbers = [],
-      n = array.length,
-      a,
-      i = -1;
-  if (arguments.length === 1) {
-    while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a);
-  } else {
-    while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a);
-  }
-  if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5);
-};
+  /**
+   * Used to match
+   * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
+   */
+  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
 
-d3.variance = function(array, f) {
-  var n = array.length,
-      m = 0,
-      a,
-      d,
-      s = 0,
-      i = -1,
-      j = 0;
-  if (arguments.length === 1) {
-    while (++i < n) {
-      if (d3_numeric(a = d3_number(array[i]))) {
-        d = a - m;
-        m += d / ++j;
-        s += d * (a - m);
-      }
-    }
-  } else {
-    while (++i < n) {
-      if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) {
-        d = a - m;
-        m += d / ++j;
-        s += d * (a - m);
-      }
-    }
-  }
-  if (j > 1) return s / (j - 1);
-};
+  /** Used to match `RegExp` flags from their coerced string values. */
+  var reFlags = /\w*$/;
 
-d3.deviation = function() {
-  var v = d3.variance.apply(this, arguments);
-  return v ? Math.sqrt(v) : v;
-};
+  /** Used to detect bad signed hexadecimal string values. */
+  var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
 
-function d3_bisector(compare) {
-  return {
-    left: function(a, x, lo, hi) {
-      if (arguments.length < 3) lo = 0;
-      if (arguments.length < 4) hi = a.length;
-      while (lo < hi) {
-        var mid = lo + hi >>> 1;
-        if (compare(a[mid], x) < 0) lo = mid + 1;
-        else hi = mid;
-      }
-      return lo;
-    },
-    right: function(a, x, lo, hi) {
-      if (arguments.length < 3) lo = 0;
-      if (arguments.length < 4) hi = a.length;
-      while (lo < hi) {
-        var mid = lo + hi >>> 1;
-        if (compare(a[mid], x) > 0) hi = mid;
-        else lo = mid + 1;
-      }
-      return lo;
-    }
-  };
-}
+  /** Used to detect binary string values. */
+  var reIsBinary = /^0b[01]+$/i;
 
-var d3_bisect = d3_bisector(d3_ascending);
-d3.bisectLeft = d3_bisect.left;
-d3.bisect = d3.bisectRight = d3_bisect.right;
+  /** Used to detect host constructors (Safari). */
+  var reIsHostCtor = /^\[object .+?Constructor\]$/;
 
-d3.bisector = function(f) {
-  return d3_bisector(f.length === 1
-      ? function(d, x) { return d3_ascending(f(d), x); }
-      : f);
-};
-d3.shuffle = function(array, i0, i1) {
-  if ((m = arguments.length) < 3) { i1 = array.length; if (m < 2) i0 = 0; }
-  var m = i1 - i0, t, i;
-  while (m) {
-    i = Math.random() * m-- | 0;
-    t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t;
-  }
-  return array;
-};
-d3.permute = function(array, indexes) {
-  var i = indexes.length, permutes = new Array(i);
-  while (i--) permutes[i] = array[indexes[i]];
-  return permutes;
-};
-d3.pairs = function(array) {
-  var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);
-  while (i < n) pairs[i] = [p0 = p1, p1 = array[++i]];
-  return pairs;
-};
+  /** Used to detect octal string values. */
+  var reIsOctal = /^0o[0-7]+$/i;
 
-d3.zip = function() {
-  if (!(n = arguments.length)) return [];
-  for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m;) {
-    for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n;) {
-      zip[j] = arguments[j][i];
-    }
-  }
-  return zips;
-};
+  /** Used to detect unsigned integer values. */
+  var reIsUint = /^(?:0|[1-9]\d*)$/;
 
-function d3_zipLength(d) {
-  return d.length;
-}
+  /** Used to match Latin Unicode letters (excluding mathematical operators). */
+  var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
 
-d3.transpose = function(matrix) {
-  return d3.zip.apply(d3, matrix);
-};
-d3.keys = function(map) {
-  var keys = [];
-  for (var key in map) keys.push(key);
-  return keys;
-};
-d3.values = function(map) {
-  var values = [];
-  for (var key in map) values.push(map[key]);
-  return values;
-};
-d3.entries = function(map) {
-  var entries = [];
-  for (var key in map) entries.push({key: key, value: map[key]});
-  return entries;
-};
-d3.merge = function(arrays) {
-  var n = arrays.length,
-      m,
-      i = -1,
-      j = 0,
-      merged,
-      array;
-
-  while (++i < n) j += arrays[i].length;
-  merged = new Array(j);
-
-  while (--n >= 0) {
-    array = arrays[n];
-    m = array.length;
-    while (--m >= 0) {
-      merged[--j] = array[m];
-    }
-  }
-
-  return merged;
-};
-var abs = Math.abs;
-
-d3.range = function(start, stop, step) {
-  if (arguments.length < 3) {
-    step = 1;
-    if (arguments.length < 2) {
-      stop = start;
-      start = 0;
-    }
-  }
-  if ((stop - start) / step === Infinity) throw new Error("infinite range");
-  var range = [],
-       k = d3_range_integerScale(abs(step)),
-       i = -1,
-       j;
-  start *= k, stop *= k, step *= k;
-  if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k);
-  else while ((j = start + step * ++i) < stop) range.push(j / k);
-  return range;
-};
-
-function d3_range_integerScale(x) {
-  var k = 1;
-  while (x * k % 1) k *= 10;
-  return k;
-}
-function d3_class(ctor, properties) {
-  for (var key in properties) {
-    Object.defineProperty(ctor.prototype, key, {
-      value: properties[key],
-      enumerable: false
-    });
-  }
-}
-
-d3.map = function(object, f) {
-  var map = new d3_Map;
-  if (object instanceof d3_Map) {
-    object.forEach(function(key, value) { map.set(key, value); });
-  } else if (Array.isArray(object)) {
-    var i = -1,
-        n = object.length,
-        o;
-    if (arguments.length === 1) while (++i < n) map.set(i, object[i]);
-    else while (++i < n) map.set(f.call(object, o = object[i], i), o);
-  } else {
-    for (var key in object) map.set(key, object[key]);
-  }
-  return map;
-};
-
-function d3_Map() {
-  this._ = Object.create(null);
-}
-
-var d3_map_proto = "__proto__",
-    d3_map_zero = "\0";
-
-d3_class(d3_Map, {
-  has: d3_map_has,
-  get: function(key) {
-    return this._[d3_map_escape(key)];
-  },
-  set: function(key, value) {
-    return this._[d3_map_escape(key)] = value;
-  },
-  remove: d3_map_remove,
-  keys: d3_map_keys,
-  values: function() {
-    var values = [];
-    for (var key in this._) values.push(this._[key]);
-    return values;
-  },
-  entries: function() {
-    var entries = [];
-    for (var key in this._) entries.push({key: d3_map_unescape(key), value: this._[key]});
-    return entries;
-  },
-  size: d3_map_size,
-  empty: d3_map_empty,
-  forEach: function(f) {
-    for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]);
-  }
-});
-
-function d3_map_escape(key) {
-  return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key;
-}
-
-function d3_map_unescape(key) {
-  return (key += "")[0] === d3_map_zero ? key.slice(1) : key;
-}
-
-function d3_map_has(key) {
-  return d3_map_escape(key) in this._;
-}
-
-function d3_map_remove(key) {
-  return (key = d3_map_escape(key)) in this._ && delete this._[key];
-}
-
-function d3_map_keys() {
-  var keys = [];
-  for (var key in this._) keys.push(d3_map_unescape(key));
-  return keys;
-}
-
-function d3_map_size() {
-  var size = 0;
-  for (var key in this._) ++size;
-  return size;
-}
-
-function d3_map_empty() {
-  for (var key in this._) return false;
-  return true;
-}
+  /** Used to ensure capturing order of template delimiters. */
+  var reNoMatch = /($^)/;
 
-d3.nest = function() {
-  var nest = {},
-      keys = [],
-      sortKeys = [],
-      sortValues,
-      rollup;
-
-  function map(mapType, array, depth) {
-    if (depth >= keys.length) return rollup
-        ? rollup.call(nest, array) : (sortValues
-        ? array.sort(sortValues)
-        : array);
-
-    var i = -1,
-        n = array.length,
-        key = keys[depth++],
-        keyValue,
-        object,
-        setter,
-        valuesByKey = new d3_Map,
-        values;
+  /** Used to match unescaped characters in compiled string literals. */
+  var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
 
-    while (++i < n) {
-      if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
-        values.push(object);
-      } else {
-        valuesByKey.set(keyValue, [object]);
-      }
-    }
+  /** Used to compose unicode character classes. */
+  var rsAstralRange = '\\ud800-\\udfff',
+      rsComboMarksRange = '\\u0300-\\u036f',
+      reComboHalfMarksRange = '\\ufe20-\\ufe2f',
+      rsComboSymbolsRange = '\\u20d0-\\u20ff',
+      rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
+      rsDingbatRange = '\\u2700-\\u27bf',
+      rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
+      rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
+      rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
+      rsPunctuationRange = '\\u2000-\\u206f',
+      rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
+      rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
+      rsVarRange = '\\ufe0e\\ufe0f',
+      rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
 
-    if (mapType) {
-      object = mapType();
-      setter = function(keyValue, values) {
-        object.set(keyValue, map(mapType, values, depth));
-      };
-    } else {
-      object = {};
-      setter = function(keyValue, values) {
-        object[keyValue] = map(mapType, values, depth);
-      };
-    }
+  /** Used to compose unicode capture groups. */
+  var rsApos = "['\u2019]",
+      rsAstral = '[' + rsAstralRange + ']',
+      rsBreak = '[' + rsBreakRange + ']',
+      rsCombo = '[' + rsComboRange + ']',
+      rsDigits = '\\d+',
+      rsDingbat = '[' + rsDingbatRange + ']',
+      rsLower = '[' + rsLowerRange + ']',
+      rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
+      rsFitz = '\\ud83c[\\udffb-\\udfff]',
+      rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
+      rsNonAstral = '[^' + rsAstralRange + ']',
+      rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
+      rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
+      rsUpper = '[' + rsUpperRange + ']',
+      rsZWJ = '\\u200d';
 
-    valuesByKey.forEach(setter);
-    return object;
-  }
+  /** Used to compose unicode regexes. */
+  var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
+      rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
+      rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
+      rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
+      reOptMod = rsModifier + '?',
+      rsOptVar = '[' + rsVarRange + ']?',
+      rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
+      rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)',
+      rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)',
+      rsSeq = rsOptVar + reOptMod + rsOptJoin,
+      rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
+      rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
 
-  function entries(map, depth) {
-    if (depth >= keys.length) return map;
+  /** Used to match apostrophes. */
+  var reApos = RegExp(rsApos, 'g');
 
-    var array = [],
-        sortKey = sortKeys[depth++];
+  /**
+   * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
+   * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
+   */
+  var reComboMark = RegExp(rsCombo, 'g');
 
-    map.forEach(function(key, keyMap) {
-      array.push({key: key, values: entries(keyMap, depth)});
-    });
+  /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
+  var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
+
+  /** Used to match complex or compound words. */
+  var reUnicodeWord = RegExp([
+    rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
+    rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
+    rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
+    rsUpper + '+' + rsOptContrUpper,
+    rsOrdUpper,
+    rsOrdLower,
+    rsDigits,
+    rsEmoji
+  ].join('|'), 'g');
+
+  /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
+  var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange  + rsComboRange + rsVarRange + ']');
+
+  /** Used to detect strings that need a more robust regexp to match words. */
+  var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
+
+  /** Used to assign default `context` object properties. */
+  var contextProps = [
+    'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
+    'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
+    'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
+    'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
+    '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
+  ];
 
-    return sortKey
-        ? array.sort(function(a, b) { return sortKey(a.key, b.key); })
-        : array;
-  }
+  /** Used to make template sourceURLs easier to identify. */
+  var templateCounter = -1;
 
-  nest.map = function(array, mapType) {
-    return map(mapType, array, 0);
-  };
+  /** Used to identify `toStringTag` values of typed arrays. */
+  var typedArrayTags = {};
+  typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+  typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+  typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+  typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+  typedArrayTags[uint32Tag] = true;
+  typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+  typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+  typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
+  typedArrayTags[errorTag] = typedArrayTags[funcTag] =
+  typedArrayTags[mapTag] = typedArrayTags[numberTag] =
+  typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
+  typedArrayTags[setTag] = typedArrayTags[stringTag] =
+  typedArrayTags[weakMapTag] = false;
 
-  nest.entries = function(array) {
-    return entries(map(d3.map, array, 0), 0);
-  };
+  /** Used to identify `toStringTag` values supported by `_.clone`. */
+  var cloneableTags = {};
+  cloneableTags[argsTag] = cloneableTags[arrayTag] =
+  cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
+  cloneableTags[boolTag] = cloneableTags[dateTag] =
+  cloneableTags[float32Tag] = cloneableTags[float64Tag] =
+  cloneableTags[int8Tag] = cloneableTags[int16Tag] =
+  cloneableTags[int32Tag] = cloneableTags[mapTag] =
+  cloneableTags[numberTag] = cloneableTags[objectTag] =
+  cloneableTags[regexpTag] = cloneableTags[setTag] =
+  cloneableTags[stringTag] = cloneableTags[symbolTag] =
+  cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+  cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+  cloneableTags[errorTag] = cloneableTags[funcTag] =
+  cloneableTags[weakMapTag] = false;
 
-  nest.key = function(d) {
-    keys.push(d);
-    return nest;
+  /** Used to map Latin Unicode letters to basic Latin letters. */
+  var deburredLetters = {
+    // Latin-1 Supplement block.
+    '\xc0': 'A',  '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+    '\xe0': 'a',  '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+    '\xc7': 'C',  '\xe7': 'c',
+    '\xd0': 'D',  '\xf0': 'd',
+    '\xc8': 'E',  '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+    '\xe8': 'e',  '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+    '\xcc': 'I',  '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+    '\xec': 'i',  '\xed': 'i', '\xee': 'i', '\xef': 'i',
+    '\xd1': 'N',  '\xf1': 'n',
+    '\xd2': 'O',  '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+    '\xf2': 'o',  '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+    '\xd9': 'U',  '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+    '\xf9': 'u',  '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+    '\xdd': 'Y',  '\xfd': 'y', '\xff': 'y',
+    '\xc6': 'Ae', '\xe6': 'ae',
+    '\xde': 'Th', '\xfe': 'th',
+    '\xdf': 'ss',
+    // Latin Extended-A block.
+    '\u0100': 'A',  '\u0102': 'A', '\u0104': 'A',
+    '\u0101': 'a',  '\u0103': 'a', '\u0105': 'a',
+    '\u0106': 'C',  '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
+    '\u0107': 'c',  '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
+    '\u010e': 'D',  '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
+    '\u0112': 'E',  '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
+    '\u0113': 'e',  '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
+    '\u011c': 'G',  '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
+    '\u011d': 'g',  '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
+    '\u0124': 'H',  '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
+    '\u0128': 'I',  '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
+    '\u0129': 'i',  '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
+    '\u0134': 'J',  '\u0135': 'j',
+    '\u0136': 'K',  '\u0137': 'k', '\u0138': 'k',
+    '\u0139': 'L',  '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
+    '\u013a': 'l',  '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
+    '\u0143': 'N',  '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
+    '\u0144': 'n',  '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
+    '\u014c': 'O',  '\u014e': 'O', '\u0150': 'O',
+    '\u014d': 'o',  '\u014f': 'o', '\u0151': 'o',
+    '\u0154': 'R',  '\u0156': 'R', '\u0158': 'R',
+    '\u0155': 'r',  '\u0157': 'r', '\u0159': 'r',
+    '\u015a': 'S',  '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
+    '\u015b': 's',  '\u015d': 's', '\u015f': 's', '\u0161': 's',
+    '\u0162': 'T',  '\u0164': 'T', '\u0166': 'T',
+    '\u0163': 't',  '\u0165': 't', '\u0167': 't',
+    '\u0168': 'U',  '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
+    '\u0169': 'u',  '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
+    '\u0174': 'W',  '\u0175': 'w',
+    '\u0176': 'Y',  '\u0177': 'y', '\u0178': 'Y',
+    '\u0179': 'Z',  '\u017b': 'Z', '\u017d': 'Z',
+    '\u017a': 'z',  '\u017c': 'z', '\u017e': 'z',
+    '\u0132': 'IJ', '\u0133': 'ij',
+    '\u0152': 'Oe', '\u0153': 'oe',
+    '\u0149': "'n", '\u017f': 's'
   };
 
-  // Specifies the order for the most-recently specified key.
-  // Note: only applies to entries. Map keys are unordered!
-  nest.sortKeys = function(order) {
-    sortKeys[keys.length - 1] = order;
-    return nest;
+  /** Used to map characters to HTML entities. */
+  var htmlEscapes = {
+    '&': '&amp;',
+    '<': '&lt;',
+    '>': '&gt;',
+    '"': '&quot;',
+    "'": '&#39;'
   };
 
-  // Specifies the order for leaf values.
-  // Applies to both maps and entries array.
-  nest.sortValues = function(order) {
-    sortValues = order;
-    return nest;
+  /** Used to map HTML entities to characters. */
+  var htmlUnescapes = {
+    '&amp;': '&',
+    '&lt;': '<',
+    '&gt;': '>',
+    '&quot;': '"',
+    '&#39;': "'"
   };
 
-  nest.rollup = function(f) {
-    rollup = f;
-    return nest;
+  /** Used to escape characters for inclusion in compiled string literals. */
+  var stringEscapes = {
+    '\\': '\\',
+    "'": "'",
+    '\n': 'n',
+    '\r': 'r',
+    '\u2028': 'u2028',
+    '\u2029': 'u2029'
   };
 
-  return nest;
-};
+  /** Built-in method references without a dependency on `root`. */
+  var freeParseFloat = parseFloat,
+      freeParseInt = parseInt;
 
-d3.set = function(array) {
-  var set = new d3_Set;
-  if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
-  return set;
-};
+  /** Detect free variable `global` from Node.js. */
+  var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
 
-function d3_Set() {
-  this._ = Object.create(null);
-}
+  /** Detect free variable `self`. */
+  var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
 
-d3_class(d3_Set, {
-  has: d3_map_has,
-  add: function(key) {
-    this._[d3_map_escape(key += "")] = true;
-    return key;
-  },
-  remove: d3_map_remove,
-  values: d3_map_keys,
-  size: d3_map_size,
-  empty: d3_map_empty,
-  forEach: function(f) {
-    for (var key in this._) f.call(this, d3_map_unescape(key));
-  }
-});
-d3.behavior = {};
-var d3_document = this.document;
+  /** Used as a reference to the global object. */
+  var root = freeGlobal || freeSelf || Function('return this')();
 
-function d3_documentElement(node) {
-  return node
-      && (node.ownerDocument // node is a Node
-      || node.document // node is a Window
-      || node).documentElement; // node is a Document
-}
+  /** Detect free variable `exports`. */
+  var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
 
-function d3_window(node) {
-  return node
-      && ((node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
-        || (node.document && node) // node is a Window
-        || node.defaultView); // node is a Document
-}
-// Copies a variable number of methods from source to target.
-d3.rebind = function(target, source) {
-  var i = 1, n = arguments.length, method;
-  while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
-  return target;
-};
+  /** Detect free variable `module`. */
+  var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
 
-// Method is assumed to be a standard D3 getter-setter:
-// If passed with no arguments, gets the value.
-// If passed with arguments, sets the value and returns the target.
-function d3_rebind(target, source, method) {
-  return function() {
-    var value = method.apply(source, arguments);
-    return value === source ? target : value;
-  };
-}
-function d3_vendorSymbol(object, name) {
-  if (name in object) return name;
-  name = name.charAt(0).toUpperCase() + name.slice(1);
-  for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
-    var prefixName = d3_vendorPrefixes[i] + name;
-    if (prefixName in object) return prefixName;
-  }
-}
+  /** Detect the popular CommonJS extension `module.exports`. */
+  var moduleExports = freeModule && freeModule.exports === freeExports;
 
-var d3_vendorPrefixes = ["webkit", "ms", "moz", "Moz", "o", "O"];
-var d3_arraySlice = [].slice,
-    d3_array = function(list) { return d3_arraySlice.call(list); }; // conversion for NodeLists
-function d3_noop() {}
+  /** Detect free variable `process` from Node.js. */
+  var freeProcess = moduleExports && freeGlobal.process;
 
-d3.dispatch = function() {
-  var dispatch = new d3_dispatch,
-      i = -1,
-      n = arguments.length;
-  while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
-  return dispatch;
-};
+  /** Used to access faster Node.js helpers. */
+  var nodeUtil = (function() {
+    try {
+      return freeProcess && freeProcess.binding && freeProcess.binding('util');
+    } catch (e) {}
+  }());
 
-function d3_dispatch() {}
+  /* Node.js helper references. */
+  var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
+      nodeIsDate = nodeUtil && nodeUtil.isDate,
+      nodeIsMap = nodeUtil && nodeUtil.isMap,
+      nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
+      nodeIsSet = nodeUtil && nodeUtil.isSet,
+      nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
 
-d3_dispatch.prototype.on = function(type, listener) {
-  var i = type.indexOf("."),
-      name = "";
+  /*--------------------------------------------------------------------------*/
 
-  // Extract optional namespace, e.g., "click.foo"
-  if (i >= 0) {
-    name = type.slice(i + 1);
-    type = type.slice(0, i);
+  /**
+   * Adds the key-value `pair` to `map`.
+   *
+   * @private
+   * @param {Object} map The map to modify.
+   * @param {Array} pair The key-value pair to add.
+   * @returns {Object} Returns `map`.
+   */
+  function addMapEntry(map, pair) {
+    // Don't return `map.set` because it's not chainable in IE 11.
+    map.set(pair[0], pair[1]);
+    return map;
   }
 
-  if (type) return arguments.length < 2
-      ? this[type].on(name)
-      : this[type].on(name, listener);
-
-  if (arguments.length === 2) {
-    if (listener == null) for (type in this) {
-      if (this.hasOwnProperty(type)) this[type].on(name, null);
-    }
-    return this;
+  /**
+   * Adds `value` to `set`.
+   *
+   * @private
+   * @param {Object} set The set to modify.
+   * @param {*} value The value to add.
+   * @returns {Object} Returns `set`.
+   */
+  function addSetEntry(set, value) {
+    // Don't return `set.add` because it's not chainable in IE 11.
+    set.add(value);
+    return set;
   }
-};
 
-function d3_dispatch_event(dispatch) {
-  var listeners = [],
-      listenerByName = new d3_Map;
-
-  function event() {
-    var z = listeners, // defensive reference
-        i = -1,
-        n = z.length,
-        l;
-    while (++i < n) if (l = z[i].on) l.apply(this, arguments);
-    return dispatch;
+  /**
+   * A faster alternative to `Function#apply`, this function invokes `func`
+   * with the `this` binding of `thisArg` and the arguments of `args`.
+   *
+   * @private
+   * @param {Function} func The function to invoke.
+   * @param {*} thisArg The `this` binding of `func`.
+   * @param {Array} args The arguments to invoke `func` with.
+   * @returns {*} Returns the result of `func`.
+   */
+  function apply(func, thisArg, args) {
+    switch (args.length) {
+      case 0: return func.call(thisArg);
+      case 1: return func.call(thisArg, args[0]);
+      case 2: return func.call(thisArg, args[0], args[1]);
+      case 3: return func.call(thisArg, args[0], args[1], args[2]);
+    }
+    return func.apply(thisArg, args);
   }
 
-  event.on = function(name, listener) {
-    var l = listenerByName.get(name),
-        i;
-
-    // return the current listener, if any
-    if (arguments.length < 2) return l && l.on;
+  /**
+   * A specialized version of `baseAggregator` for arrays.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} setter The function to set `accumulator` values.
+   * @param {Function} iteratee The iteratee to transform keys.
+   * @param {Object} accumulator The initial aggregated object.
+   * @returns {Function} Returns `accumulator`.
+   */
+  function arrayAggregator(array, setter, iteratee, accumulator) {
+    var index = -1,
+        length = array == null ? 0 : array.length;
 
-    // remove the old listener, if any (with copy-on-write)
-    if (l) {
-      l.on = null;
-      listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
-      listenerByName.remove(name);
+    while (++index < length) {
+      var value = array[index];
+      setter(accumulator, value, iteratee(value), array);
     }
+    return accumulator;
+  }
 
-    // add the new listener, if any
-    if (listener) listeners.push(listenerByName.set(name, {on: listener}));
-
-    return dispatch;
-  };
-
-  return event;
-}
-
-d3.event = null;
-
-function d3_eventPreventDefault() {
-  d3.event.preventDefault();
-}
-
-function d3_eventCancel() {
-  d3.event.preventDefault();
-  d3.event.stopPropagation();
-}
-
-function d3_eventSource() {
-  var e = d3.event, s;
-  while (s = e.sourceEvent) e = s;
-  return e;
-}
+  /**
+   * A specialized version of `_.forEach` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {Array} Returns `array`.
+   */
+  function arrayEach(array, iteratee) {
+    var index = -1,
+        length = array == null ? 0 : array.length;
 
-// Like d3.dispatch, but for custom events abstracting native UI events. These
-// events have a target component (such as a brush), a target element (such as
-// the svg:g element containing the brush) and the standard arguments `d` (the
-// target element's data) and `i` (the selection index of the target element).
-function d3_eventDispatch(target) {
-  var dispatch = new d3_dispatch,
-      i = 0,
-      n = arguments.length;
-
-  while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
-
-  // Creates a dispatch context for the specified `thiz` (typically, the target
-  // DOM element that received the source event) and `argumentz` (typically, the
-  // data `d` and index `i` of the target element). The returned function can be
-  // used to dispatch an event to any registered listeners; the function takes a
-  // single argument as input, being the event to dispatch. The event must have
-  // a "type" attribute which corresponds to a type registered in the
-  // constructor. This context will automatically populate the "sourceEvent" and
-  // "target" attributes of the event, as well as setting the `d3.event` global
-  // for the duration of the notification.
-  dispatch.of = function(thiz, argumentz) {
-    return function(e1) {
-      try {
-        var e0 =
-        e1.sourceEvent = d3.event;
-        e1.target = target;
-        d3.event = e1;
-        dispatch[e1.type].apply(thiz, argumentz);
-      } finally {
-        d3.event = e0;
+    while (++index < length) {
+      if (iteratee(array[index], index, array) === false) {
+        break;
       }
-    };
-  };
-
-  return dispatch;
-}
-d3.requote = function(s) {
-  return s.replace(d3_requote_re, "\\$&");
-};
-
-var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
-var d3_subclass = {}.__proto__?
-
-// Until ECMAScript supports array subclassing, prototype injection works well.
-function(object, prototype) {
-  object.__proto__ = prototype;
-}:
-
-// And if your browser doesn't support __proto__, we'll use direct extension.
-function(object, prototype) {
-  for (var property in prototype) object[property] = prototype[property];
-};
-
-function d3_selection(groups) {
-  d3_subclass(groups, d3_selectionPrototype);
-  return groups;
-}
-
-var d3_select = function(s, n) { return n.querySelector(s); },
-    d3_selectAll = function(s, n) { return n.querySelectorAll(s); },
-    d3_selectMatches = function(n, s) {
-      var d3_selectMatcher = n.matches || n[d3_vendorSymbol(n, "matchesSelector")];
-      d3_selectMatches = function(n, s) {
-        return d3_selectMatcher.call(n, s);
-      };
-      return d3_selectMatches(n, s);
-    };
-
-// Prefer Sizzle, if available.
-if (typeof Sizzle === "function") {
-  d3_select = function(s, n) { return Sizzle(s, n)[0] || null; };
-  d3_selectAll = Sizzle;
-  d3_selectMatches = Sizzle.matchesSelector;
-}
-
-d3.selection = function() {
-  return d3.select(d3_document.documentElement);
-};
-
-var d3_selectionPrototype = d3.selection.prototype = [];
-
-
-d3_selectionPrototype.select = function(selector) {
-  var subgroups = [],
-      subgroup,
-      subnode,
-      group,
-      node;
+    }
+    return array;
+  }
 
-  selector = d3_selection_selector(selector);
+  /**
+   * A specialized version of `_.forEachRight` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {Array} Returns `array`.
+   */
+  function arrayEachRight(array, iteratee) {
+    var length = array == null ? 0 : array.length;
 
-  for (var j = -1, m = this.length; ++j < m;) {
-    subgroups.push(subgroup = []);
-    subgroup.parentNode = (group = this[j]).parentNode;
-    for (var i = -1, n = group.length; ++i < n;) {
-      if (node = group[i]) {
-        subgroup.push(subnode = selector.call(node, node.__data__, i, j));
-        if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
-      } else {
-        subgroup.push(null);
+    while (length--) {
+      if (iteratee(array[length], length, array) === false) {
+        break;
       }
     }
+    return array;
   }
 
-  return d3_selection(subgroups);
-};
-
-function d3_selection_selector(selector) {
-  return typeof selector === "function" ? selector : function() {
-    return d3_select(selector, this);
-  };
-}
+  /**
+   * A specialized version of `_.every` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} predicate The function invoked per iteration.
+   * @returns {boolean} Returns `true` if all elements pass the predicate check,
+   *  else `false`.
+   */
+  function arrayEvery(array, predicate) {
+    var index = -1,
+        length = array == null ? 0 : array.length;
 
-d3_selectionPrototype.selectAll = function(selector) {
-  var subgroups = [],
-      subgroup,
-      node;
+    while (++index < length) {
+      if (!predicate(array[index], index, array)) {
+        return false;
+      }
+    }
+    return true;
+  }
 
-  selector = d3_selection_selectorAll(selector);
+  /**
+   * A specialized version of `_.filter` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} predicate The function invoked per iteration.
+   * @returns {Array} Returns the new filtered array.
+   */
+  function arrayFilter(array, predicate) {
+    var index = -1,
+        length = array == null ? 0 : array.length,
+        resIndex = 0,
+        result = [];
 
-  for (var j = -1, m = this.length; ++j < m;) {
-    for (var group = this[j], i = -1, n = group.length; ++i < n;) {
-      if (node = group[i]) {
-        subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
-        subgroup.parentNode = node;
+    while (++index < length) {
+      var value = array[index];
+      if (predicate(value, index, array)) {
+        result[resIndex++] = value;
       }
     }
+    return result;
   }
 
-  return d3_selection(subgroups);
-};
+  /**
+   * A specialized version of `_.includes` for arrays without support for
+   * specifying an index to search from.
+   *
+   * @private
+   * @param {Array} [array] The array to inspect.
+   * @param {*} target The value to search for.
+   * @returns {boolean} Returns `true` if `target` is found, else `false`.
+   */
+  function arrayIncludes(array, value) {
+    var length = array == null ? 0 : array.length;
+    return !!length && baseIndexOf(array, value, 0) > -1;
+  }
 
-function d3_selection_selectorAll(selector) {
-  return typeof selector === "function" ? selector : function() {
-    return d3_selectAll(selector, this);
-  };
-}
-var d3_nsPrefix = {
-  svg: "http://www.w3.org/2000/svg",
-  xhtml: "http://www.w3.org/1999/xhtml",
-  xlink: "http://www.w3.org/1999/xlink",
-  xml: "http://www.w3.org/XML/1998/namespace",
-  xmlns: "http://www.w3.org/2000/xmlns/"
-};
+  /**
+   * This function is like `arrayIncludes` except that it accepts a comparator.
+   *
+   * @private
+   * @param {Array} [array] The array to inspect.
+   * @param {*} target The value to search for.
+   * @param {Function} comparator The comparator invoked per element.
+   * @returns {boolean} Returns `true` if `target` is found, else `false`.
+   */
+  function arrayIncludesWith(array, value, comparator) {
+    var index = -1,
+        length = array == null ? 0 : array.length;
 
-d3.ns = {
-  prefix: d3_nsPrefix,
-  qualify: function(name) {
-    var i = name.indexOf(":"),
-        prefix = name;
-    if (i >= 0) {
-      prefix = name.slice(0, i);
-      name = name.slice(i + 1);
+    while (++index < length) {
+      if (comparator(value, array[index])) {
+        return true;
+      }
     }
-    return d3_nsPrefix.hasOwnProperty(prefix)
-        ? {space: d3_nsPrefix[prefix], local: name}
-        : name;
+    return false;
   }
-};
 
-d3_selectionPrototype.attr = function(name, value) {
-  if (arguments.length < 2) {
+  /**
+   * A specialized version of `_.map` for arrays without support for iteratee
+   * shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {Array} Returns the new mapped array.
+   */
+  function arrayMap(array, iteratee) {
+    var index = -1,
+        length = array == null ? 0 : array.length,
+        result = Array(length);
 
-    // For attr(string), return the attribute value for the first node.
-    if (typeof name === "string") {
-      var node = this.node();
-      name = d3.ns.qualify(name);
-      return name.local
-          ? node.getAttributeNS(name.space, name.local)
-          : node.getAttribute(name);
+    while (++index < length) {
+      result[index] = iteratee(array[index], index, array);
     }
-
-    // For attr(object), the object specifies the names and values of the
-    // attributes to set or remove. The values may be functions that are
-    // evaluated for each element.
-    for (value in name) this.each(d3_selection_attr(value, name[value]));
-    return this;
+    return result;
   }
 
-  return this.each(d3_selection_attr(name, value));
-};
-
-function d3_selection_attr(name, value) {
-  name = d3.ns.qualify(name);
+  /**
+   * Appends the elements of `values` to `array`.
+   *
+   * @private
+   * @param {Array} array The array to modify.
+   * @param {Array} values The values to append.
+   * @returns {Array} Returns `array`.
+   */
+  function arrayPush(array, values) {
+    var index = -1,
+        length = values.length,
+        offset = array.length;
 
-  // For attr(string, null), remove the attribute with the specified name.
-  function attrNull() {
-    this.removeAttribute(name);
-  }
-  function attrNullNS() {
-    this.removeAttributeNS(name.space, name.local);
+    while (++index < length) {
+      array[offset + index] = values[index];
+    }
+    return array;
   }
 
-  // For attr(string, string), set the attribute with the specified name.
-  function attrConstant() {
-    this.setAttribute(name, value);
-  }
-  function attrConstantNS() {
-    this.setAttributeNS(name.space, name.local, value);
-  }
+  /**
+   * A specialized version of `_.reduce` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @param {*} [accumulator] The initial value.
+   * @param {boolean} [initAccum] Specify using the first element of `array` as
+   *  the initial value.
+   * @returns {*} Returns the accumulated value.
+   */
+  function arrayReduce(array, iteratee, accumulator, initAccum) {
+    var index = -1,
+        length = array == null ? 0 : array.length;
 
-  // For attr(string, function), evaluate the function for each element, and set
-  // or remove the attribute as appropriate.
-  function attrFunction() {
-    var x = value.apply(this, arguments);
-    if (x == null) this.removeAttribute(name);
-    else this.setAttribute(name, x);
-  }
-  function attrFunctionNS() {
-    var x = value.apply(this, arguments);
-    if (x == null) this.removeAttributeNS(name.space, name.local);
-    else this.setAttributeNS(name.space, name.local, x);
+    if (initAccum && length) {
+      accumulator = array[++index];
+    }
+    while (++index < length) {
+      accumulator = iteratee(accumulator, array[index], index, array);
+    }
+    return accumulator;
   }
 
-  return value == null
-      ? (name.local ? attrNullNS : attrNull) : (typeof value === "function"
-      ? (name.local ? attrFunctionNS : attrFunction)
-      : (name.local ? attrConstantNS : attrConstant));
-}
-function d3_collapse(s) {
-  return s.trim().replace(/\s+/g, " ");
-}
+  /**
+   * A specialized version of `_.reduceRight` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @param {*} [accumulator] The initial value.
+   * @param {boolean} [initAccum] Specify using the last element of `array` as
+   *  the initial value.
+   * @returns {*} Returns the accumulated value.
+   */
+  function arrayReduceRight(array, iteratee, accumulator, initAccum) {
+    var length = array == null ? 0 : array.length;
+    if (initAccum && length) {
+      accumulator = array[--length];
+    }
+    while (length--) {
+      accumulator = iteratee(accumulator, array[length], length, array);
+    }
+    return accumulator;
+  }
 
-d3_selectionPrototype.classed = function(name, value) {
-  if (arguments.length < 2) {
+  /**
+   * A specialized version of `_.some` for arrays without support for iteratee
+   * shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} predicate The function invoked per iteration.
+   * @returns {boolean} Returns `true` if any element passes the predicate check,
+   *  else `false`.
+   */
+  function arraySome(array, predicate) {
+    var index = -1,
+        length = array == null ? 0 : array.length;
 
-    // For classed(string), return true only if the first node has the specified
-    // class or classes. Note that even if the browser supports DOMTokenList, it
-    // probably doesn't support it on SVG elements (which can be animated).
-    if (typeof name === "string") {
-      var node = this.node(),
-          n = (name = d3_selection_classes(name)).length,
-          i = -1;
-      if (value = node.classList) {
-        while (++i < n) if (!value.contains(name[i])) return false;
-      } else {
-        value = node.getAttribute("class");
-        while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
+    while (++index < length) {
+      if (predicate(array[index], index, array)) {
+        return true;
       }
-      return true;
     }
-
-    // For classed(object), the object specifies the names of classes to add or
-    // remove. The values may be functions that are evaluated for each element.
-    for (value in name) this.each(d3_selection_classed(value, name[value]));
-    return this;
+    return false;
   }
 
-  // Otherwise, both a name and a value are specified, and are handled as below.
-  return this.each(d3_selection_classed(name, value));
-};
-
-function d3_selection_classedRe(name) {
-  return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
-}
-
-function d3_selection_classes(name) {
-  return (name + "").trim().split(/^|\s+/);
-}
-
-// Multiple class names are allowed (e.g., "foo bar").
-function d3_selection_classed(name, value) {
-  name = d3_selection_classes(name).map(d3_selection_classedName);
-  var n = name.length;
+  /**
+   * Gets the size of an ASCII `string`.
+   *
+   * @private
+   * @param {string} string The string inspect.
+   * @returns {number} Returns the string size.
+   */
+  var asciiSize = baseProperty('length');
 
-  function classedConstant() {
-    var i = -1;
-    while (++i < n) name[i](this, value);
+  /**
+   * Converts an ASCII `string` to an array.
+   *
+   * @private
+   * @param {string} string The string to convert.
+   * @returns {Array} Returns the converted array.
+   */
+  function asciiToArray(string) {
+    return string.split('');
   }
 
-  // When the value is a function, the function is still evaluated only once per
-  // element even if there are multiple class names.
-  function classedFunction() {
-    var i = -1, x = value.apply(this, arguments);
-    while (++i < n) name[i](this, x);
+  /**
+   * Splits an ASCII `string` into an array of its words.
+   *
+   * @private
+   * @param {string} The string to inspect.
+   * @returns {Array} Returns the words of `string`.
+   */
+  function asciiWords(string) {
+    return string.match(reAsciiWord) || [];
   }
 
-  return typeof value === "function"
-      ? classedFunction
-      : classedConstant;
-}
+  /**
+   * The base implementation of methods like `_.findKey` and `_.findLastKey`,
+   * without support for iteratee shorthands, which iterates over `collection`
+   * using `eachFunc`.
+   *
+   * @private
+   * @param {Array|Object} collection The collection to inspect.
+   * @param {Function} predicate The function invoked per iteration.
+   * @param {Function} eachFunc The function to iterate over `collection`.
+   * @returns {*} Returns the found element or its key, else `undefined`.
+   */
+  function baseFindKey(collection, predicate, eachFunc) {
+    var result;
+    eachFunc(collection, function(value, key, collection) {
+      if (predicate(value, key, collection)) {
+        result = key;
+        return false;
+      }
+    });
+    return result;
+  }
 
-function d3_selection_classedName(name) {
-  var re = d3_selection_classedRe(name);
-  return function(node, value) {
-    if (c = node.classList) return value ? c.add(name) : c.remove(name);
-    var c = node.getAttribute("class") || "";
-    if (value) {
-      re.lastIndex = 0;
-      if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name));
-    } else {
-      node.setAttribute("class", d3_collapse(c.replace(re, " ")));
+  /**
+   * The base implementation of `_.findIndex` and `_.findLastIndex` without
+   * support for iteratee shorthands.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {Function} predicate The function invoked per iteration.
+   * @param {number} fromIndex The index to search from.
+   * @param {boolean} [fromRight] Specify iterating from right to left.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */
+  function baseFindIndex(array, predicate, fromIndex, fromRight) {
+    var length = array.length,
+        index = fromIndex + (fromRight ? 1 : -1);
+
+    while ((fromRight ? index-- : ++index < length)) {
+      if (predicate(array[index], index, array)) {
+        return index;
+      }
     }
-  };
-}
+    return -1;
+  }
 
-d3_selectionPrototype.style = function(name, value, priority) {
-  var n = arguments.length;
-  if (n < 3) {
+  /**
+   * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} value The value to search for.
+   * @param {number} fromIndex The index to search from.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */
+  function baseIndexOf(array, value, fromIndex) {
+    return value === value
+      ? strictIndexOf(array, value, fromIndex)
+      : baseFindIndex(array, baseIsNaN, fromIndex);
+  }
 
-    // For style(object) or style(object, string), the object specifies the
-    // names and values of the attributes to set or remove. The values may be
-    // functions that are evaluated for each element. The optional string
-    // specifies the priority.
-    if (typeof name !== "string") {
-      if (n < 2) value = "";
-      for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
-      return this;
-    }
+  /**
+   * This function is like `baseIndexOf` except that it accepts a comparator.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} value The value to search for.
+   * @param {number} fromIndex The index to search from.
+   * @param {Function} comparator The comparator invoked per element.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */
+  function baseIndexOfWith(array, value, fromIndex, comparator) {
+    var index = fromIndex - 1,
+        length = array.length;
 
-    // For style(string), return the computed style value for the first node.
-    if (n < 2) {
-      var node = this.node();
-      return d3_window(node).getComputedStyle(node, null).getPropertyValue(name);
+    while (++index < length) {
+      if (comparator(array[index], value)) {
+        return index;
+      }
     }
-
-    // For style(string, string) or style(string, function), use the default
-    // priority. The priority is ignored for style(string, null).
-    priority = "";
+    return -1;
   }
 
-  // Otherwise, a name, value and priority are specified, and handled as below.
-  return this.each(d3_selection_style(name, value, priority));
-};
+  /**
+   * The base implementation of `_.isNaN` without support for number objects.
+   *
+   * @private
+   * @param {*} value The value to check.
+   * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+   */
+  function baseIsNaN(value) {
+    return value !== value;
+  }
 
-function d3_selection_style(name, value, priority) {
+  /**
+   * The base implementation of `_.mean` and `_.meanBy` without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} array The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {number} Returns the mean.
+   */
+  function baseMean(array, iteratee) {
+    var length = array == null ? 0 : array.length;
+    return length ? (baseSum(array, iteratee) / length) : NAN;
+  }
 
-  // For style(name, null) or style(name, null, priority), remove the style
-  // property with the specified name. The priority is ignored.
-  function styleNull() {
-    this.style.removeProperty(name);
+  /**
+   * The base implementation of `_.property` without support for deep paths.
+   *
+   * @private
+   * @param {string} key The key of the property to get.
+   * @returns {Function} Returns the new accessor function.
+   */
+  function baseProperty(key) {
+    return function(object) {
+      return object == null ? undefined : object[key];
+    };
   }
 
-  // For style(name, string) or style(name, string, priority), set the style
-  // property with the specified name, using the specified priority.
-  function styleConstant() {
-    this.style.setProperty(name, value, priority);
+  /**
+   * The base implementation of `_.propertyOf` without support for deep paths.
+   *
+   * @private
+   * @param {Object} object The object to query.
+   * @returns {Function} Returns the new accessor function.
+   */
+  function basePropertyOf(object) {
+    return function(key) {
+      return object == null ? undefined : object[key];
+    };
   }
 
-  // For style(name, function) or style(name, function, priority), evaluate the
-  // function for each element, and set or remove the style property as
-  // appropriate. When setting, use the specified priority.
-  function styleFunction() {
-    var x = value.apply(this, arguments);
-    if (x == null) this.style.removeProperty(name);
-    else this.style.setProperty(name, x, priority);
+  /**
+   * The base implementation of `_.reduce` and `_.reduceRight`, without support
+   * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
+   *
+   * @private
+   * @param {Array|Object} collection The collection to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @param {*} accumulator The initial value.
+   * @param {boolean} initAccum Specify using the first or last element of
+   *  `collection` as the initial value.
+   * @param {Function} eachFunc The function to iterate over `collection`.
+   * @returns {*} Returns the accumulated value.
+   */
+  function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
+    eachFunc(collection, function(value, index, collection) {
+      accumulator = initAccum
+        ? (initAccum = false, value)
+        : iteratee(accumulator, value, index, collection);
+    });
+    return accumulator;
   }
 
-  return value == null
-      ? styleNull : (typeof value === "function"
-      ? styleFunction : styleConstant);
-}
+  /**
+   * The base implementation of `_.sortBy` which uses `comparer` to define the
+   * sort order of `array` and replaces criteria objects with their corresponding
+   * values.
+   *
+   * @private
+   * @param {Array} array The array to sort.
+   * @param {Function} comparer The function to define sort order.
+   * @returns {Array} Returns `array`.
+   */
+  function baseSortBy(array, comparer) {
+    var length = array.length;
 
-d3_selectionPrototype.property = function(name, value) {
-  if (arguments.length < 2) {
+    array.sort(comparer);
+    while (length--) {
+      array[length] = array[length].value;
+    }
+    return array;
+  }
 
-    // For property(string), return the property value for the first node.
-    if (typeof name === "string") return this.node()[name];
+  /**
+   * The base implementation of `_.sum` and `_.sumBy` without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} array The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {number} Returns the sum.
+   */
+  function baseSum(array, iteratee) {
+    var result,
+        index = -1,
+        length = array.length;
 
-    // For property(object), the object specifies the names and values of the
-    // properties to set or remove. The values may be functions that are
-    // evaluated for each element.
-    for (value in name) this.each(d3_selection_property(value, name[value]));
-    return this;
+    while (++index < length) {
+      var current = iteratee(array[index]);
+      if (current !== undefined) {
+        result = result === undefined ? current : (result + current);
+      }
+    }
+    return result;
   }
 
-  // Otherwise, both a name and a value are specified, and are handled as below.
-  return this.each(d3_selection_property(name, value));
-};
-
-function d3_selection_property(name, value) {
+  /**
+   * The base implementation of `_.times` without support for iteratee shorthands
+   * or max array length checks.
+   *
+   * @private
+   * @param {number} n The number of times to invoke `iteratee`.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {Array} Returns the array of results.
+   */
+  function baseTimes(n, iteratee) {
+    var index = -1,
+        result = Array(n);
 
-  // For property(name, null), remove the property with the specified name.
-  function propertyNull() {
-    delete this[name];
+    while (++index < n) {
+      result[index] = iteratee(index);
+    }
+    return result;
   }
 
-  // For property(name, string), set the property with the specified name.
-  function propertyConstant() {
-    this[name] = value;
+  /**
+   * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
+   * of key-value pairs for `object` corresponding to the property names of `props`.
+   *
+   * @private
+   * @param {Object} object The object to query.
+   * @param {Array} props The property names to get values for.
+   * @returns {Object} Returns the key-value pairs.
+   */
+  function baseToPairs(object, props) {
+    return arrayMap(props, function(key) {
+      return [key, object[key]];
+    });
   }
 
-  // For property(name, function), evaluate the function for each element, and
-  // set or remove the property as appropriate.
-  function propertyFunction() {
-    var x = value.apply(this, arguments);
-    if (x == null) delete this[name];
-    else this[name] = x;
+  /**
+   * The base implementation of `_.unary` without support for storing metadata.
+   *
+   * @private
+   * @param {Function} func The function to cap arguments for.
+   * @returns {Function} Returns the new capped function.
+   */
+  function baseUnary(func) {
+    return function(value) {
+      return func(value);
+    };
   }
 
-  return value == null
-      ? propertyNull : (typeof value === "function"
-      ? propertyFunction : propertyConstant);
-}
-
-d3_selectionPrototype.text = function(value) {
-  return arguments.length
-      ? this.each(typeof value === "function"
-      ? function() { var v = value.apply(this, arguments); this.textContent = v == null ? "" : v; } : value == null
-      ? function() { if (this.textContent !== "") this.textContent = ""; }
-      : function() { if (this.textContent !== value) this.textContent = value; })
-      : this.node().textContent;
-};
-
-d3_selectionPrototype.html = function(value) {
-  return arguments.length
-      ? this.each(typeof value === "function"
-      ? function() { var v = value.apply(this, arguments); this.innerHTML = v == null ? "" : v; } : value == null
-      ? function() { this.innerHTML = ""; }
-      : function() { this.innerHTML = value; })
-      : this.node().innerHTML;
-};
-
-d3_selectionPrototype.append = function(name) {
-  name = d3_selection_creator(name);
-  return this.select(function() {
-    return this.appendChild(name.apply(this, arguments));
-  });
-};
-
-function d3_selection_creator(name) {
-
-  function create() {
-    var document = this.ownerDocument,
-        namespace = this.namespaceURI;
-    return namespace
-        ? document.createElementNS(namespace, name)
-        : document.createElement(name);
+  /**
+   * The base implementation of `_.values` and `_.valuesIn` which creates an
+   * array of `object` property values corresponding to the property names
+   * of `props`.
+   *
+   * @private
+   * @param {Object} object The object to query.
+   * @param {Array} props The property names to get values for.
+   * @returns {Object} Returns the array of property values.
+   */
+  function baseValues(object, props) {
+    return arrayMap(props, function(key) {
+      return object[key];
+    });
   }
 
-  function createNS() {
-    return this.ownerDocument.createElementNS(name.space, name.local);
+  /**
+   * Checks if a `cache` value for `key` exists.
+   *
+   * @private
+   * @param {Object} cache The cache to query.
+   * @param {string} key The key of the entry to check.
+   * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+   */
+  function cacheHas(cache, key) {
+    return cache.has(key);
   }
 
-  return typeof name === "function" ? name
-      : (name = d3.ns.qualify(name)).local ? createNS
-      : create;
-}
-
-d3_selectionPrototype.insert = function(name, before) {
-  name = d3_selection_creator(name);
-  before = d3_selection_selector(before);
-  return this.select(function() {
-    return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
-  });
-};
-
-// TODO remove(selector)?
-// TODO remove(node)?
-// TODO remove(function)?
-d3_selectionPrototype.remove = function() {
-  return this.each(d3_selectionRemove);
-};
+  /**
+   * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
+   * that is not found in the character symbols.
+   *
+   * @private
+   * @param {Array} strSymbols The string symbols to inspect.
+   * @param {Array} chrSymbols The character symbols to find.
+   * @returns {number} Returns the index of the first unmatched string symbol.
+   */
+  function charsStartIndex(strSymbols, chrSymbols) {
+    var index = -1,
+        length = strSymbols.length;
 
-function d3_selectionRemove() {
-  var parent = this.parentNode;
-  if (parent) parent.removeChild(this);
-}
+    while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
+    return index;
+  }
 
-d3_selectionPrototype.data = function(value, key) {
-  var i = -1,
-      n = this.length,
-      group,
-      node;
+  /**
+   * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
+   * that is not found in the character symbols.
+   *
+   * @private
+   * @param {Array} strSymbols The string symbols to inspect.
+   * @param {Array} chrSymbols The character symbols to find.
+   * @returns {number} Returns the index of the last unmatched string symbol.
+   */
+  function charsEndIndex(strSymbols, chrSymbols) {
+    var index = strSymbols.length;
 
-  // If no value is specified, return the first value.
-  if (!arguments.length) {
-    value = new Array(n = (group = this[0]).length);
-    while (++i < n) {
-      if (node = group[i]) {
-        value[i] = node.__data__;
-      }
-    }
-    return value;
+    while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
+    return index;
   }
 
-  function bind(group, groupData) {
-    var i,
-        n = group.length,
-        m = groupData.length,
-        n0 = Math.min(n, m),
-        updateNodes = new Array(m),
-        enterNodes = new Array(m),
-        exitNodes = new Array(n),
-        node,
-        nodeData;
-
-    if (key) {
-      var nodeByKeyValue = new d3_Map,
-          keyValues = new Array(n),
-          keyValue;
-
-      for (i = -1; ++i < n;) {
-        if (nodeByKeyValue.has(keyValue = key.call(node = group[i], node.__data__, i))) {
-          exitNodes[i] = node; // duplicate selection key
-        } else {
-          nodeByKeyValue.set(keyValue, node);
-        }
-        keyValues[i] = keyValue;
-      }
-
-      for (i = -1; ++i < m;) {
-        if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) {
-          enterNodes[i] = d3_selection_dataNode(nodeData);
-        } else if (node !== true) { // no duplicate data key
-          updateNodes[i] = node;
-          node.__data__ = nodeData;
-        }
-        nodeByKeyValue.set(keyValue, true);
-      }
+  /**
+   * Gets the number of `placeholder` occurrences in `array`.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} placeholder The placeholder to search for.
+   * @returns {number} Returns the placeholder count.
+   */
+  function countHolders(array, placeholder) {
+    var length = array.length,
+        result = 0;
 
-      for (i = -1; ++i < n;) {
-        if (nodeByKeyValue.get(keyValues[i]) !== true) {
-          exitNodes[i] = group[i];
-        }
-      }
-    } else {
-      for (i = -1; ++i < n0;) {
-        node = group[i];
-        nodeData = groupData[i];
-        if (node) {
-          node.__data__ = nodeData;
-          updateNodes[i] = node;
-        } else {
-          enterNodes[i] = d3_selection_dataNode(nodeData);
-        }
-      }
-      for (; i < m; ++i) {
-        enterNodes[i] = d3_selection_dataNode(groupData[i]);
-      }
-      for (; i < n; ++i) {
-        exitNodes[i] = group[i];
+    while (length--) {
+      if (array[length] === placeholder) {
+        ++result;
       }
     }
+    return result;
+  }
 
-    enterNodes.update
-        = updateNodes;
+  /**
+   * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
+   * letters to basic Latin letters.
+   *
+   * @private
+   * @param {string} letter The matched letter to deburr.
+   * @returns {string} Returns the deburred letter.
+   */
+  var deburrLetter = basePropertyOf(deburredLetters);
 
-    enterNodes.parentNode
-        = updateNodes.parentNode
-        = exitNodes.parentNode
-        = group.parentNode;
+  /**
+   * Used by `_.escape` to convert characters to HTML entities.
+   *
+   * @private
+   * @param {string} chr The matched character to escape.
+   * @returns {string} Returns the escaped character.
+   */
+  var escapeHtmlChar = basePropertyOf(htmlEscapes);
 
-    enter.push(enterNodes);
-    update.push(updateNodes);
-    exit.push(exitNodes);
+  /**
+   * Used by `_.template` to escape characters for inclusion in compiled string literals.
+   *
+   * @private
+   * @param {string} chr The matched character to escape.
+   * @returns {string} Returns the escaped character.
+   */
+  function escapeStringChar(chr) {
+    return '\\' + stringEscapes[chr];
   }
 
-  var enter = d3_selection_enter([]),
-      update = d3_selection([]),
-      exit = d3_selection([]);
-
-  if (typeof value === "function") {
-    while (++i < n) {
-      bind(group = this[i], value.call(group, group.parentNode.__data__, i));
-    }
-  } else {
-    while (++i < n) {
-      bind(group = this[i], value);
-    }
+  /**
+   * Gets the value at `key` of `object`.
+   *
+   * @private
+   * @param {Object} [object] The object to query.
+   * @param {string} key The key of the property to get.
+   * @returns {*} Returns the property value.
+   */
+  function getValue(object, key) {
+    return object == null ? undefined : object[key];
   }
 
-  update.enter = function() { return enter; };
-  update.exit = function() { return exit; };
-  return update;
-};
-
-function d3_selection_dataNode(data) {
-  return {__data__: data};
-}
-
-d3_selectionPrototype.datum = function(value) {
-  return arguments.length
-      ? this.property("__data__", value)
-      : this.property("__data__");
-};
-
-d3_selectionPrototype.filter = function(filter) {
-  var subgroups = [],
-      subgroup,
-      group,
-      node;
-
-  if (typeof filter !== "function") filter = d3_selection_filter(filter);
-
-  for (var j = 0, m = this.length; j < m; j++) {
-    subgroups.push(subgroup = []);
-    subgroup.parentNode = (group = this[j]).parentNode;
-    for (var i = 0, n = group.length; i < n; i++) {
-      if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
-        subgroup.push(node);
-      }
-    }
+  /**
+   * Checks if `string` contains Unicode symbols.
+   *
+   * @private
+   * @param {string} string The string to inspect.
+   * @returns {boolean} Returns `true` if a symbol is found, else `false`.
+   */
+  function hasUnicode(string) {
+    return reHasUnicode.test(string);
   }
 
-  return d3_selection(subgroups);
-};
-
-function d3_selection_filter(selector) {
-  return function() {
-    return d3_selectMatches(this, selector);
-  };
-}
-
-d3_selectionPrototype.order = function() {
-  for (var j = -1, m = this.length; ++j < m;) {
-    for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
-      if (node = group[i]) {
-        if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
-        next = node;
-      }
-    }
+  /**
+   * Checks if `string` contains a word composed of Unicode symbols.
+   *
+   * @private
+   * @param {string} string The string to inspect.
+   * @returns {boolean} Returns `true` if a word is found, else `false`.
+   */
+  function hasUnicodeWord(string) {
+    return reHasUnicodeWord.test(string);
   }
-  return this;
-};
-
-d3_selectionPrototype.sort = function(comparator) {
-  comparator = d3_selection_sortComparator.apply(this, arguments);
-  for (var j = -1, m = this.length; ++j < m;) this[j].sort(comparator);
-  return this.order();
-};
-
-function d3_selection_sortComparator(comparator) {
-  if (!arguments.length) comparator = d3_ascending;
-  return function(a, b) {
-    return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
-  };
-}
 
-d3_selectionPrototype.each = function(callback) {
-  return d3_selection_each(this, function(node, i, j) {
-    callback.call(node, node.__data__, i, j);
-  });
-};
+  /**
+   * Converts `iterator` to an array.
+   *
+   * @private
+   * @param {Object} iterator The iterator to convert.
+   * @returns {Array} Returns the converted array.
+   */
+  function iteratorToArray(iterator) {
+    var data,
+        result = [];
 
-function d3_selection_each(groups, callback) {
-  for (var j = 0, m = groups.length; j < m; j++) {
-    for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
-      if (node = group[i]) callback(node, i, j);
+    while (!(data = iterator.next()).done) {
+      result.push(data.value);
     }
+    return result;
   }
-  return groups;
-}
-
-d3_selectionPrototype.call = function(callback) {
-  var args = d3_array(arguments);
-  callback.apply(args[0] = this, args);
-  return this;
-};
 
-d3_selectionPrototype.empty = function() {
-  return !this.node();
-};
+  /**
+   * Converts `map` to its key-value pairs.
+   *
+   * @private
+   * @param {Object} map The map to convert.
+   * @returns {Array} Returns the key-value pairs.
+   */
+  function mapToArray(map) {
+    var index = -1,
+        result = Array(map.size);
 
-d3_selectionPrototype.node = function() {
-  for (var j = 0, m = this.length; j < m; j++) {
-    for (var group = this[j], i = 0, n = group.length; i < n; i++) {
-      var node = group[i];
-      if (node) return node;
-    }
+    map.forEach(function(value, key) {
+      result[++index] = [key, value];
+    });
+    return result;
   }
-  return null;
-};
-
-d3_selectionPrototype.size = function() {
-  var n = 0;
-  d3_selection_each(this, function() { ++n; });
-  return n;
-};
-
-function d3_selection_enter(selection) {
-  d3_subclass(selection, d3_selection_enterPrototype);
-  return selection;
-}
-
-var d3_selection_enterPrototype = [];
-
-d3.selection.enter = d3_selection_enter;
-d3.selection.enter.prototype = d3_selection_enterPrototype;
-
-d3_selection_enterPrototype.append = d3_selectionPrototype.append;
-d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
-d3_selection_enterPrototype.node = d3_selectionPrototype.node;
-d3_selection_enterPrototype.call = d3_selectionPrototype.call;
-d3_selection_enterPrototype.size = d3_selectionPrototype.size;
 
+  /**
+   * Creates a unary function that invokes `func` with its argument transformed.
+   *
+   * @private
+   * @param {Function} func The function to wrap.
+   * @param {Function} transform The argument transform.
+   * @returns {Function} Returns the new function.
+   */
+  function overArg(func, transform) {
+    return function(arg) {
+      return func(transform(arg));
+    };
+  }
 
-d3_selection_enterPrototype.select = function(selector) {
-  var subgroups = [],
-      subgroup,
-      subnode,
-      upgroup,
-      group,
-      node;
+  /**
+   * Replaces all `placeholder` elements in `array` with an internal placeholder
+   * and returns an array of their indexes.
+   *
+   * @private
+   * @param {Array} array The array to modify.
+   * @param {*} placeholder The placeholder to replace.
+   * @returns {Array} Returns the new array of placeholder indexes.
+   */
+  function replaceHolders(array, placeholder) {
+    var index = -1,
+        length = array.length,
+        resIndex = 0,
+        result = [];
 
-  for (var j = -1, m = this.length; ++j < m;) {
-    upgroup = (group = this[j]).update;
-    subgroups.push(subgroup = []);
-    subgroup.parentNode = group.parentNode;
-    for (var i = -1, n = group.length; ++i < n;) {
-      if (node = group[i]) {
-        subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j));
-        subnode.__data__ = node.__data__;
-      } else {
-        subgroup.push(null);
+    while (++index < length) {
+      var value = array[index];
+      if (value === placeholder || value === PLACEHOLDER) {
+        array[index] = PLACEHOLDER;
+        result[resIndex++] = index;
       }
     }
+    return result;
   }
 
-  return d3_selection(subgroups);
-};
-
-d3_selection_enterPrototype.insert = function(name, before) {
-  if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
-  return d3_selectionPrototype.insert.call(this, name, before);
-};
-
-function d3_selection_enterInsertBefore(enter) {
-  var i0, j0;
-  return function(d, i, j) {
-    var group = enter[j].update,
-        n = group.length,
-        node;
-    if (j != j0) j0 = j, i0 = 0;
-    if (i >= i0) i0 = i + 1;
-    while (!(node = group[i0]) && ++i0 < n);
-    return node;
-  };
-}
-
-// TODO fast singleton implementation?
-d3.select = function(node) {
-  var group;
-  if (typeof node === "string") {
-    group = [d3_select(node, d3_document)];
-    group.parentNode = d3_document.documentElement;
-  } else {
-    group = [node];
-    group.parentNode = d3_documentElement(node);
-  }
-  return d3_selection([group]);
-};
+  /**
+   * Converts `set` to an array of its values.
+   *
+   * @private
+   * @param {Object} set The set to convert.
+   * @returns {Array} Returns the values.
+   */
+  function setToArray(set) {
+    var index = -1,
+        result = Array(set.size);
 
-d3.selectAll = function(nodes) {
-  var group;
-  if (typeof nodes === "string") {
-    group = d3_array(d3_selectAll(nodes, d3_document));
-    group.parentNode = d3_document.documentElement;
-  } else {
-    group = nodes;
-    group.parentNode = null;
+    set.forEach(function(value) {
+      result[++index] = value;
+    });
+    return result;
   }
-  return d3_selection([group]);
-};
 
-d3_selectionPrototype.on = function(type, listener, capture) {
-  var n = arguments.length;
-  if (n < 3) {
-
-    // For on(object) or on(object, boolean), the object specifies the event
-    // types and listeners to add or remove. The optional boolean specifies
-    // whether the listener captures events.
-    if (typeof type !== "string") {
-      if (n < 2) listener = false;
-      for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
-      return this;
-    }
-
-    // For on(string), return the listener for the first node.
-    if (n < 2) return (n = this.node()["__on" + type]) && n._;
+  /**
+   * Converts `set` to its value-value pairs.
+   *
+   * @private
+   * @param {Object} set The set to convert.
+   * @returns {Array} Returns the value-value pairs.
+   */
+  function setToPairs(set) {
+    var index = -1,
+        result = Array(set.size);
 
-    // For on(string, function), use the default capture.
-    capture = false;
+    set.forEach(function(value) {
+      result[++index] = [value, value];
+    });
+    return result;
   }
 
-  // Otherwise, a type, listener and capture are specified, and handled as below.
-  return this.each(d3_selection_on(type, listener, capture));
-};
-
-function d3_selection_on(type, listener, capture) {
-  var name = "__on" + type,
-      i = type.indexOf("."),
-      wrap = d3_selection_onListener;
-
-  if (i > 0) type = type.slice(0, i);
-  var filter = d3_selection_onFilters.get(type);
-  if (filter) type = filter, wrap = d3_selection_onFilter;
+  /**
+   * A specialized version of `_.indexOf` which performs strict equality
+   * comparisons of values, i.e. `===`.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} value The value to search for.
+   * @param {number} fromIndex The index to search from.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */
+  function strictIndexOf(array, value, fromIndex) {
+    var index = fromIndex - 1,
+        length = array.length;
 
-  function onRemove() {
-    var l = this[name];
-    if (l) {
-      this.removeEventListener(type, l, l.$);
-      delete this[name];
+    while (++index < length) {
+      if (array[index] === value) {
+        return index;
+      }
     }
+    return -1;
   }
 
-  function onAdd() {
-    var l = wrap(listener, d3_array(arguments));
-    if (typeof Raven !== 'undefined') l = Raven.wrap(l);
-    onRemove.call(this);
-    this.addEventListener(type, this[name] = l, l.$ = capture);
-    l._ = listener;
-  }
-
-  function removeAll() {
-    var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"),
-        match;
-    for (var name in this) {
-      if (match = name.match(re)) {
-        var l = this[name];
-        this.removeEventListener(match[1], l, l.$);
-        delete this[name];
+  /**
+   * A specialized version of `_.lastIndexOf` which performs strict equality
+   * comparisons of values, i.e. `===`.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} value The value to search for.
+   * @param {number} fromIndex The index to search from.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */
+  function strictLastIndexOf(array, value, fromIndex) {
+    var index = fromIndex + 1;
+    while (index--) {
+      if (array[index] === value) {
+        return index;
       }
     }
+    return index;
   }
 
-  return i
-      ? listener ? onAdd : onRemove
-      : listener ? d3_noop : removeAll;
-}
+  /**
+   * Gets the number of symbols in `string`.
+   *
+   * @private
+   * @param {string} string The string to inspect.
+   * @returns {number} Returns the string size.
+   */
+  function stringSize(string) {
+    return hasUnicode(string)
+      ? unicodeSize(string)
+      : asciiSize(string);
+  }
 
-var d3_selection_onFilters = d3.map({
-  mouseenter: "mouseover",
-  mouseleave: "mouseout"
-});
-
-if (d3_document) {
-  d3_selection_onFilters.forEach(function(k) {
-    if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
-  });
-}
+  /**
+   * Converts `string` to an array.
+   *
+   * @private
+   * @param {string} string The string to convert.
+   * @returns {Array} Returns the converted array.
+   */
+  function stringToArray(string) {
+    return hasUnicode(string)
+      ? unicodeToArray(string)
+      : asciiToArray(string);
+  }
 
-function d3_selection_onListener(listener, argumentz) {
-  return function(e) {
-    var o = d3.event; // Events can be reentrant (e.g., focus).
-    d3.event = e;
-    argumentz[0] = this.__data__;
-    try {
-      listener.apply(this, argumentz);
-    } finally {
-      d3.event = o;
-    }
-  };
-}
+  /**
+   * Used by `_.unescape` to convert HTML entities to characters.
+   *
+   * @private
+   * @param {string} chr The matched character to unescape.
+   * @returns {string} Returns the unescaped character.
+   */
+  var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
 
-function d3_selection_onFilter(listener, argumentz) {
-  var l = d3_selection_onListener(listener, argumentz);
-  return function(e) {
-    var target = this, related = e.relatedTarget;
-    if (!related || (related !== target && !(related.compareDocumentPosition(target) & 8))) {
-      l.call(target, e);
+  /**
+   * Gets the size of a Unicode `string`.
+   *
+   * @private
+   * @param {string} string The string inspect.
+   * @returns {number} Returns the string size.
+   */
+  function unicodeSize(string) {
+    var result = reUnicode.lastIndex = 0;
+    while (reUnicode.test(string)) {
+      ++result;
     }
-  };
-}
-
-var d3_event_dragSelect,
-    d3_event_dragId = 0;
-
-function d3_event_dragSuppress(node) {
-  var name = ".dragsuppress-" + ++d3_event_dragId,
-      click = "click" + name,
-      w = d3.select(d3_window(node))
-          .on("touchmove" + name, d3_eventPreventDefault)
-          .on("dragstart" + name, d3_eventPreventDefault)
-          .on("selectstart" + name, d3_eventPreventDefault);
-
-  if (d3_event_dragSelect == null) {
-    d3_event_dragSelect = "onselectstart" in node ? false
-        : d3_vendorSymbol(node.style, "userSelect");
+    return result;
   }
 
-  if (d3_event_dragSelect) {
-    var style = d3_documentElement(node).style,
-        select = style[d3_event_dragSelect];
-    style[d3_event_dragSelect] = "none";
+  /**
+   * Converts a Unicode `string` to an array.
+   *
+   * @private
+   * @param {string} string The string to convert.
+   * @returns {Array} Returns the converted array.
+   */
+  function unicodeToArray(string) {
+    return string.match(reUnicode) || [];
   }
 
-  return function(suppressClick) {
-    w.on(name, null);
-    if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
-    if (suppressClick) { // suppress the next click, but only if it’s immediate
-      var off = function() { w.on(click, null); };
-      w.on(click, function() { d3_eventCancel(); off(); }, true);
-      setTimeout(off, 0);
-    }
-  };
-}
-
-d3.mouse = function(container) {
-  return d3_mousePoint(container, d3_eventSource());
-};
-
-// https://bugs.webkit.org/show_bug.cgi?id=44083
-var d3_mouse_bug44083 = this.navigator && /WebKit/.test(this.navigator.userAgent) ? -1 : 0;
-
-function d3_mousePoint(container, e) {
-  if (e.changedTouches) e = e.changedTouches[0];
-  var svg = container.ownerSVGElement || container;
-  if (svg.createSVGPoint) {
-    var point = svg.createSVGPoint();
-    if (d3_mouse_bug44083 < 0) {
-      var window = d3_window(container);
-      if (window.scrollX || window.scrollY) {
-        svg = d3.select("body").append("svg").style({
-          position: "absolute",
-          top: 0,
-          left: 0,
-          margin: 0,
-          padding: 0,
-          border: "none"
-        }, "important");
-        var ctm = svg[0][0].getScreenCTM();
-        d3_mouse_bug44083 = !(ctm.f || ctm.e);
-        svg.remove();
-      }
-    }
-    if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY;
-    else point.x = e.clientX, point.y = e.clientY;
-    point = point.matrixTransform(container.getScreenCTM().inverse());
-    return [point.x, point.y];
+  /**
+   * Splits a Unicode `string` into an array of its words.
+   *
+   * @private
+   * @param {string} The string to inspect.
+   * @returns {Array} Returns the words of `string`.
+   */
+  function unicodeWords(string) {
+    return string.match(reUnicodeWord) || [];
   }
-  var rect = container.getBoundingClientRect();
-  return [e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop];
-};
 
-d3.touches = function(container, touches) {
-  if (arguments.length < 2) touches = d3_eventSource().touches;
-  return touches ? d3_array(touches).map(function(touch) {
-    var point = d3_mousePoint(container, touch);
-    point.identifier = touch.identifier;
-    return point;
-  }) : [];
-};
-var ε = 1e-6,
-    ε2 = ε * ε,
-    π = Math.PI,
-    τ = 2 * π,
-    τε = τ - ε,
-    halfπ = π / 2,
-    d3_radians = π / 180,
-    d3_degrees = 180 / π;
+  /*--------------------------------------------------------------------------*/
 
-function d3_sgn(x) {
-  return x > 0 ? 1 : x < 0 ? -1 : 0;
-}
+  /**
+   * Create a new pristine `lodash` function using the `context` object.
+   *
+   * @static
+   * @memberOf _
+   * @since 1.1.0
+   * @category Util
+   * @param {Object} [context=root] The context object.
+   * @returns {Function} Returns a new `lodash` function.
+   * @example
+   *
+   * _.mixin({ 'foo': _.constant('foo') });
+   *
+   * var lodash = _.runInContext();
+   * lodash.mixin({ 'bar': lodash.constant('bar') });
+   *
+   * _.isFunction(_.foo);
+   * // => true
+   * _.isFunction(_.bar);
+   * // => false
+   *
+   * lodash.isFunction(lodash.foo);
+   * // => false
+   * lodash.isFunction(lodash.bar);
+   * // => true
+   *
+   * // Create a suped-up `defer` in Node.js.
+   * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+   */
+  var runInContext = (function runInContext(context) {
+    context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
+
+    /** Built-in constructor references. */
+    var Array = context.Array,
+        Date = context.Date,
+        Error = context.Error,
+        Function = context.Function,
+        Math = context.Math,
+        Object = context.Object,
+        RegExp = context.RegExp,
+        String = context.String,
+        TypeError = context.TypeError;
+
+    /** Used for built-in method references. */
+    var arrayProto = Array.prototype,
+        funcProto = Function.prototype,
+        objectProto = Object.prototype;
+
+    /** Used to detect overreaching core-js shims. */
+    var coreJsData = context['__core-js_shared__'];
+
+    /** Used to resolve the decompiled source of functions. */
+    var funcToString = funcProto.toString;
+
+    /** Used to check objects for own properties. */
+    var hasOwnProperty = objectProto.hasOwnProperty;
+
+    /** Used to generate unique IDs. */
+    var idCounter = 0;
+
+    /** Used to detect methods masquerading as native. */
+    var maskSrcKey = (function() {
+      var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
+      return uid ? ('Symbol(src)_1.' + uid) : '';
+    }());
 
-// Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
-// the 3D cross product in a quadrant I Cartesian coordinate system (+x is
-// right, +y is up). Returns a positive value if ABC is counter-clockwise,
-// negative if clockwise, and zero if the points are collinear.
-function d3_cross2d(a, b, c) {
-  return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
-}
+    /**
+     * Used to resolve the
+     * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+     * of values.
+     */
+    var nativeObjectToString = objectProto.toString;
+
+    /** Used to infer the `Object` constructor. */
+    var objectCtorString = funcToString.call(Object);
+
+    /** Used to restore the original `_` reference in `_.noConflict`. */
+    var oldDash = root._;
+
+    /** Used to detect if a method is native. */
+    var reIsNative = RegExp('^' +
+      funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+      .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+    );
+
+    /** Built-in value references. */
+    var Buffer = moduleExports ? context.Buffer : undefined,
+        Symbol = context.Symbol,
+        Uint8Array = context.Uint8Array,
+        allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
+        getPrototype = overArg(Object.getPrototypeOf, Object),
+        objectCreate = Object.create,
+        propertyIsEnumerable = objectProto.propertyIsEnumerable,
+        splice = arrayProto.splice,
+        spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
+        symIterator = Symbol ? Symbol.iterator : undefined,
+        symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+    var defineProperty = (function() {
+      try {
+        var func = getNative(Object, 'defineProperty');
+        func({}, '', {});
+        return func;
+      } catch (e) {}
+    }());
+
+    /** Mocked built-ins. */
+    var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
+        ctxNow = Date && Date.now !== root.Date.now && Date.now,
+        ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
+
+    /* Built-in method references for those with the same name as other `lodash` methods. */
+    var nativeCeil = Math.ceil,
+        nativeFloor = Math.floor,
+        nativeGetSymbols = Object.getOwnPropertySymbols,
+        nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
+        nativeIsFinite = context.isFinite,
+        nativeJoin = arrayProto.join,
+        nativeKeys = overArg(Object.keys, Object),
+        nativeMax = Math.max,
+        nativeMin = Math.min,
+        nativeNow = Date.now,
+        nativeParseInt = context.parseInt,
+        nativeRandom = Math.random,
+        nativeReverse = arrayProto.reverse;
+
+    /* Built-in method references that are verified to be native. */
+    var DataView = getNative(context, 'DataView'),
+        Map = getNative(context, 'Map'),
+        Promise = getNative(context, 'Promise'),
+        Set = getNative(context, 'Set'),
+        WeakMap = getNative(context, 'WeakMap'),
+        nativeCreate = getNative(Object, 'create');
+
+    /** Used to store function metadata. */
+    var metaMap = WeakMap && new WeakMap;
+
+    /** Used to lookup unminified function names. */
+    var realNames = {};
+
+    /** Used to detect maps, sets, and weakmaps. */
+    var dataViewCtorString = toSource(DataView),
+        mapCtorString = toSource(Map),
+        promiseCtorString = toSource(Promise),
+        setCtorString = toSource(Set),
+        weakMapCtorString = toSource(WeakMap);
+
+    /** Used to convert symbols to primitives and strings. */
+    var symbolProto = Symbol ? Symbol.prototype : undefined,
+        symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
+        symbolToString = symbolProto ? symbolProto.toString : undefined;
+
+    /*------------------------------------------------------------------------*/
 
-function d3_acos(x) {
-  return x > 1 ? 0 : x < -1 ? π : Math.acos(x);
-}
+    /**
+     * Creates a `lodash` object which wraps `value` to enable implicit method
+     * chain sequences. Methods that operate on and return arrays, collections,
+     * and functions can be chained together. Methods that retrieve a single value
+     * or may return a primitive value will automatically end the chain sequence
+     * and return the unwrapped value. Otherwise, the value must be unwrapped
+     * with `_#value`.
+     *
+     * Explicit chain sequences, which must be unwrapped with `_#value`, may be
+     * enabled using `_.chain`.
+     *
+     * The execution of chained methods is lazy, that is, it's deferred until
+     * `_#value` is implicitly or explicitly called.
+     *
+     * Lazy evaluation allows several methods to support shortcut fusion.
+     * Shortcut fusion is an optimization to merge iteratee calls; this avoids
+     * the creation of intermediate arrays and can greatly reduce the number of
+     * iteratee executions. Sections of a chain sequence qualify for shortcut
+     * fusion if the section is applied to an array of at least `200` elements
+     * and any iteratees accept only one argument. The heuristic for whether a
+     * section qualifies for shortcut fusion is subject to change.
+     *
+     * Chaining is supported in custom builds as long as the `_#value` method is
+     * directly or indirectly included in the build.
+     *
+     * In addition to lodash methods, wrappers have `Array` and `String` methods.
+     *
+     * The wrapper `Array` methods are:
+     * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
+     *
+     * The wrapper `String` methods are:
+     * `replace` and `split`
+     *
+     * The wrapper methods that support shortcut fusion are:
+     * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
+     * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
+     * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
+     *
+     * The chainable wrapper methods are:
+     * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
+     * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
+     * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
+     * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
+     * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
+     * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
+     * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
+     * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
+     * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
+     * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
+     * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
+     * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
+     * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
+     * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
+     * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
+     * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
+     * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
+     * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
+     * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
+     * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
+     * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
+     * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
+     * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
+     * `zipObject`, `zipObjectDeep`, and `zipWith`
+     *
+     * The wrapper methods that are **not** chainable by default are:
+     * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
+     * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
+     * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
+     * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
+     * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
+     * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
+     * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
+     * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
+     * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
+     * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
+     * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
+     * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
+     * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
+     * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
+     * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
+     * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
+     * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
+     * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
+     * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
+     * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
+     * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
+     * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
+     * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
+     * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
+     * `upperFirst`, `value`, and `words`
+     *
+     * @name _
+     * @constructor
+     * @category Seq
+     * @param {*} value The value to wrap in a `lodash` instance.
+     * @returns {Object} Returns the new `lodash` wrapper instance.
+     * @example
+     *
+     * function square(n) {
+     *   return n * n;
+     * }
+     *
+     * var wrapped = _([1, 2, 3]);
+     *
+     * // Returns an unwrapped value.
+     * wrapped.reduce(_.add);
+     * // => 6
+     *
+     * // Returns a wrapped value.
+     * var squares = wrapped.map(square);
+     *
+     * _.isArray(squares);
+     * // => false
+     *
+     * _.isArray(squares.value());
+     * // => true
+     */
+    function lodash(value) {
+      if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
+        if (value instanceof LodashWrapper) {
+          return value;
+        }
+        if (hasOwnProperty.call(value, '__wrapped__')) {
+          return wrapperClone(value);
+        }
+      }
+      return new LodashWrapper(value);
+    }
 
-function d3_asin(x) {
-  return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);
-}
+    /**
+     * The base implementation of `_.create` without support for assigning
+     * properties to the created object.
+     *
+     * @private
+     * @param {Object} proto The object to inherit from.
+     * @returns {Object} Returns the new object.
+     */
+    var baseCreate = (function() {
+      function object() {}
+      return function(proto) {
+        if (!isObject(proto)) {
+          return {};
+        }
+        if (objectCreate) {
+          return objectCreate(proto);
+        }
+        object.prototype = proto;
+        var result = new object;
+        object.prototype = undefined;
+        return result;
+      };
+    }());
 
-function d3_sinh(x) {
-  return ((x = Math.exp(x)) - 1 / x) / 2;
-}
+    /**
+     * The function whose prototype chain sequence wrappers inherit from.
+     *
+     * @private
+     */
+    function baseLodash() {
+      // No operation performed.
+    }
 
-function d3_cosh(x) {
-  return ((x = Math.exp(x)) + 1 / x) / 2;
-}
+    /**
+     * The base constructor for creating `lodash` wrapper objects.
+     *
+     * @private
+     * @param {*} value The value to wrap.
+     * @param {boolean} [chainAll] Enable explicit method chain sequences.
+     */
+    function LodashWrapper(value, chainAll) {
+      this.__wrapped__ = value;
+      this.__actions__ = [];
+      this.__chain__ = !!chainAll;
+      this.__index__ = 0;
+      this.__values__ = undefined;
+    }
 
-function d3_tanh(x) {
-  return ((x = Math.exp(2 * x)) - 1) / (x + 1);
-}
+    /**
+     * By default, the template delimiters used by lodash are like those in
+     * embedded Ruby (ERB). Change the following template settings to use
+     * alternative delimiters.
+     *
+     * @static
+     * @memberOf _
+     * @type {Object}
+     */
+    lodash.templateSettings = {
+
+      /**
+       * Used to detect `data` property values to be HTML-escaped.
+       *
+       * @memberOf _.templateSettings
+       * @type {RegExp}
+       */
+      'escape': reEscape,
+
+      /**
+       * Used to detect code to be evaluated.
+       *
+       * @memberOf _.templateSettings
+       * @type {RegExp}
+       */
+      'evaluate': reEvaluate,
+
+      /**
+       * Used to detect `data` property values to inject.
+       *
+       * @memberOf _.templateSettings
+       * @type {RegExp}
+       */
+      'interpolate': reInterpolate,
+
+      /**
+       * Used to reference the data object in the template text.
+       *
+       * @memberOf _.templateSettings
+       * @type {string}
+       */
+      'variable': '',
+
+      /**
+       * Used to import variables into the compiled template.
+       *
+       * @memberOf _.templateSettings
+       * @type {Object}
+       */
+      'imports': {
+
+        /**
+         * A reference to the `lodash` function.
+         *
+         * @memberOf _.templateSettings.imports
+         * @type {Function}
+         */
+        '_': lodash
+      }
+    };
 
-function d3_haversin(x) {
-  return (x = Math.sin(x / 2)) * x;
-}
+    // Ensure wrappers are instances of `baseLodash`.
+    lodash.prototype = baseLodash.prototype;
+    lodash.prototype.constructor = lodash;
 
-var ρ = Math.SQRT2,
-    ρ2 = 2,
-    ρ4 = 4;
+    LodashWrapper.prototype = baseCreate(baseLodash.prototype);
+    LodashWrapper.prototype.constructor = LodashWrapper;
 
-// p0 = [ux0, uy0, w0]
-// p1 = [ux1, uy1, w1]
-d3.interpolateZoom = function(p0, p1) {
-  var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
-      ux1 = p1[0], uy1 = p1[1], w1 = p1[2];
+    /*------------------------------------------------------------------------*/
 
-  var dx = ux1 - ux0,
-      dy = uy1 - uy0,
-      d2 = dx * dx + dy * dy,
-      d1 = Math.sqrt(d2),
-      b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1),
-      b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1),
-      r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
-      r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1),
-      dr = r1 - r0,
-      S = (dr || Math.log(w1 / w0)) / ρ;
-
-  function interpolate(t) {
-    var s = t * S;
-    if (dr) {
-      // General case.
-      var coshr0 = d3_cosh(r0),
-          u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));
-      return [
-        ux0 + u * dx,
-        uy0 + u * dy,
-        w0 * coshr0 / d3_cosh(ρ * s + r0)
-      ];
+    /**
+     * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+     *
+     * @private
+     * @constructor
+     * @param {*} value The value to wrap.
+     */
+    function LazyWrapper(value) {
+      this.__wrapped__ = value;
+      this.__actions__ = [];
+      this.__dir__ = 1;
+      this.__filtered__ = false;
+      this.__iteratees__ = [];
+      this.__takeCount__ = MAX_ARRAY_LENGTH;
+      this.__views__ = [];
     }
-    // Special case for u0 ~= u1.
-    return [
-      ux0 + t * dx,
-      uy0 + t * dy,
-      w0 * Math.exp(ρ * s)
-    ];
-  }
-
-  interpolate.duration = S * 1000;
-
-  return interpolate;
-};
 
-d3.behavior.zoom = function() {
-  var view = {x: 0, y: 0, k: 1},
-      translate0, // translate when we started zooming (to avoid drift)
-      center0, // implicit desired position of translate0 after zooming
-      center, // explicit desired position of translate0 after zooming
-      size = [960, 500], // viewport size; required for zoom interpolation
-      scaleExtent = d3_behavior_zoomInfinity,
-      duration = 250,
-      zooming = 0,
-      mousedown = "mousedown.zoom",
-      mousemove = "mousemove.zoom",
-      mouseup = "mouseup.zoom",
-      mousewheelTimer,
-      touchstart = "touchstart.zoom",
-      touchtime, // time of last touchstart (to detect double-tap)
-      event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"),
-      x0,
-      x1,
-      y0,
-      y1;
-
-  // Lazily determine the DOM’s support for Wheel events.
-  // https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/wheel
-  if (!d3_behavior_zoomWheel) {
-    d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); }, "wheel")
-        : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { return d3.event.wheelDelta; }, "mousewheel")
-        : (d3_behavior_zoomDelta = function() { return -d3.event.detail; }, "MozMousePixelScroll");
-  }
+    /**
+     * Creates a clone of the lazy wrapper object.
+     *
+     * @private
+     * @name clone
+     * @memberOf LazyWrapper
+     * @returns {Object} Returns the cloned `LazyWrapper` object.
+     */
+    function lazyClone() {
+      var result = new LazyWrapper(this.__wrapped__);
+      result.__actions__ = copyArray(this.__actions__);
+      result.__dir__ = this.__dir__;
+      result.__filtered__ = this.__filtered__;
+      result.__iteratees__ = copyArray(this.__iteratees__);
+      result.__takeCount__ = this.__takeCount__;
+      result.__views__ = copyArray(this.__views__);
+      return result;
+    }
 
-  function zoom(g) {
-    g   .on(mousedown, mousedowned)
-        .on(d3_behavior_zoomWheel + ".zoom", mousewheeled)
-        .on("dblclick.zoom", dblclicked)
-        .on(touchstart, touchstarted);
-  }
-
-  zoom.event = function(g) {
-    g.each(function() {
-      var dispatch = event.of(this, arguments),
-          view1 = view;
-      if (d3_transitionInheritId) {
-        d3.select(this).transition()
-            .each("start.zoom", function() {
-              view = this.__chart__ || {x: 0, y: 0, k: 1}; // pre-transition state
-              zoomstarted(dispatch);
-            })
-            .tween("zoom:zoom", function() {
-              var dx = size[0],
-                  dy = size[1],
-                  cx = center0 ? center0[0] : dx / 2,
-                  cy = center0 ? center0[1] : dy / 2,
-                  i = d3.interpolateZoom(
-                    [(cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k],
-                    [(cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k]
-                  );
-              return function(t) {
-                var l = i(t), k = dx / l[2];
-                this.__chart__ = view = {x: cx - l[0] * k, y: cy - l[1] * k, k: k};
-                zoomed(dispatch);
-              };
-            })
-            .each("interrupt.zoom", function() {
-              zoomended(dispatch);
-            })
-            .each("end.zoom", function() {
-              zoomended(dispatch);
-            });
+    /**
+     * Reverses the direction of lazy iteration.
+     *
+     * @private
+     * @name reverse
+     * @memberOf LazyWrapper
+     * @returns {Object} Returns the new reversed `LazyWrapper` object.
+     */
+    function lazyReverse() {
+      if (this.__filtered__) {
+        var result = new LazyWrapper(this);
+        result.__dir__ = -1;
+        result.__filtered__ = true;
       } else {
-        this.__chart__ = view;
-        zoomstarted(dispatch);
-        zoomed(dispatch);
-        zoomended(dispatch);
+        result = this.clone();
+        result.__dir__ *= -1;
       }
-    });
-  }
-
-  zoom.translate = function(_) {
-    if (!arguments.length) return [view.x, view.y];
-    view = {x: +_[0], y: +_[1], k: view.k}; // copy-on-write
-    rescale();
-    return zoom;
-  };
-
-  zoom.scale = function(_) {
-    if (!arguments.length) return view.k;
-    view = {x: view.x, y: view.y, k: +_}; // copy-on-write
-    rescale();
-    return zoom;
-  };
-
-  zoom.scaleExtent = function(_) {
-    if (!arguments.length) return scaleExtent;
-    scaleExtent = _ == null ? d3_behavior_zoomInfinity : [+_[0], +_[1]];
-    return zoom;
-  };
-
-  zoom.center = function(_) {
-    if (!arguments.length) return center;
-    center = _ && [+_[0], +_[1]];
-    return zoom;
-  };
-
-  zoom.size = function(_) {
-    if (!arguments.length) return size;
-    size = _ && [+_[0], +_[1]];
-    return zoom;
-  };
-
-  zoom.duration = function(_) {
-    if (!arguments.length) return duration;
-    duration = +_; // TODO function based on interpolateZoom distance?
-    return zoom;
-  };
-
-  zoom.x = function(z) {
-    if (!arguments.length) return x1;
-    x1 = z;
-    x0 = z.copy();
-    view = {x: 0, y: 0, k: 1}; // copy-on-write
-    return zoom;
-  };
-
-  zoom.y = function(z) {
-    if (!arguments.length) return y1;
-    y1 = z;
-    y0 = z.copy();
-    view = {x: 0, y: 0, k: 1}; // copy-on-write
-    return zoom;
-  };
+      return result;
+    }
 
-  function location(p) {
-    return [(p[0] - view.x) / view.k, (p[1] - view.y) / view.k];
-  }
+    /**
+     * Extracts the unwrapped value from its lazy wrapper.
+     *
+     * @private
+     * @name value
+     * @memberOf LazyWrapper
+     * @returns {*} Returns the unwrapped value.
+     */
+    function lazyValue() {
+      var array = this.__wrapped__.value(),
+          dir = this.__dir__,
+          isArr = isArray(array),
+          isRight = dir < 0,
+          arrLength = isArr ? array.length : 0,
+          view = getView(0, arrLength, this.__views__),
+          start = view.start,
+          end = view.end,
+          length = end - start,
+          index = isRight ? end : (start - 1),
+          iteratees = this.__iteratees__,
+          iterLength = iteratees.length,
+          resIndex = 0,
+          takeCount = nativeMin(length, this.__takeCount__);
+
+      if (!isArr || arrLength < LARGE_ARRAY_SIZE ||
+          (arrLength == length && takeCount == length)) {
+        return baseWrapperValue(array, this.__actions__);
+      }
+      var result = [];
+
+      outer:
+      while (length-- && resIndex < takeCount) {
+        index += dir;
+
+        var iterIndex = -1,
+            value = array[index];
+
+        while (++iterIndex < iterLength) {
+          var data = iteratees[iterIndex],
+              iteratee = data.iteratee,
+              type = data.type,
+              computed = iteratee(value);
+
+          if (type == LAZY_MAP_FLAG) {
+            value = computed;
+          } else if (!computed) {
+            if (type == LAZY_FILTER_FLAG) {
+              continue outer;
+            } else {
+              break outer;
+            }
+          }
+        }
+        result[resIndex++] = value;
+      }
+      return result;
+    }
 
-  function point(l) {
-    return [l[0] * view.k + view.x, l[1] * view.k + view.y];
-  }
+    // Ensure `LazyWrapper` is an instance of `baseLodash`.
+    LazyWrapper.prototype = baseCreate(baseLodash.prototype);
+    LazyWrapper.prototype.constructor = LazyWrapper;
 
-  function scaleTo(s) {
-    view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
-  }
+    /*------------------------------------------------------------------------*/
 
-  function translateTo(p, l) {
-    l = point(l);
-    view.x += p[0] - l[0];
-    view.y += p[1] - l[1];
-  }
+    /**
+     * Creates a hash object.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [entries] The key-value pairs to cache.
+     */
+    function Hash(entries) {
+      var index = -1,
+          length = entries == null ? 0 : entries.length;
 
-  function zoomTo(that, p, l, k) {
-    that.__chart__ = {x: view.x, y: view.y, k: view.k};
+      this.clear();
+      while (++index < length) {
+        var entry = entries[index];
+        this.set(entry[0], entry[1]);
+      }
+    }
 
-    scaleTo(Math.pow(2, k));
-    translateTo(center0 = p, l);
+    /**
+     * Removes all key-value entries from the hash.
+     *
+     * @private
+     * @name clear
+     * @memberOf Hash
+     */
+    function hashClear() {
+      this.__data__ = nativeCreate ? nativeCreate(null) : {};
+      this.size = 0;
+    }
 
-    that = d3.select(that);
-    if (duration > 0) that = that.transition().duration(duration);
-    that.call(zoom.event);
-  }
+    /**
+     * Removes `key` and its value from the hash.
+     *
+     * @private
+     * @name delete
+     * @memberOf Hash
+     * @param {Object} hash The hash to modify.
+     * @param {string} key The key of the value to remove.
+     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+     */
+    function hashDelete(key) {
+      var result = this.has(key) && delete this.__data__[key];
+      this.size -= result ? 1 : 0;
+      return result;
+    }
 
-  function rescale() {
-    if (x1) x1.domain(x0.range().map(function(x) { return (x - view.x) / view.k; }).map(x0.invert));
-    if (y1) y1.domain(y0.range().map(function(y) { return (y - view.y) / view.k; }).map(y0.invert));
-  }
+    /**
+     * Gets the hash value for `key`.
+     *
+     * @private
+     * @name get
+     * @memberOf Hash
+     * @param {string} key The key of the value to get.
+     * @returns {*} Returns the entry value.
+     */
+    function hashGet(key) {
+      var data = this.__data__;
+      if (nativeCreate) {
+        var result = data[key];
+        return result === HASH_UNDEFINED ? undefined : result;
+      }
+      return hasOwnProperty.call(data, key) ? data[key] : undefined;
+    }
 
-  function zoomstarted(dispatch) {
-    if (!zooming++) dispatch({type: "zoomstart"});
-  }
+    /**
+     * Checks if a hash value for `key` exists.
+     *
+     * @private
+     * @name has
+     * @memberOf Hash
+     * @param {string} key The key of the entry to check.
+     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+     */
+    function hashHas(key) {
+      var data = this.__data__;
+      return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
+    }
 
-  function zoomed(dispatch) {
-    rescale();
-    dispatch({type: "zoom", scale: view.k, translate: [view.x, view.y]});
-  }
+    /**
+     * Sets the hash `key` to `value`.
+     *
+     * @private
+     * @name set
+     * @memberOf Hash
+     * @param {string} key The key of the value to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns the hash instance.
+     */
+    function hashSet(key, value) {
+      var data = this.__data__;
+      this.size += this.has(key) ? 0 : 1;
+      data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
+      return this;
+    }
 
-  function zoomended(dispatch) {
-    if (!--zooming) dispatch({type: "zoomend"}), center0 = null;
-  }
+    // Add methods to `Hash`.
+    Hash.prototype.clear = hashClear;
+    Hash.prototype['delete'] = hashDelete;
+    Hash.prototype.get = hashGet;
+    Hash.prototype.has = hashHas;
+    Hash.prototype.set = hashSet;
 
-  function mousedowned() {
-    var that = this,
-        target = d3.event.target,
-        dispatch = event.of(that, arguments),
-        dragged = 0,
-        subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended),
-        location0 = location(d3.mouse(that)),
-        dragRestore = d3_event_dragSuppress(that);
+    /*------------------------------------------------------------------------*/
 
-    d3_selection_interrupt.call(that);
-    zoomstarted(dispatch);
+    /**
+     * Creates an list cache object.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [entries] The key-value pairs to cache.
+     */
+    function ListCache(entries) {
+      var index = -1,
+          length = entries == null ? 0 : entries.length;
 
-    function moved() {
-      dragged = 1;
-      translateTo(d3.mouse(that), location0);
-      zoomed(dispatch);
+      this.clear();
+      while (++index < length) {
+        var entry = entries[index];
+        this.set(entry[0], entry[1]);
+      }
     }
 
-    function ended() {
-      subject.on(mousemove, null).on(mouseup, null);
-      dragRestore(dragged && d3.event.target === target);
-      zoomended(dispatch);
+    /**
+     * Removes all key-value entries from the list cache.
+     *
+     * @private
+     * @name clear
+     * @memberOf ListCache
+     */
+    function listCacheClear() {
+      this.__data__ = [];
+      this.size = 0;
     }
-  }
 
-  // These closures persist for as long as at least one touch is active.
-  function touchstarted() {
-    var that = this,
-        dispatch = event.of(that, arguments),
-        locations0 = {}, // touchstart locations
-        distance0 = 0, // distance² between initial touches
-        scale0, // scale when we started touching
-        zoomName = ".zoom-" + d3.event.changedTouches[0].identifier,
-        touchmove = "touchmove" + zoomName,
-        touchend = "touchend" + zoomName,
-        targets = [],
-        subject = d3.select(that),
-        dragRestore = d3_event_dragSuppress(that);
-
-    started();
-    zoomstarted(dispatch);
-
-    // Workaround for Chrome issue 412723: the touchstart listener must be set
-    // after the touchmove listener.
-    subject.on(mousedown, null).on(touchstart, started); // prevent duplicate events
-
-    // Updates locations of any touches in locations0.
-    function relocate() {
-      var touches = d3.touches(that);
-      scale0 = view.k;
-      touches.forEach(function(t) {
-        if (t.identifier in locations0) locations0[t.identifier] = location(t);
-      });
-      return touches;
+    /**
+     * Removes `key` and its value from the list cache.
+     *
+     * @private
+     * @name delete
+     * @memberOf ListCache
+     * @param {string} key The key of the value to remove.
+     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+     */
+    function listCacheDelete(key) {
+      var data = this.__data__,
+          index = assocIndexOf(data, key);
+
+      if (index < 0) {
+        return false;
+      }
+      var lastIndex = data.length - 1;
+      if (index == lastIndex) {
+        data.pop();
+      } else {
+        splice.call(data, index, 1);
+      }
+      --this.size;
+      return true;
     }
 
-    // Temporarily override touchstart while gesture is active.
-    function started() {
+    /**
+     * Gets the list cache value for `key`.
+     *
+     * @private
+     * @name get
+     * @memberOf ListCache
+     * @param {string} key The key of the value to get.
+     * @returns {*} Returns the entry value.
+     */
+    function listCacheGet(key) {
+      var data = this.__data__,
+          index = assocIndexOf(data, key);
 
-      // Listen for touchmove and touchend on the target of touchstart.
-      var target = d3.event.target;
-      d3.select(target).on(touchmove, moved).on(touchend, ended);
-      targets.push(target);
+      return index < 0 ? undefined : data[index][1];
+    }
 
-      // Only track touches started on the same subject element.
-      var changed = d3.event.changedTouches;
-      for (var i = 0, n = changed.length; i < n; ++i) {
-        locations0[changed[i].identifier] = null;
-      }
+    /**
+     * Checks if a list cache value for `key` exists.
+     *
+     * @private
+     * @name has
+     * @memberOf ListCache
+     * @param {string} key The key of the entry to check.
+     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+     */
+    function listCacheHas(key) {
+      return assocIndexOf(this.__data__, key) > -1;
+    }
 
-      var touches = relocate(),
-          now = Date.now();
+    /**
+     * Sets the list cache `key` to `value`.
+     *
+     * @private
+     * @name set
+     * @memberOf ListCache
+     * @param {string} key The key of the value to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns the list cache instance.
+     */
+    function listCacheSet(key, value) {
+      var data = this.__data__,
+          index = assocIndexOf(data, key);
 
-      if (touches.length === 1) {
-        if (now - touchtime < 500) { // dbltap
-          var p = touches[0];
-          zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1);
-          d3_eventPreventDefault();
-        }
-        touchtime = now;
-      } else if (touches.length > 1) {
-        var p = touches[0], q = touches[1],
-            dx = p[0] - q[0], dy = p[1] - q[1];
-        distance0 = dx * dx + dy * dy;
+      if (index < 0) {
+        ++this.size;
+        data.push([key, value]);
+      } else {
+        data[index][1] = value;
       }
+      return this;
     }
 
-    function moved() {
-      var touches = d3.touches(that),
-          p0, l0,
-          p1, l1;
+    // Add methods to `ListCache`.
+    ListCache.prototype.clear = listCacheClear;
+    ListCache.prototype['delete'] = listCacheDelete;
+    ListCache.prototype.get = listCacheGet;
+    ListCache.prototype.has = listCacheHas;
+    ListCache.prototype.set = listCacheSet;
 
-      d3_selection_interrupt.call(that);
+    /*------------------------------------------------------------------------*/
 
-      for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
-        p1 = touches[i];
-        if (l1 = locations0[p1.identifier]) {
-          if (l0) break;
-          p0 = p1, l0 = l1;
-        }
-      }
+    /**
+     * Creates a map cache object to store key-value pairs.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [entries] The key-value pairs to cache.
+     */
+    function MapCache(entries) {
+      var index = -1,
+          length = entries == null ? 0 : entries.length;
 
-      if (l1) {
-        var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1,
-            scale1 = distance0 && Math.sqrt(distance1 / distance0);
-        p0 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
-        l0 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
-        scaleTo(scale1 * scale0);
+      this.clear();
+      while (++index < length) {
+        var entry = entries[index];
+        this.set(entry[0], entry[1]);
       }
-
-      touchtime = null;
-      translateTo(p0, l0);
-      zoomed(dispatch);
     }
 
-    function ended() {
-      // If there are any globally-active touches remaining, remove the ended
-      // touches from locations0.
-      if (d3.event.touches.length) {
-        var changed = d3.event.changedTouches;
-        for (var i = 0, n = changed.length; i < n; ++i) {
-          delete locations0[changed[i].identifier];
-        }
-        // If locations0 is not empty, then relocate and continue listening for
-        // touchmove and touchend.
-        for (var identifier in locations0) {
-          return void relocate(); // locations may have detached due to rotation
-        }
-      }
-      // Otherwise, remove touchmove and touchend listeners.
-      d3.selectAll(targets).on(zoomName, null);
-      subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
-      dragRestore();
-      zoomended(dispatch);
+    /**
+     * Removes all key-value entries from the map.
+     *
+     * @private
+     * @name clear
+     * @memberOf MapCache
+     */
+    function mapCacheClear() {
+      this.size = 0;
+      this.__data__ = {
+        'hash': new Hash,
+        'map': new (Map || ListCache),
+        'string': new Hash
+      };
     }
-  }
 
-  function mousewheeled() {
-    var dispatch = event.of(this, arguments);
-    if (mousewheelTimer) clearTimeout(mousewheelTimer);
-    else d3_selection_interrupt.call(this), translate0 = location(center0 = center || d3.mouse(this)), zoomstarted(dispatch);
-    mousewheelTimer = setTimeout(function() { mousewheelTimer = null; zoomended(dispatch); }, 50);
-    d3_eventPreventDefault();
-    scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
-    translateTo(center0, translate0);
-    zoomed(dispatch);
-  }
+    /**
+     * Removes `key` and its value from the map.
+     *
+     * @private
+     * @name delete
+     * @memberOf MapCache
+     * @param {string} key The key of the value to remove.
+     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+     */
+    function mapCacheDelete(key) {
+      var result = getMapData(this, key)['delete'](key);
+      this.size -= result ? 1 : 0;
+      return result;
+    }
 
-  function dblclicked() {
-    var p = d3.mouse(this),
-        k = Math.log(view.k) / Math.LN2;
+    /**
+     * Gets the map value for `key`.
+     *
+     * @private
+     * @name get
+     * @memberOf MapCache
+     * @param {string} key The key of the value to get.
+     * @returns {*} Returns the entry value.
+     */
+    function mapCacheGet(key) {
+      return getMapData(this, key).get(key);
+    }
 
-    zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1);
-  }
+    /**
+     * Checks if a map value for `key` exists.
+     *
+     * @private
+     * @name has
+     * @memberOf MapCache
+     * @param {string} key The key of the entry to check.
+     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+     */
+    function mapCacheHas(key) {
+      return getMapData(this, key).has(key);
+    }
 
-  return d3.rebind(zoom, event, "on");
-};
+    /**
+     * Sets the map `key` to `value`.
+     *
+     * @private
+     * @name set
+     * @memberOf MapCache
+     * @param {string} key The key of the value to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns the map cache instance.
+     */
+    function mapCacheSet(key, value) {
+      var data = getMapData(this, key),
+          size = data.size;
 
-var d3_behavior_zoomInfinity = [0, Infinity], // default scale extent
-    d3_behavior_zoomDelta, // initialized lazily
-    d3_behavior_zoomWheel;
-function d3_functor(v) {
-  return typeof v === "function" ? v : function() { return v; };
-}
+      data.set(key, value);
+      this.size += data.size == size ? 0 : 1;
+      return this;
+    }
 
-d3.functor = d3_functor;
+    // Add methods to `MapCache`.
+    MapCache.prototype.clear = mapCacheClear;
+    MapCache.prototype['delete'] = mapCacheDelete;
+    MapCache.prototype.get = mapCacheGet;
+    MapCache.prototype.has = mapCacheHas;
+    MapCache.prototype.set = mapCacheSet;
 
-d3.touch = function(container, touches, identifier) {
-  if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;
-  if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {
-    if ((touch = touches[i]).identifier === identifier) {
-      return d3_mousePoint(container, touch);
+    /*------------------------------------------------------------------------*/
+
+    /**
+     *
+     * Creates an array cache object to store unique values.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [values] The values to cache.
+     */
+    function SetCache(values) {
+      var index = -1,
+          length = values == null ? 0 : values.length;
+
+      this.__data__ = new MapCache;
+      while (++index < length) {
+        this.add(values[index]);
+      }
     }
-  }
-};
 
-var d3_timer_queueHead,
-    d3_timer_queueTail,
-    d3_timer_interval, // is an interval (or frame) active?
-    d3_timer_timeout, // is a timeout active?
-    d3_timer_active, // active timer object
-    d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) { setTimeout(callback, 17); };
+    /**
+     * Adds `value` to the array cache.
+     *
+     * @private
+     * @name add
+     * @memberOf SetCache
+     * @alias push
+     * @param {*} value The value to cache.
+     * @returns {Object} Returns the cache instance.
+     */
+    function setCacheAdd(value) {
+      this.__data__.set(value, HASH_UNDEFINED);
+      return this;
+    }
 
-// The timer will continue to fire until callback returns true.
-d3.timer = function(callback, delay, then) {
-  var n = arguments.length;
-  if (n < 2) delay = 0;
-  if (n < 3) then = Date.now();
+    /**
+     * Checks if `value` is in the array cache.
+     *
+     * @private
+     * @name has
+     * @memberOf SetCache
+     * @param {*} value The value to search for.
+     * @returns {number} Returns `true` if `value` is found, else `false`.
+     */
+    function setCacheHas(value) {
+      return this.__data__.has(value);
+    }
 
-  // Add the callback to the tail of the queue.
-  var time = then + delay, timer = {c: callback, t: time, f: false, n: null};
-  if (d3_timer_queueTail) d3_timer_queueTail.n = timer;
-  else d3_timer_queueHead = timer;
-  d3_timer_queueTail = timer;
+    // Add methods to `SetCache`.
+    SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
+    SetCache.prototype.has = setCacheHas;
 
-  // Start animatin'!
-  if (!d3_timer_interval) {
-    d3_timer_timeout = clearTimeout(d3_timer_timeout);
-    d3_timer_interval = 1;
-    d3_timer_frame(d3_timer_step);
-  }
-};
+    /*------------------------------------------------------------------------*/
 
-function d3_timer_step() {
-  var now = d3_timer_mark(),
-      delay = d3_timer_sweep() - now;
-  if (delay > 24) {
-    if (isFinite(delay)) {
-      clearTimeout(d3_timer_timeout);
-      d3_timer_timeout = setTimeout(d3_timer_step, delay);
+    /**
+     * Creates a stack cache object to store key-value pairs.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [entries] The key-value pairs to cache.
+     */
+    function Stack(entries) {
+      var data = this.__data__ = new ListCache(entries);
+      this.size = data.size;
     }
-    d3_timer_interval = 0;
-  } else {
-    d3_timer_interval = 1;
-    d3_timer_frame(d3_timer_step);
-  }
-}
 
-d3.timer.flush = function() {
-  d3_timer_mark();
-  d3_timer_sweep();
-};
+    /**
+     * Removes all key-value entries from the stack.
+     *
+     * @private
+     * @name clear
+     * @memberOf Stack
+     */
+    function stackClear() {
+      this.__data__ = new ListCache;
+      this.size = 0;
+    }
 
-function d3_timer_mark() {
-  var now = Date.now();
-  d3_timer_active = d3_timer_queueHead;
-  while (d3_timer_active) {
-    if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t);
-    d3_timer_active = d3_timer_active.n;
-  }
-  return now;
-}
+    /**
+     * Removes `key` and its value from the stack.
+     *
+     * @private
+     * @name delete
+     * @memberOf Stack
+     * @param {string} key The key of the value to remove.
+     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+     */
+    function stackDelete(key) {
+      var data = this.__data__,
+          result = data['delete'](key);
 
-// Flush after callbacks to avoid concurrent queue modification.
-// Returns the time of the earliest active timer, post-sweep.
-function d3_timer_sweep() {
-  var t0,
-      t1 = d3_timer_queueHead,
-      time = Infinity;
-  while (t1) {
-    if (t1.f) {
-      t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
-    } else {
-      if (t1.t < time) time = t1.t;
-      t1 = (t0 = t1).n;
+      this.size = data.size;
+      return result;
     }
-  }
-  d3_timer_queueTail = t0;
-  return time;
-}
-d3.geo = {};
 
-d3.geo.stream = function(object, listener) {
-  if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
-    d3_geo_streamObjectType[object.type](object, listener);
-  } else {
-    d3_geo_streamGeometry(object, listener);
-  }
-};
+    /**
+     * Gets the stack value for `key`.
+     *
+     * @private
+     * @name get
+     * @memberOf Stack
+     * @param {string} key The key of the value to get.
+     * @returns {*} Returns the entry value.
+     */
+    function stackGet(key) {
+      return this.__data__.get(key);
+    }
 
-function d3_geo_streamGeometry(geometry, listener) {
-  if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
-    d3_geo_streamGeometryType[geometry.type](geometry, listener);
-  }
-}
+    /**
+     * Checks if a stack value for `key` exists.
+     *
+     * @private
+     * @name has
+     * @memberOf Stack
+     * @param {string} key The key of the entry to check.
+     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+     */
+    function stackHas(key) {
+      return this.__data__.has(key);
+    }
 
-var d3_geo_streamObjectType = {
-  Feature: function(feature, listener) {
-    d3_geo_streamGeometry(feature.geometry, listener);
-  },
-  FeatureCollection: function(object, listener) {
-    var features = object.features, i = -1, n = features.length;
-    while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
-  }
-};
+    /**
+     * Sets the stack `key` to `value`.
+     *
+     * @private
+     * @name set
+     * @memberOf Stack
+     * @param {string} key The key of the value to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns the stack cache instance.
+     */
+    function stackSet(key, value) {
+      var data = this.__data__;
+      if (data instanceof ListCache) {
+        var pairs = data.__data__;
+        if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
+          pairs.push([key, value]);
+          this.size = ++data.size;
+          return this;
+        }
+        data = this.__data__ = new MapCache(pairs);
+      }
+      data.set(key, value);
+      this.size = data.size;
+      return this;
+    }
 
-var d3_geo_streamGeometryType = {
-  Sphere: function(object, listener) {
-    listener.sphere();
-  },
-  Point: function(object, listener) {
-    object = object.coordinates;
-    listener.point(object[0], object[1], object[2]);
-  },
-  MultiPoint: function(object, listener) {
-    var coordinates = object.coordinates, i = -1, n = coordinates.length;
-    while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);
-  },
-  LineString: function(object, listener) {
-    d3_geo_streamLine(object.coordinates, listener, 0);
-  },
-  MultiLineString: function(object, listener) {
-    var coordinates = object.coordinates, i = -1, n = coordinates.length;
-    while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
-  },
-  Polygon: function(object, listener) {
-    d3_geo_streamPolygon(object.coordinates, listener);
-  },
-  MultiPolygon: function(object, listener) {
-    var coordinates = object.coordinates, i = -1, n = coordinates.length;
-    while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
-  },
-  GeometryCollection: function(object, listener) {
-    var geometries = object.geometries, i = -1, n = geometries.length;
-    while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
-  }
-};
+    // Add methods to `Stack`.
+    Stack.prototype.clear = stackClear;
+    Stack.prototype['delete'] = stackDelete;
+    Stack.prototype.get = stackGet;
+    Stack.prototype.has = stackHas;
+    Stack.prototype.set = stackSet;
 
-function d3_geo_streamLine(coordinates, listener, closed) {
-  var i = -1, n = coordinates.length - closed, coordinate;
-  listener.lineStart();
-  while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]);
-  listener.lineEnd();
-}
+    /*------------------------------------------------------------------------*/
 
-function d3_geo_streamPolygon(coordinates, listener) {
-  var i = -1, n = coordinates.length;
-  listener.polygonStart();
-  while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
-  listener.polygonEnd();
-}
+    /**
+     * Creates an array of the enumerable property names of the array-like `value`.
+     *
+     * @private
+     * @param {*} value The value to query.
+     * @param {boolean} inherited Specify returning inherited property names.
+     * @returns {Array} Returns the array of property names.
+     */
+    function arrayLikeKeys(value, inherited) {
+      var isArr = isArray(value),
+          isArg = !isArr && isArguments(value),
+          isBuff = !isArr && !isArg && isBuffer(value),
+          isType = !isArr && !isArg && !isBuff && isTypedArray(value),
+          skipIndexes = isArr || isArg || isBuff || isType,
+          result = skipIndexes ? baseTimes(value.length, String) : [],
+          length = result.length;
+
+      for (var key in value) {
+        if ((inherited || hasOwnProperty.call(value, key)) &&
+            !(skipIndexes && (
+               // Safari 9 has enumerable `arguments.length` in strict mode.
+               key == 'length' ||
+               // Node.js 0.10 has enumerable non-index properties on buffers.
+               (isBuff && (key == 'offset' || key == 'parent')) ||
+               // PhantomJS 2 has enumerable non-index properties on typed arrays.
+               (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
+               // Skip index properties.
+               isIndex(key, length)
+            ))) {
+          result.push(key);
+        }
+      }
+      return result;
+    }
 
-d3.geo.length = function(object) {
-  d3_geo_lengthSum = 0;
-  d3.geo.stream(object, d3_geo_length);
-  return d3_geo_lengthSum;
-};
+    /**
+     * A specialized version of `_.sample` for arrays.
+     *
+     * @private
+     * @param {Array} array The array to sample.
+     * @returns {*} Returns the random element.
+     */
+    function arraySample(array) {
+      var length = array.length;
+      return length ? array[baseRandom(0, length - 1)] : undefined;
+    }
 
-var d3_geo_lengthSum;
+    /**
+     * A specialized version of `_.sampleSize` for arrays.
+     *
+     * @private
+     * @param {Array} array The array to sample.
+     * @param {number} n The number of elements to sample.
+     * @returns {Array} Returns the random elements.
+     */
+    function arraySampleSize(array, n) {
+      return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
+    }
 
-var d3_geo_length = {
-  sphere: d3_noop,
-  point: d3_noop,
-  lineStart: d3_geo_lengthLineStart,
-  lineEnd: d3_noop,
-  polygonStart: d3_noop,
-  polygonEnd: d3_noop
-};
+    /**
+     * A specialized version of `_.shuffle` for arrays.
+     *
+     * @private
+     * @param {Array} array The array to shuffle.
+     * @returns {Array} Returns the new shuffled array.
+     */
+    function arrayShuffle(array) {
+      return shuffleSelf(copyArray(array));
+    }
 
-function d3_geo_lengthLineStart() {
-  var λ0, sinφ0, cosφ0;
+    /**
+     * Used by `_.defaults` to customize its `_.assignIn` use.
+     *
+     * @private
+     * @param {*} objValue The destination value.
+     * @param {*} srcValue The source value.
+     * @param {string} key The key of the property to assign.
+     * @param {Object} object The parent object of `objValue`.
+     * @returns {*} Returns the value to assign.
+     */
+    function assignInDefaults(objValue, srcValue, key, object) {
+      if (objValue === undefined ||
+          (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
+        return srcValue;
+      }
+      return objValue;
+    }
 
-  d3_geo_length.point = function(λ, φ) {
-    λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);
-    d3_geo_length.point = nextPoint;
-  };
+    /**
+     * This function is like `assignValue` except that it doesn't assign
+     * `undefined` values.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {string} key The key of the property to assign.
+     * @param {*} value The value to assign.
+     */
+    function assignMergeValue(object, key, value) {
+      if ((value !== undefined && !eq(object[key], value)) ||
+          (value === undefined && !(key in object))) {
+        baseAssignValue(object, key, value);
+      }
+    }
 
-  d3_geo_length.lineEnd = function() {
-    d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
-  };
+    /**
+     * Assigns `value` to `key` of `object` if the existing value is not equivalent
+     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {string} key The key of the property to assign.
+     * @param {*} value The value to assign.
+     */
+    function assignValue(object, key, value) {
+      var objValue = object[key];
+      if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
+          (value === undefined && !(key in object))) {
+        baseAssignValue(object, key, value);
+      }
+    }
 
-  function nextPoint(λ, φ) {
-    var sinφ = Math.sin(φ *= d3_radians),
-        cosφ = Math.cos(φ),
-        t = abs((λ *= d3_radians) - λ0),
-        cosΔλ = Math.cos(t);
-    d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ);
-    λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;
-  }
-}
-function d3_identity(d) {
-  return d;
-}
-function d3_true() {
-  return true;
-}
+    /**
+     * Gets the index at which the `key` is found in `array` of key-value pairs.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {*} key The key to search for.
+     * @returns {number} Returns the index of the matched value, else `-1`.
+     */
+    function assocIndexOf(array, key) {
+      var length = array.length;
+      while (length--) {
+        if (eq(array[length][0], key)) {
+          return length;
+        }
+      }
+      return -1;
+    }
 
-function d3_geo_spherical(cartesian) {
-  return [
-    Math.atan2(cartesian[1], cartesian[0]),
-    d3_asin(cartesian[2])
-  ];
-}
+    /**
+     * Aggregates elements of `collection` on `accumulator` with keys transformed
+     * by `iteratee` and values set by `setter`.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} setter The function to set `accumulator` values.
+     * @param {Function} iteratee The iteratee to transform keys.
+     * @param {Object} accumulator The initial aggregated object.
+     * @returns {Function} Returns `accumulator`.
+     */
+    function baseAggregator(collection, setter, iteratee, accumulator) {
+      baseEach(collection, function(value, key, collection) {
+        setter(accumulator, value, iteratee(value), collection);
+      });
+      return accumulator;
+    }
 
-function d3_geo_sphericalEqual(a, b) {
-  return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
-}
+    /**
+     * The base implementation of `_.assign` without support for multiple sources
+     * or `customizer` functions.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @returns {Object} Returns `object`.
+     */
+    function baseAssign(object, source) {
+      return object && copyObject(source, keys(source), object);
+    }
 
-// General spherical polygon clipping algorithm: takes a polygon, cuts it into
-// visible line segments and rejoins the segments by interpolating along the
-// clip edge.
-function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) {
-  var subject = [],
-      clip = [];
+    /**
+     * The base implementation of `_.assignIn` without support for multiple sources
+     * or `customizer` functions.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @returns {Object} Returns `object`.
+     */
+    function baseAssignIn(object, source) {
+      return object && copyObject(source, keysIn(source), object);
+    }
 
-  segments.forEach(function(segment) {
-    if ((n = segment.length - 1) <= 0) return;
-    var n, p0 = segment[0], p1 = segment[n];
-
-    // If the first and last points of a segment are coincident, then treat as
-    // a closed ring.
-    // TODO if all rings are closed, then the winding order of the exterior
-    // ring should be checked.
-    if (d3_geo_sphericalEqual(p0, p1)) {
-      listener.lineStart();
-      for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
-      listener.lineEnd();
-      return;
+    /**
+     * The base implementation of `assignValue` and `assignMergeValue` without
+     * value checks.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {string} key The key of the property to assign.
+     * @param {*} value The value to assign.
+     */
+    function baseAssignValue(object, key, value) {
+      if (key == '__proto__' && defineProperty) {
+        defineProperty(object, key, {
+          'configurable': true,
+          'enumerable': true,
+          'value': value,
+          'writable': true
+        });
+      } else {
+        object[key] = value;
+      }
     }
 
-    var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true),
-        b = new d3_geo_clipPolygonIntersection(p0, null, a, false);
-    a.o = b;
-    subject.push(a);
-    clip.push(b);
-    a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
-    b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
-    a.o = b;
-    subject.push(a);
-    clip.push(b);
-  });
-  clip.sort(compare);
-  d3_geo_clipPolygonLinkCircular(subject);
-  d3_geo_clipPolygonLinkCircular(clip);
-  if (!subject.length) return;
+    /**
+     * The base implementation of `_.at` without support for individual paths.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {string[]} paths The property paths to pick.
+     * @returns {Array} Returns the picked elements.
+     */
+    function baseAt(object, paths) {
+      var index = -1,
+          length = paths.length,
+          result = Array(length),
+          skip = object == null;
 
-  for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
-    clip[i].e = entry = !entry;
-  }
+      while (++index < length) {
+        result[index] = skip ? undefined : get(object, paths[index]);
+      }
+      return result;
+    }
 
-  var start = subject[0],
-      points,
-      point;
-  while (1) {
-    // Find first unvisited intersection.
-    var current = start,
-        isSubject = true;
-    while (current.v) if ((current = current.n) === start) return;
-    points = current.z;
-    listener.lineStart();
-    do {
-      current.v = current.o.v = true;
-      if (current.e) {
-        if (isSubject) {
-          for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);
-        } else {
-          interpolate(current.x, current.n.x, 1, listener);
+    /**
+     * The base implementation of `_.clamp` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {number} number The number to clamp.
+     * @param {number} [lower] The lower bound.
+     * @param {number} upper The upper bound.
+     * @returns {number} Returns the clamped number.
+     */
+    function baseClamp(number, lower, upper) {
+      if (number === number) {
+        if (upper !== undefined) {
+          number = number <= upper ? number : upper;
+        }
+        if (lower !== undefined) {
+          number = number >= lower ? number : lower;
+        }
+      }
+      return number;
+    }
+
+    /**
+     * The base implementation of `_.clone` and `_.cloneDeep` which tracks
+     * traversed objects.
+     *
+     * @private
+     * @param {*} value The value to clone.
+     * @param {boolean} bitmask The bitmask flags.
+     *  1 - Deep clone
+     *  2 - Flatten inherited properties
+     *  4 - Clone symbols
+     * @param {Function} [customizer] The function to customize cloning.
+     * @param {string} [key] The key of `value`.
+     * @param {Object} [object] The parent object of `value`.
+     * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
+     * @returns {*} Returns the cloned value.
+     */
+    function baseClone(value, bitmask, customizer, key, object, stack) {
+      var result,
+          isDeep = bitmask & CLONE_DEEP_FLAG,
+          isFlat = bitmask & CLONE_FLAT_FLAG,
+          isFull = bitmask & CLONE_SYMBOLS_FLAG;
+
+      if (customizer) {
+        result = object ? customizer(value, key, object, stack) : customizer(value);
+      }
+      if (result !== undefined) {
+        return result;
+      }
+      if (!isObject(value)) {
+        return value;
+      }
+      var isArr = isArray(value);
+      if (isArr) {
+        result = initCloneArray(value);
+        if (!isDeep) {
+          return copyArray(value, result);
         }
-        current = current.n;
       } else {
-        if (isSubject) {
-          points = current.p.z;
-          for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);
+        var tag = getTag(value),
+            isFunc = tag == funcTag || tag == genTag;
+
+        if (isBuffer(value)) {
+          return cloneBuffer(value, isDeep);
+        }
+        if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+          result = (isFlat || isFunc) ? {} : initCloneObject(value);
+          if (!isDeep) {
+            return isFlat
+              ? copySymbolsIn(value, baseAssignIn(result, value))
+              : copySymbols(value, baseAssign(result, value));
+          }
         } else {
-          interpolate(current.x, current.p.x, -1, listener);
+          if (!cloneableTags[tag]) {
+            return object ? value : {};
+          }
+          result = initCloneByTag(value, tag, baseClone, isDeep);
         }
-        current = current.p;
       }
-      current = current.o;
-      points = current.z;
-      isSubject = !isSubject;
-    } while (!current.v);
-    listener.lineEnd();
-  }
-}
+      // Check for circular references and return its corresponding clone.
+      stack || (stack = new Stack);
+      var stacked = stack.get(value);
+      if (stacked) {
+        return stacked;
+      }
+      stack.set(value, result);
 
-function d3_geo_clipPolygonLinkCircular(array) {
-  if (!(n = array.length)) return;
-  var n,
-      i = 0,
-      a = array[0],
-      b;
-  while (++i < n) {
-    a.n = b = array[i];
-    b.p = a;
-    a = b;
-  }
-  a.n = b = array[0];
-  b.p = a;
-}
+      var keysFunc = isFull
+        ? (isFlat ? getAllKeysIn : getAllKeys)
+        : (isFlat ? keysIn : keys);
 
-function d3_geo_clipPolygonIntersection(point, points, other, entry) {
-  this.x = point;
-  this.z = points;
-  this.o = other; // another intersection
-  this.e = entry; // is an entry?
-  this.v = false; // visited
-  this.n = this.p = null; // next & previous
-}
+      var props = isArr ? undefined : keysFunc(value);
+      arrayEach(props || value, function(subValue, key) {
+        if (props) {
+          key = subValue;
+          subValue = value[key];
+        }
+        // Recursively populate clone (susceptible to call stack limits).
+        assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
+      });
+      return result;
+    }
 
-function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
-  return function(rotate, listener) {
-    var line = clipLine(listener),
-        rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);
+    /**
+     * The base implementation of `_.conforms` which doesn't clone `source`.
+     *
+     * @private
+     * @param {Object} source The object of property predicates to conform to.
+     * @returns {Function} Returns the new spec function.
+     */
+    function baseConforms(source) {
+      var props = keys(source);
+      return function(object) {
+        return baseConformsTo(object, source, props);
+      };
+    }
 
-    var clip = {
-      point: point,
-      lineStart: lineStart,
-      lineEnd: lineEnd,
-      polygonStart: function() {
-        clip.point = pointRing;
-        clip.lineStart = ringStart;
-        clip.lineEnd = ringEnd;
-        segments = [];
-        polygon = [];
-      },
-      polygonEnd: function() {
-        clip.point = point;
-        clip.lineStart = lineStart;
-        clip.lineEnd = lineEnd;
-
-        segments = d3.merge(segments);
-        var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
-        if (segments.length) {
-          if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
-          d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
-        } else if (clipStartInside) {
-          if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
-          listener.lineStart();
-          interpolate(null, null, 1, listener);
-          listener.lineEnd();
-        }
-        if (polygonStarted) listener.polygonEnd(), polygonStarted = false;
-        segments = polygon = null;
-      },
-      sphere: function() {
-        listener.polygonStart();
-        listener.lineStart();
-        interpolate(null, null, 1, listener);
-        listener.lineEnd();
-        listener.polygonEnd();
+    /**
+     * The base implementation of `_.conformsTo` which accepts `props` to check.
+     *
+     * @private
+     * @param {Object} object The object to inspect.
+     * @param {Object} source The object of property predicates to conform to.
+     * @returns {boolean} Returns `true` if `object` conforms, else `false`.
+     */
+    function baseConformsTo(object, source, props) {
+      var length = props.length;
+      if (object == null) {
+        return !length;
       }
-    };
+      object = Object(object);
+      while (length--) {
+        var key = props[length],
+            predicate = source[key],
+            value = object[key];
 
-    function point(λ, φ) {
-      var point = rotate(λ, φ);
-      if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);
-    }
-    function pointLine(λ, φ) {
-      var point = rotate(λ, φ);
-      line.point(point[0], point[1]);
+        if ((value === undefined && !(key in object)) || !predicate(value)) {
+          return false;
+        }
+      }
+      return true;
     }
-    function lineStart() { clip.point = pointLine; line.lineStart(); }
-    function lineEnd() { clip.point = point; line.lineEnd(); }
 
-    var segments;
+    /**
+     * The base implementation of `_.delay` and `_.defer` which accepts `args`
+     * to provide to `func`.
+     *
+     * @private
+     * @param {Function} func The function to delay.
+     * @param {number} wait The number of milliseconds to delay invocation.
+     * @param {Array} args The arguments to provide to `func`.
+     * @returns {number|Object} Returns the timer id or timeout object.
+     */
+    function baseDelay(func, wait, args) {
+      if (typeof func != 'function') {
+        throw new TypeError(FUNC_ERROR_TEXT);
+      }
+      return setTimeout(function() { func.apply(undefined, args); }, wait);
+    }
 
-    var buffer = d3_geo_clipBufferListener(),
-        ringListener = clipLine(buffer),
-        polygonStarted = false,
-        polygon,
-        ring;
+    /**
+     * The base implementation of methods like `_.difference` without support
+     * for excluding multiple arrays or iteratee shorthands.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {Array} values The values to exclude.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of filtered values.
+     */
+    function baseDifference(array, values, iteratee, comparator) {
+      var index = -1,
+          includes = arrayIncludes,
+          isCommon = true,
+          length = array.length,
+          result = [],
+          valuesLength = values.length;
 
-    function pointRing(λ, φ) {
-      ring.push([λ, φ]);
-      var point = rotate(λ, φ);
-      ringListener.point(point[0], point[1]);
+      if (!length) {
+        return result;
+      }
+      if (iteratee) {
+        values = arrayMap(values, baseUnary(iteratee));
+      }
+      if (comparator) {
+        includes = arrayIncludesWith;
+        isCommon = false;
+      }
+      else if (values.length >= LARGE_ARRAY_SIZE) {
+        includes = cacheHas;
+        isCommon = false;
+        values = new SetCache(values);
+      }
+      outer:
+      while (++index < length) {
+        var value = array[index],
+            computed = iteratee == null ? value : iteratee(value);
+
+        value = (comparator || value !== 0) ? value : 0;
+        if (isCommon && computed === computed) {
+          var valuesIndex = valuesLength;
+          while (valuesIndex--) {
+            if (values[valuesIndex] === computed) {
+              continue outer;
+            }
+          }
+          result.push(value);
+        }
+        else if (!includes(values, computed, comparator)) {
+          result.push(value);
+        }
+      }
+      return result;
     }
 
-    function ringStart() {
-      ringListener.lineStart();
-      ring = [];
-    }
+    /**
+     * The base implementation of `_.forEach` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Array|Object} Returns `collection`.
+     */
+    var baseEach = createBaseEach(baseForOwn);
 
-    function ringEnd() {
-      pointRing(ring[0][0], ring[0][1]);
-      ringListener.lineEnd();
+    /**
+     * The base implementation of `_.forEachRight` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Array|Object} Returns `collection`.
+     */
+    var baseEachRight = createBaseEach(baseForOwnRight, true);
 
-      var clean = ringListener.clean(),
-          ringSegments = buffer.buffer(),
-          segment,
-          n = ringSegments.length;
+    /**
+     * The base implementation of `_.every` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} predicate The function invoked per iteration.
+     * @returns {boolean} Returns `true` if all elements pass the predicate check,
+     *  else `false`
+     */
+    function baseEvery(collection, predicate) {
+      var result = true;
+      baseEach(collection, function(value, index, collection) {
+        result = !!predicate(value, index, collection);
+        return result;
+      });
+      return result;
+    }
 
-      ring.pop();
-      polygon.push(ring);
-      ring = null;
+    /**
+     * The base implementation of methods like `_.max` and `_.min` which accepts a
+     * `comparator` to determine the extremum value.
+     *
+     * @private
+     * @param {Array} array The array to iterate over.
+     * @param {Function} iteratee The iteratee invoked per iteration.
+     * @param {Function} comparator The comparator used to compare values.
+     * @returns {*} Returns the extremum value.
+     */
+    function baseExtremum(array, iteratee, comparator) {
+      var index = -1,
+          length = array.length;
 
-      if (!n) return;
+      while (++index < length) {
+        var value = array[index],
+            current = iteratee(value);
 
-      // No intersections.
-      if (clean & 1) {
-        segment = ringSegments[0];
-        var n = segment.length - 1,
-            i = -1,
-            point;
-        if (n > 0) {
-          if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
-          listener.lineStart();
-          while (++i < n) listener.point((point = segment[i])[0], point[1]);
-          listener.lineEnd();
+        if (current != null && (computed === undefined
+              ? (current === current && !isSymbol(current))
+              : comparator(current, computed)
+            )) {
+          var computed = current,
+              result = value;
         }
-        return;
       }
-
-      // Rejoin connected segments.
-      // TODO reuse bufferListener.rejoin()?
-      if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
-
-      segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
+      return result;
     }
 
-    return clip;
-  };
-}
-
-function d3_geo_clipSegmentLength1(segment) {
-  return segment.length > 1;
-}
+    /**
+     * The base implementation of `_.fill` without an iteratee call guard.
+     *
+     * @private
+     * @param {Array} array The array to fill.
+     * @param {*} value The value to fill `array` with.
+     * @param {number} [start=0] The start position.
+     * @param {number} [end=array.length] The end position.
+     * @returns {Array} Returns `array`.
+     */
+    function baseFill(array, value, start, end) {
+      var length = array.length;
 
-function d3_geo_clipBufferListener() {
-  var lines = [],
-      line;
-  return {
-    lineStart: function() { lines.push(line = []); },
-    point: function(λ, φ) { line.push([λ, φ]); },
-    lineEnd: d3_noop,
-    buffer: function() {
-      var buffer = lines;
-      lines = [];
-      line = null;
-      return buffer;
-    },
-    rejoin: function() {
-      if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
+      start = toInteger(start);
+      if (start < 0) {
+        start = -start > length ? 0 : (length + start);
+      }
+      end = (end === undefined || end > length) ? length : toInteger(end);
+      if (end < 0) {
+        end += length;
+      }
+      end = start > end ? 0 : toLength(end);
+      while (start < end) {
+        array[start++] = value;
+      }
+      return array;
     }
-  };
-}
 
-// Intersection points are sorted along the clip edge. For both antimeridian
-// cutting and circle clipping, the same comparison is used.
-function d3_geo_clipSort(a, b) {
-  return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1])
-       - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);
-}
+    /**
+     * The base implementation of `_.filter` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} predicate The function invoked per iteration.
+     * @returns {Array} Returns the new filtered array.
+     */
+    function baseFilter(collection, predicate) {
+      var result = [];
+      baseEach(collection, function(value, index, collection) {
+        if (predicate(value, index, collection)) {
+          result.push(value);
+        }
+      });
+      return result;
+    }
 
-var d3_geo_clipAntimeridian = d3_geo_clip(
-    d3_true,
-    d3_geo_clipAntimeridianLine,
-    d3_geo_clipAntimeridianInterpolate,
-    [-π, -π / 2]);
+    /**
+     * The base implementation of `_.flatten` with support for restricting flattening.
+     *
+     * @private
+     * @param {Array} array The array to flatten.
+     * @param {number} depth The maximum recursion depth.
+     * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
+     * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
+     * @param {Array} [result=[]] The initial result value.
+     * @returns {Array} Returns the new flattened array.
+     */
+    function baseFlatten(array, depth, predicate, isStrict, result) {
+      var index = -1,
+          length = array.length;
 
-// Takes a line and cuts into visible segments. Return values:
-//   0: there were intersections or the line was empty.
-//   1: no intersections.
-//   2: there were intersections, and the first and last segments should be
-//      rejoined.
-function d3_geo_clipAntimeridianLine(listener) {
-  var λ0 = NaN,
-      φ0 = NaN,
-      sλ0 = NaN,
-      clean; // no intersections
+      predicate || (predicate = isFlattenable);
+      result || (result = []);
 
-  return {
-    lineStart: function() {
-      listener.lineStart();
-      clean = 1;
-    },
-    point: function(λ1, φ1) {
-      var sλ1 = λ1 > 0 ? π : -π,
-          dλ = abs(λ1 - λ0);
-      if (abs(dλ - π) < ε) { // line crosses a pole
-        listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
-        listener.point(sλ0, φ0);
-        listener.lineEnd();
-        listener.lineStart();
-        listener.point(sλ1, φ0);
-        listener.point(λ1, φ0);
-        clean = 0;
-      } else if (sλ0 !== sλ1 && dλ >= π) { // line crosses antimeridian
-        // handle degeneracies
-        if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
-        if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
-        φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
-        listener.point(sλ0, φ0);
-        listener.lineEnd();
-        listener.lineStart();
-        listener.point(sλ1, φ0);
-        clean = 0;
+      while (++index < length) {
+        var value = array[index];
+        if (depth > 0 && predicate(value)) {
+          if (depth > 1) {
+            // Recursively flatten arrays (susceptible to call stack limits).
+            baseFlatten(value, depth - 1, predicate, isStrict, result);
+          } else {
+            arrayPush(result, value);
+          }
+        } else if (!isStrict) {
+          result[result.length] = value;
+        }
       }
-      listener.point(λ0 = λ1, φ0 = φ1);
-      sλ0 = sλ1;
-    },
-    lineEnd: function() {
-      listener.lineEnd();
-      λ0 = φ0 = NaN;
-    },
-    // if there are intersections, we always rejoin the first and last segments.
-    clean: function() { return 2 - clean; }
-  };
-}
-
-function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
-  var cosφ0,
-      cosφ1,
-      sinλ0_λ1 = Math.sin(λ0 - λ1);
-  return abs(sinλ0_λ1) > ε
-      ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1)
-                 - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0))
-                 / (cosφ0 * cosφ1 * sinλ0_λ1))
-      : (φ0 + φ1) / 2;
-}
+      return result;
+    }
 
-function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
-  var φ;
-  if (from == null) {
-    φ = direction * halfπ;
-    listener.point(-π,  φ);
-    listener.point( 0,  φ);
-    listener.point( π,  φ);
-    listener.point( π,  0);
-    listener.point( π, -φ);
-    listener.point( 0, -φ);
-    listener.point(-π, -φ);
-    listener.point(-π,  0);
-    listener.point(-π,  φ);
-  } else if (abs(from[0] - to[0]) > ε) {
-    var s = from[0] < to[0] ? π : -π;
-    φ = direction * s / 2;
-    listener.point(-s, φ);
-    listener.point( 0, φ);
-    listener.point( s, φ);
-  } else {
-    listener.point(to[0], to[1]);
-  }
-}
-// TODO
-// cross and scale return new vectors,
-// whereas add and normalize operate in-place
+    /**
+     * The base implementation of `baseForOwn` which iterates over `object`
+     * properties returned by `keysFunc` and invokes `iteratee` for each property.
+     * Iteratee functions may exit iteration early by explicitly returning `false`.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @param {Function} keysFunc The function to get the keys of `object`.
+     * @returns {Object} Returns `object`.
+     */
+    var baseFor = createBaseFor();
 
-function d3_geo_cartesian(spherical) {
-  var λ = spherical[0],
-      φ = spherical[1],
-      cosφ = Math.cos(φ);
-  return [
-    cosφ * Math.cos(λ),
-    cosφ * Math.sin(λ),
-    Math.sin(φ)
-  ];
-}
+    /**
+     * This function is like `baseFor` except that it iterates over properties
+     * in the opposite order.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @param {Function} keysFunc The function to get the keys of `object`.
+     * @returns {Object} Returns `object`.
+     */
+    var baseForRight = createBaseFor(true);
 
-function d3_geo_cartesianDot(a, b) {
-  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
-}
+    /**
+     * The base implementation of `_.forOwn` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Object} Returns `object`.
+     */
+    function baseForOwn(object, iteratee) {
+      return object && baseFor(object, iteratee, keys);
+    }
 
-function d3_geo_cartesianCross(a, b) {
-  return [
-    a[1] * b[2] - a[2] * b[1],
-    a[2] * b[0] - a[0] * b[2],
-    a[0] * b[1] - a[1] * b[0]
-  ];
-}
+    /**
+     * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Object} Returns `object`.
+     */
+    function baseForOwnRight(object, iteratee) {
+      return object && baseForRight(object, iteratee, keys);
+    }
 
-function d3_geo_cartesianAdd(a, b) {
-  a[0] += b[0];
-  a[1] += b[1];
-  a[2] += b[2];
-}
+    /**
+     * The base implementation of `_.functions` which creates an array of
+     * `object` function property names filtered from `props`.
+     *
+     * @private
+     * @param {Object} object The object to inspect.
+     * @param {Array} props The property names to filter.
+     * @returns {Array} Returns the function names.
+     */
+    function baseFunctions(object, props) {
+      return arrayFilter(props, function(key) {
+        return isFunction(object[key]);
+      });
+    }
 
-function d3_geo_cartesianScale(vector, k) {
-  return [
-    vector[0] * k,
-    vector[1] * k,
-    vector[2] * k
-  ];
-}
+    /**
+     * The base implementation of `_.get` without support for default values.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path of the property to get.
+     * @returns {*} Returns the resolved value.
+     */
+    function baseGet(object, path) {
+      path = isKey(path, object) ? [path] : castPath(path);
 
-function d3_geo_cartesianNormalize(d) {
-  var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
-  d[0] /= l;
-  d[1] /= l;
-  d[2] /= l;
-}
-function d3_geo_compose(a, b) {
+      var index = 0,
+          length = path.length;
 
-  function compose(x, y) {
-    return x = a(x, y), b(x[0], x[1]);
-  }
+      while (object != null && index < length) {
+        object = object[toKey(path[index++])];
+      }
+      return (index && index == length) ? object : undefined;
+    }
 
-  if (a.invert && b.invert) compose.invert = function(x, y) {
-    return x = b.invert(x, y), x && a.invert(x[0], x[1]);
-  };
+    /**
+     * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
+     * `keysFunc` and `symbolsFunc` to get the enumerable property names and
+     * symbols of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {Function} keysFunc The function to get the keys of `object`.
+     * @param {Function} symbolsFunc The function to get the symbols of `object`.
+     * @returns {Array} Returns the array of property names and symbols.
+     */
+    function baseGetAllKeys(object, keysFunc, symbolsFunc) {
+      var result = keysFunc(object);
+      return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
+    }
 
-  return compose;
-}
+    /**
+     * The base implementation of `getTag` without fallbacks for buggy environments.
+     *
+     * @private
+     * @param {*} value The value to query.
+     * @returns {string} Returns the `toStringTag`.
+     */
+    function baseGetTag(value) {
+      if (value == null) {
+        return value === undefined ? undefinedTag : nullTag;
+      }
+      value = Object(value);
+      return (symToStringTag && symToStringTag in value)
+        ? getRawTag(value)
+        : objectToString(value);
+    }
 
-function d3_geo_equirectangular(λ, φ) {
-  return [λ, φ];
-}
+    /**
+     * The base implementation of `_.gt` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if `value` is greater than `other`,
+     *  else `false`.
+     */
+    function baseGt(value, other) {
+      return value > other;
+    }
 
-(d3.geo.equirectangular = function() {
-  return d3_geo_projection(d3_geo_equirectangular);
-}).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
+    /**
+     * The base implementation of `_.has` without support for deep paths.
+     *
+     * @private
+     * @param {Object} [object] The object to query.
+     * @param {Array|string} key The key to check.
+     * @returns {boolean} Returns `true` if `key` exists, else `false`.
+     */
+    function baseHas(object, key) {
+      return object != null && hasOwnProperty.call(object, key);
+    }
 
-d3.geo.rotation = function(rotate) {
-  rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);
+    /**
+     * The base implementation of `_.hasIn` without support for deep paths.
+     *
+     * @private
+     * @param {Object} [object] The object to query.
+     * @param {Array|string} key The key to check.
+     * @returns {boolean} Returns `true` if `key` exists, else `false`.
+     */
+    function baseHasIn(object, key) {
+      return object != null && key in Object(object);
+    }
 
-  function forward(coordinates) {
-    coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
-    return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
-  }
+    /**
+     * The base implementation of `_.inRange` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {number} number The number to check.
+     * @param {number} start The start of the range.
+     * @param {number} end The end of the range.
+     * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
+     */
+    function baseInRange(number, start, end) {
+      return number >= nativeMin(start, end) && number < nativeMax(start, end);
+    }
 
-  forward.invert = function(coordinates) {
-    coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
-    return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
-  };
+    /**
+     * The base implementation of methods like `_.intersection`, without support
+     * for iteratee shorthands, that accepts an array of arrays to inspect.
+     *
+     * @private
+     * @param {Array} arrays The arrays to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of shared values.
+     */
+    function baseIntersection(arrays, iteratee, comparator) {
+      var includes = comparator ? arrayIncludesWith : arrayIncludes,
+          length = arrays[0].length,
+          othLength = arrays.length,
+          othIndex = othLength,
+          caches = Array(othLength),
+          maxLength = Infinity,
+          result = [];
+
+      while (othIndex--) {
+        var array = arrays[othIndex];
+        if (othIndex && iteratee) {
+          array = arrayMap(array, baseUnary(iteratee));
+        }
+        maxLength = nativeMin(array.length, maxLength);
+        caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
+          ? new SetCache(othIndex && array)
+          : undefined;
+      }
+      array = arrays[0];
 
-  return forward;
-};
+      var index = -1,
+          seen = caches[0];
 
-function d3_geo_identityRotation(λ, φ) {
-  return [λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ];
-}
+      outer:
+      while (++index < length && result.length < maxLength) {
+        var value = array[index],
+            computed = iteratee ? iteratee(value) : value;
 
-d3_geo_identityRotation.invert = d3_geo_equirectangular;
+        value = (comparator || value !== 0) ? value : 0;
+        if (!(seen
+              ? cacheHas(seen, computed)
+              : includes(result, computed, comparator)
+            )) {
+          othIndex = othLength;
+          while (--othIndex) {
+            var cache = caches[othIndex];
+            if (!(cache
+                  ? cacheHas(cache, computed)
+                  : includes(arrays[othIndex], computed, comparator))
+                ) {
+              continue outer;
+            }
+          }
+          if (seen) {
+            seen.push(computed);
+          }
+          result.push(value);
+        }
+      }
+      return result;
+    }
 
-// Note: |δλ| must be < 2π
-function d3_geo_rotation(δλ, δφ, δγ) {
-  return δλ ? (δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ))
-    : d3_geo_rotationλ(δλ))
-    : (δφ || δγ ? d3_geo_rotationφγ(δφ, δγ)
-    : d3_geo_identityRotation);
-}
+    /**
+     * The base implementation of `_.invert` and `_.invertBy` which inverts
+     * `object` with values transformed by `iteratee` and set by `setter`.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} setter The function to set `accumulator` values.
+     * @param {Function} iteratee The iteratee to transform values.
+     * @param {Object} accumulator The initial inverted object.
+     * @returns {Function} Returns `accumulator`.
+     */
+    function baseInverter(object, setter, iteratee, accumulator) {
+      baseForOwn(object, function(value, key, object) {
+        setter(accumulator, iteratee(value), key, object);
+      });
+      return accumulator;
+    }
 
-function d3_geo_forwardRotationλ(δλ) {
-  return function(λ, φ) {
-    return λ += δλ, [λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ];
-  };
-}
+    /**
+     * The base implementation of `_.invoke` without support for individual
+     * method arguments.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path of the method to invoke.
+     * @param {Array} args The arguments to invoke the method with.
+     * @returns {*} Returns the result of the invoked method.
+     */
+    function baseInvoke(object, path, args) {
+      if (!isKey(path, object)) {
+        path = castPath(path);
+        object = parent(object, path);
+        path = last(path);
+      }
+      var func = object == null ? object : object[toKey(path)];
+      return func == null ? undefined : apply(func, object, args);
+    }
 
-function d3_geo_rotationλ(δλ) {
-  var rotation = d3_geo_forwardRotationλ(δλ);
-  rotation.invert = d3_geo_forwardRotationλ(-δλ);
-  return rotation;
-}
+    /**
+     * The base implementation of `_.isArguments`.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+     */
+    function baseIsArguments(value) {
+      return isObjectLike(value) && baseGetTag(value) == argsTag;
+    }
 
-function d3_geo_rotationφγ(δφ, δγ) {
-  var cosδφ = Math.cos(δφ),
-      sinδφ = Math.sin(δφ),
-      cosδγ = Math.cos(δγ),
-      sinδγ = Math.sin(δγ);
+    /**
+     * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
+     */
+    function baseIsArrayBuffer(value) {
+      return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
+    }
 
-  function rotation(λ, φ) {
-    var cosφ = Math.cos(φ),
-        x = Math.cos(λ) * cosφ,
-        y = Math.sin(λ) * cosφ,
-        z = Math.sin(φ),
-        k = z * cosδφ + x * sinδφ;
-    return [
-      Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ),
-      d3_asin(k * cosδγ + y * sinδγ)
-    ];
-  }
+    /**
+     * The base implementation of `_.isDate` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
+     */
+    function baseIsDate(value) {
+      return isObjectLike(value) && baseGetTag(value) == dateTag;
+    }
 
-  rotation.invert = function(λ, φ) {
-    var cosφ = Math.cos(φ),
-        x = Math.cos(λ) * cosφ,
-        y = Math.sin(λ) * cosφ,
-        z = Math.sin(φ),
-        k = z * cosδγ - y * sinδγ;
-    return [
-      Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ),
-      d3_asin(k * cosδφ - x * sinδφ)
-    ];
-  };
+    /**
+     * The base implementation of `_.isEqual` which supports partial comparisons
+     * and tracks traversed objects.
+     *
+     * @private
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @param {boolean} bitmask The bitmask flags.
+     *  1 - Unordered comparison
+     *  2 - Partial comparison
+     * @param {Function} [customizer] The function to customize comparisons.
+     * @param {Object} [stack] Tracks traversed `value` and `other` objects.
+     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+     */
+    function baseIsEqual(value, other, bitmask, customizer, stack) {
+      if (value === other) {
+        return true;
+      }
+      if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
+        return value !== value && other !== other;
+      }
+      return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
+    }
 
-  return rotation;
-}
-
-d3.geo.circle = function() {
-  var origin = [0, 0],
-      angle,
-      precision = 6,
-      interpolate;
-
-  function circle() {
-    var center = typeof origin === "function" ? origin.apply(this, arguments) : origin,
-        rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert,
-        ring = [];
+    /**
+     * A specialized version of `baseIsEqual` for arrays and objects which performs
+     * deep comparisons and tracks traversed objects enabling objects with circular
+     * references to be compared.
+     *
+     * @private
+     * @param {Object} object The object to compare.
+     * @param {Object} other The other object to compare.
+     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+     * @param {Function} customizer The function to customize comparisons.
+     * @param {Function} equalFunc The function to determine equivalents of values.
+     * @param {Object} [stack] Tracks traversed `object` and `other` objects.
+     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+     */
+    function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
+      var objIsArr = isArray(object),
+          othIsArr = isArray(other),
+          objTag = arrayTag,
+          othTag = arrayTag;
+
+      if (!objIsArr) {
+        objTag = getTag(object);
+        objTag = objTag == argsTag ? objectTag : objTag;
+      }
+      if (!othIsArr) {
+        othTag = getTag(other);
+        othTag = othTag == argsTag ? objectTag : othTag;
+      }
+      var objIsObj = objTag == objectTag,
+          othIsObj = othTag == objectTag,
+          isSameTag = objTag == othTag;
 
-    interpolate(null, null, 1, {
-      point: function(x, y) {
-        ring.push(x = rotate(x, y));
-        x[0] *= d3_degrees, x[1] *= d3_degrees;
+      if (isSameTag && isBuffer(object)) {
+        if (!isBuffer(other)) {
+          return false;
+        }
+        objIsArr = true;
+        objIsObj = false;
       }
-    });
+      if (isSameTag && !objIsObj) {
+        stack || (stack = new Stack);
+        return (objIsArr || isTypedArray(object))
+          ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
+          : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
+      }
+      if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
+        var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+            othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
 
-    return {type: "Polygon", coordinates: [ring]};
-  }
+        if (objIsWrapped || othIsWrapped) {
+          var objUnwrapped = objIsWrapped ? object.value() : object,
+              othUnwrapped = othIsWrapped ? other.value() : other;
 
-  circle.origin = function(x) {
-    if (!arguments.length) return origin;
-    origin = x;
-    return circle;
-  };
+          stack || (stack = new Stack);
+          return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
+        }
+      }
+      if (!isSameTag) {
+        return false;
+      }
+      stack || (stack = new Stack);
+      return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
+    }
 
-  circle.angle = function(x) {
-    if (!arguments.length) return angle;
-    interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
-    return circle;
-  };
+    /**
+     * The base implementation of `_.isMap` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
+     */
+    function baseIsMap(value) {
+      return isObjectLike(value) && getTag(value) == mapTag;
+    }
 
-  circle.precision = function(_) {
-    if (!arguments.length) return precision;
-    interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
-    return circle;
-  };
+    /**
+     * The base implementation of `_.isMatch` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Object} object The object to inspect.
+     * @param {Object} source The object of property values to match.
+     * @param {Array} matchData The property names, values, and compare flags to match.
+     * @param {Function} [customizer] The function to customize comparisons.
+     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+     */
+    function baseIsMatch(object, source, matchData, customizer) {
+      var index = matchData.length,
+          length = index,
+          noCustomizer = !customizer;
 
-  return circle.angle(90);
-};
+      if (object == null) {
+        return !length;
+      }
+      object = Object(object);
+      while (index--) {
+        var data = matchData[index];
+        if ((noCustomizer && data[2])
+              ? data[1] !== object[data[0]]
+              : !(data[0] in object)
+            ) {
+          return false;
+        }
+      }
+      while (++index < length) {
+        data = matchData[index];
+        var key = data[0],
+            objValue = object[key],
+            srcValue = data[1];
 
-// Interpolates along a circle centered at [0°, 0°], with a given radius and
-// precision.
-function d3_geo_circleInterpolate(radius, precision) {
-  var cr = Math.cos(radius),
-      sr = Math.sin(radius);
-  return function(from, to, direction, listener) {
-    var step = direction * precision;
-    if (from != null) {
-      from = d3_geo_circleAngle(cr, from);
-      to = d3_geo_circleAngle(cr, to);
-      if (direction > 0 ? from < to: from > to) from += direction * τ;
-    } else {
-      from = radius + direction * τ;
-      to = radius - .5 * step;
-    }
-    for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
-      listener.point((point = d3_geo_spherical([
-        cr,
-        -sr * Math.cos(t),
-        -sr * Math.sin(t)
-      ]))[0], point[1]);
+        if (noCustomizer && data[2]) {
+          if (objValue === undefined && !(key in object)) {
+            return false;
+          }
+        } else {
+          var stack = new Stack;
+          if (customizer) {
+            var result = customizer(objValue, srcValue, key, object, source, stack);
+          }
+          if (!(result === undefined
+                ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
+                : result
+              )) {
+            return false;
+          }
+        }
+      }
+      return true;
     }
-  };
-}
-
-// Signed angle of a cartesian point relative to [cr, 0, 0].
-function d3_geo_circleAngle(cr, point) {
-  var a = d3_geo_cartesian(point);
-  a[0] -= cr;
-  d3_geo_cartesianNormalize(a);
-  var angle = d3_acos(-a[1]);
-  return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
-}
-// Adds floating point numbers with twice the normal precision.
-// Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
-// Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
-// 305–363 (1997).
-// Code adapted from GeographicLib by Charles F. F. Karney,
-// http://geographiclib.sourceforge.net/
-// See lib/geographiclib/LICENSE for details.
-
-function d3_adder() {}
 
-d3_adder.prototype = {
-  s: 0, // rounded value
-  t: 0, // exact error
-  add: function(y) {
-    d3_adderSum(y, this.t, d3_adderTemp);
-    d3_adderSum(d3_adderTemp.s, this.s, this);
-    if (this.s) this.t += d3_adderTemp.t;
-    else this.s = d3_adderTemp.t;
-  },
-  reset: function() {
-    this.s = this.t = 0;
-  },
-  valueOf: function() {
-    return this.s;
-  }
-};
+    /**
+     * The base implementation of `_.isNative` without bad shim checks.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a native function,
+     *  else `false`.
+     */
+    function baseIsNative(value) {
+      if (!isObject(value) || isMasked(value)) {
+        return false;
+      }
+      var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
+      return pattern.test(toSource(value));
+    }
 
-var d3_adderTemp = new d3_adder;
+    /**
+     * The base implementation of `_.isRegExp` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
+     */
+    function baseIsRegExp(value) {
+      return isObjectLike(value) && baseGetTag(value) == regexpTag;
+    }
 
-function d3_adderSum(a, b, o) {
-  var x = o.s = a + b, // a + b
-      bv = x - a, av = x - bv; // b_virtual & a_virtual
-  o.t = (a - av) + (b - bv); // a_roundoff + b_roundoff
-}
+    /**
+     * The base implementation of `_.isSet` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
+     */
+    function baseIsSet(value) {
+      return isObjectLike(value) && getTag(value) == setTag;
+    }
 
-d3.geo.area = function(object) {
-  d3_geo_areaSum = 0;
-  d3.geo.stream(object, d3_geo_area);
-  return d3_geo_areaSum;
-};
+    /**
+     * The base implementation of `_.isTypedArray` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+     */
+    function baseIsTypedArray(value) {
+      return isObjectLike(value) &&
+        isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
+    }
 
-var d3_geo_areaSum,
-    d3_geo_areaRingSum = new d3_adder;
+    /**
+     * The base implementation of `_.iteratee`.
+     *
+     * @private
+     * @param {*} [value=_.identity] The value to convert to an iteratee.
+     * @returns {Function} Returns the iteratee.
+     */
+    function baseIteratee(value) {
+      // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
+      // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
+      if (typeof value == 'function') {
+        return value;
+      }
+      if (value == null) {
+        return identity;
+      }
+      if (typeof value == 'object') {
+        return isArray(value)
+          ? baseMatchesProperty(value[0], value[1])
+          : baseMatches(value);
+      }
+      return property(value);
+    }
 
-var d3_geo_area = {
-  sphere: function() { d3_geo_areaSum += 4 * π; },
-  point: d3_noop,
-  lineStart: d3_noop,
-  lineEnd: d3_noop,
+    /**
+     * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names.
+     */
+    function baseKeys(object) {
+      if (!isPrototype(object)) {
+        return nativeKeys(object);
+      }
+      var result = [];
+      for (var key in Object(object)) {
+        if (hasOwnProperty.call(object, key) && key != 'constructor') {
+          result.push(key);
+        }
+      }
+      return result;
+    }
 
-  // Only count area for polygon rings.
-  polygonStart: function() {
-    d3_geo_areaRingSum.reset();
-    d3_geo_area.lineStart = d3_geo_areaRingStart;
-  },
-  polygonEnd: function() {
-    var area = 2 * d3_geo_areaRingSum;
-    d3_geo_areaSum += area < 0 ? 4 * π + area : area;
-    d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
-  }
-};
+    /**
+     * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names.
+     */
+    function baseKeysIn(object) {
+      if (!isObject(object)) {
+        return nativeKeysIn(object);
+      }
+      var isProto = isPrototype(object),
+          result = [];
 
-function d3_geo_areaRingStart() {
-  var λ00, φ00, λ0, cosφ0, sinφ0; // start point and previous point
+      for (var key in object) {
+        if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+          result.push(key);
+        }
+      }
+      return result;
+    }
 
-  // For the first point, …
-  d3_geo_area.point = function(λ, φ) {
-    d3_geo_area.point = nextPoint;
-    λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), sinφ0 = Math.sin(φ);
-  };
+    /**
+     * The base implementation of `_.lt` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if `value` is less than `other`,
+     *  else `false`.
+     */
+    function baseLt(value, other) {
+      return value < other;
+    }
 
-  // For subsequent points, …
-  function nextPoint(λ, φ) {
-    λ *= d3_radians;
-    φ = φ * d3_radians / 2 + π / 4; // half the angular distance from south pole
+    /**
+     * The base implementation of `_.map` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Array} Returns the new mapped array.
+     */
+    function baseMap(collection, iteratee) {
+      var index = -1,
+          result = isArrayLike(collection) ? Array(collection.length) : [];
 
-    // Spherical excess E for a spherical triangle with vertices: south pole,
-    // previous point, current point.  Uses a formula derived from Cagnoli’s
-    // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
-    var dλ = λ - λ0,
-        sdλ = dλ >= 0 ? 1 : -1,
-        adλ = sdλ * dλ,
-        cosφ = Math.cos(φ),
-        sinφ = Math.sin(φ),
-        k = sinφ0 * sinφ,
-        u = cosφ0 * cosφ + k * Math.cos(adλ),
-        v = k * sdλ * Math.sin(adλ);
-    d3_geo_areaRingSum.add(Math.atan2(v, u));
+      baseEach(collection, function(value, key, collection) {
+        result[++index] = iteratee(value, key, collection);
+      });
+      return result;
+    }
 
-    // Advance the previous points.
-    λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
-  }
+    /**
+     * The base implementation of `_.matches` which doesn't clone `source`.
+     *
+     * @private
+     * @param {Object} source The object of property values to match.
+     * @returns {Function} Returns the new spec function.
+     */
+    function baseMatches(source) {
+      var matchData = getMatchData(source);
+      if (matchData.length == 1 && matchData[0][2]) {
+        return matchesStrictComparable(matchData[0][0], matchData[0][1]);
+      }
+      return function(object) {
+        return object === source || baseIsMatch(object, source, matchData);
+      };
+    }
 
-  // For the last point, return to the start.
-  d3_geo_area.lineEnd = function() {
-    nextPoint(λ00, φ00);
-  };
-}
+    /**
+     * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
+     *
+     * @private
+     * @param {string} path The path of the property to get.
+     * @param {*} srcValue The value to match.
+     * @returns {Function} Returns the new spec function.
+     */
+    function baseMatchesProperty(path, srcValue) {
+      if (isKey(path) && isStrictComparable(srcValue)) {
+        return matchesStrictComparable(toKey(path), srcValue);
+      }
+      return function(object) {
+        var objValue = get(object, path);
+        return (objValue === undefined && objValue === srcValue)
+          ? hasIn(object, path)
+          : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
+      };
+    }
 
-function d3_geo_pointInPolygon(point, polygon) {
-  var meridian = point[0],
-      parallel = point[1],
-      meridianNormal = [Math.sin(meridian), -Math.cos(meridian), 0],
-      polarAngle = 0,
-      winding = 0;
-  d3_geo_areaRingSum.reset();
+    /**
+     * The base implementation of `_.merge` without support for multiple sources.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @param {number} srcIndex The index of `source`.
+     * @param {Function} [customizer] The function to customize merged values.
+     * @param {Object} [stack] Tracks traversed source values and their merged
+     *  counterparts.
+     */
+    function baseMerge(object, source, srcIndex, customizer, stack) {
+      if (object === source) {
+        return;
+      }
+      baseFor(source, function(srcValue, key) {
+        if (isObject(srcValue)) {
+          stack || (stack = new Stack);
+          baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
+        }
+        else {
+          var newValue = customizer
+            ? customizer(object[key], srcValue, (key + ''), object, source, stack)
+            : undefined;
 
-  for (var i = 0, n = polygon.length; i < n; ++i) {
-    var ring = polygon[i],
-        m = ring.length;
-    if (!m) continue;
-    var point0 = ring[0],
-        λ0 = point0[0],
-        φ0 = point0[1] / 2 + π / 4,
-        sinφ0 = Math.sin(φ0),
-        cosφ0 = Math.cos(φ0),
-        j = 1;
-
-    while (true) {
-      if (j === m) j = 0;
-      point = ring[j];
-      var λ = point[0],
-          φ = point[1] / 2 + π / 4,
-          sinφ = Math.sin(φ),
-          cosφ = Math.cos(φ),
-          dλ = λ - λ0,
-          sdλ = dλ >= 0 ? 1 : -1,
-          adλ = sdλ * dλ,
-          antimeridian = adλ > π,
-          k = sinφ0 * sinφ;
-      d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));
-
-      polarAngle += antimeridian ? dλ + sdλ * τ : dλ;
-
-      // Are the longitudes either side of the point's meridian, and are the
-      // latitudes smaller than the parallel?
-      if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
-        var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));
-        d3_geo_cartesianNormalize(arc);
-        var intersection = d3_geo_cartesianCross(meridianNormal, arc);
-        d3_geo_cartesianNormalize(intersection);
-        var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
-        if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {
-          winding += antimeridian ^ dλ >= 0 ? 1 : -1;
-        }
-      }
-      if (!j++) break;
-      λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;
+          if (newValue === undefined) {
+            newValue = srcValue;
+          }
+          assignMergeValue(object, key, newValue);
+        }
+      }, keysIn);
     }
-  }
-
-  // First, determine whether the South pole is inside or outside:
-  //
-  // It is inside if:
-  // * the polygon winds around it in a clockwise direction.
-  // * the polygon does not (cumulatively) wind around it, but has a negative
-  //   (counter-clockwise) area.
-  //
-  // Second, count the (signed) number of times a segment crosses a meridian
-  // from the point to the South pole.  If it is zero, then the point is the
-  // same side as the South pole.
 
-  return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ (winding & 1);
-}
+    /**
+     * A specialized version of `baseMerge` for arrays and objects which performs
+     * deep merges and tracks traversed objects enabling objects with circular
+     * references to be merged.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @param {string} key The key of the value to merge.
+     * @param {number} srcIndex The index of `source`.
+     * @param {Function} mergeFunc The function to merge values.
+     * @param {Function} [customizer] The function to customize assigned values.
+     * @param {Object} [stack] Tracks traversed source values and their merged
+     *  counterparts.
+     */
+    function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
+      var objValue = object[key],
+          srcValue = source[key],
+          stacked = stack.get(srcValue);
 
-// Clip features against a small circle centered at [0°, 0°].
-function d3_geo_clipCircle(radius) {
-  var cr = Math.cos(radius),
-      smallRadius = cr > 0,
-      notHemisphere = abs(cr) > ε, // TODO optimise for this common case
-      interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
+      if (stacked) {
+        assignMergeValue(object, key, stacked);
+        return;
+      }
+      var newValue = customizer
+        ? customizer(objValue, srcValue, (key + ''), object, source, stack)
+        : undefined;
 
-  return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-π, radius - π]);
+      var isCommon = newValue === undefined;
 
-  function visible(λ, φ) {
-    return Math.cos(λ) * Math.cos(φ) > cr;
-  }
+      if (isCommon) {
+        var isArr = isArray(srcValue),
+            isBuff = !isArr && isBuffer(srcValue),
+            isTyped = !isArr && !isBuff && isTypedArray(srcValue);
 
-  // Takes a line and cuts into visible segments. Return values used for
-  // polygon clipping:
-  //   0: there were intersections or the line was empty.
-  //   1: no intersections.
-  //   2: there were intersections, and the first and last segments should be
-  //      rejoined.
-  function clipLine(listener) {
-    var point0, // previous point
-        c0, // code for previous point
-        v0, // visibility of previous point
-        v00, // visibility of first point
-        clean; // no intersections
-    return {
-      lineStart: function() {
-        v00 = v0 = false;
-        clean = 1;
-      },
-      point: function(λ, φ) {
-        var point1 = [λ, φ],
-            point2,
-            v = visible(λ, φ),
-            c = smallRadius
-              ? v ? 0 : code(λ, φ)
-              : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;
-        if (!point0 && (v00 = v0 = v)) listener.lineStart();
-        // Handle degeneracies.
-        // TODO ignore if not clipping polygons.
-        if (v !== v0) {
-          point2 = intersect(point0, point1);
-          if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
-            point1[0] += ε;
-            point1[1] += ε;
-            v = visible(point1[0], point1[1]);
+        newValue = srcValue;
+        if (isArr || isBuff || isTyped) {
+          if (isArray(objValue)) {
+            newValue = objValue;
+          }
+          else if (isArrayLikeObject(objValue)) {
+            newValue = copyArray(objValue);
+          }
+          else if (isBuff) {
+            isCommon = false;
+            newValue = cloneBuffer(srcValue, true);
+          }
+          else if (isTyped) {
+            isCommon = false;
+            newValue = cloneTypedArray(srcValue, true);
+          }
+          else {
+            newValue = [];
           }
         }
-        if (v !== v0) {
-          clean = 0;
-          if (v) {
-            // outside going in
-            listener.lineStart();
-            point2 = intersect(point1, point0);
-            listener.point(point2[0], point2[1]);
-          } else {
-            // inside going out
-            point2 = intersect(point0, point1);
-            listener.point(point2[0], point2[1]);
-            listener.lineEnd();
+        else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+          newValue = objValue;
+          if (isArguments(objValue)) {
+            newValue = toPlainObject(objValue);
           }
-          point0 = point2;
-        } else if (notHemisphere && point0 && smallRadius ^ v) {
-          var t;
-          // If the codes for two points are different, or are both zero,
-          // and there this segment intersects with the small circle.
-          if (!(c & c0) && (t = intersect(point1, point0, true))) {
-            clean = 0;
-            if (smallRadius) {
-              listener.lineStart();
-              listener.point(t[0][0], t[0][1]);
-              listener.point(t[1][0], t[1][1]);
-              listener.lineEnd();
-            } else {
-              listener.point(t[1][0], t[1][1]);
-              listener.lineEnd();
-              listener.lineStart();
-              listener.point(t[0][0], t[0][1]);
-            }
+          else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
+            newValue = initCloneObject(srcValue);
           }
         }
-        if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
-          listener.point(point1[0], point1[1]);
+        else {
+          isCommon = false;
         }
-        point0 = point1, v0 = v, c0 = c;
-      },
-      lineEnd: function() {
-        if (v0) listener.lineEnd();
-        point0 = null;
-      },
-      // Rejoin first and last segments if there were intersections and the first
-      // and last points were visible.
-      clean: function() { return clean | ((v00 && v0) << 1); }
-    };
-  }
+      }
+      if (isCommon) {
+        // Recursively merge objects and arrays (susceptible to call stack limits).
+        stack.set(srcValue, newValue);
+        mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
+        stack['delete'](srcValue);
+      }
+      assignMergeValue(object, key, newValue);
+    }
 
-  // Intersects the great circle between a and b with the clip circle.
-  function intersect(a, b, two) {
-    var pa = d3_geo_cartesian(a),
-        pb = d3_geo_cartesian(b);
+    /**
+     * The base implementation of `_.nth` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {Array} array The array to query.
+     * @param {number} n The index of the element to return.
+     * @returns {*} Returns the nth element of `array`.
+     */
+    function baseNth(array, n) {
+      var length = array.length;
+      if (!length) {
+        return;
+      }
+      n += n < 0 ? length : 0;
+      return isIndex(n, length) ? array[n] : undefined;
+    }
 
-    // We have two planes, n1.p = d1 and n2.p = d2.
-    // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
-    var n1 = [1, 0, 0], // normal
-        n2 = d3_geo_cartesianCross(pa, pb),
-        n2n2 = d3_geo_cartesianDot(n2, n2),
-        n1n2 = n2[0], // d3_geo_cartesianDot(n1, n2),
-        determinant = n2n2 - n1n2 * n1n2;
+    /**
+     * The base implementation of `_.orderBy` without param guards.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
+     * @param {string[]} orders The sort orders of `iteratees`.
+     * @returns {Array} Returns the new sorted array.
+     */
+    function baseOrderBy(collection, iteratees, orders) {
+      var index = -1;
+      iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee()));
 
-    // Two polar points.
-    if (!determinant) return !two && a;
+      var result = baseMap(collection, function(value, key, collection) {
+        var criteria = arrayMap(iteratees, function(iteratee) {
+          return iteratee(value);
+        });
+        return { 'criteria': criteria, 'index': ++index, 'value': value };
+      });
 
-    var c1 =  cr * n2n2 / determinant,
-        c2 = -cr * n1n2 / determinant,
-        n1xn2 = d3_geo_cartesianCross(n1, n2),
-        A = d3_geo_cartesianScale(n1, c1),
-        B = d3_geo_cartesianScale(n2, c2);
-    d3_geo_cartesianAdd(A, B);
+      return baseSortBy(result, function(object, other) {
+        return compareMultiple(object, other, orders);
+      });
+    }
 
-    // Solve |p(t)|^2 = 1.
-    var u = n1xn2,
-        w = d3_geo_cartesianDot(A, u),
-        uu = d3_geo_cartesianDot(u, u),
-        t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
+    /**
+     * The base implementation of `_.pick` without support for individual
+     * property identifiers.
+     *
+     * @private
+     * @param {Object} object The source object.
+     * @param {string[]} paths The property paths to pick.
+     * @returns {Object} Returns the new object.
+     */
+    function basePick(object, paths) {
+      object = Object(object);
+      return basePickBy(object, paths, function(value, path) {
+        return hasIn(object, path);
+      });
+    }
 
-    if (t2 < 0) return;
+    /**
+     * The base implementation of  `_.pickBy` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Object} object The source object.
+     * @param {string[]} paths The property paths to pick.
+     * @param {Function} predicate The function invoked per property.
+     * @returns {Object} Returns the new object.
+     */
+    function basePickBy(object, paths, predicate) {
+      var index = -1,
+          length = paths.length,
+          result = {};
 
-    var t = Math.sqrt(t2),
-        q = d3_geo_cartesianScale(u, (-w - t) / uu);
-    d3_geo_cartesianAdd(q, A);
-    q = d3_geo_spherical(q);
-    if (!two) return q;
+      while (++index < length) {
+        var path = paths[index],
+            value = baseGet(object, path);
 
-    // Two intersection points.
-    var λ0 = a[0],
-        λ1 = b[0],
-        φ0 = a[1],
-        φ1 = b[1],
-        z;
-    if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
-    var δλ = λ1 - λ0,
-        polar = abs(δλ - π) < ε,
-        meridian = polar || δλ < ε;
-
-    if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;
+        if (predicate(value, path)) {
+          baseSet(result, path, value);
+        }
+      }
+      return result;
+    }
 
-    // Check that the first point is between a and b.
-    if (meridian
-        ? polar
-          ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1)
-          : φ0 <= q[1] && q[1] <= φ1
-        : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {
-      var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
-      d3_geo_cartesianAdd(q1, A);
-      return [q, d3_geo_spherical(q1)];
+    /**
+     * A specialized version of `baseProperty` which supports deep paths.
+     *
+     * @private
+     * @param {Array|string} path The path of the property to get.
+     * @returns {Function} Returns the new accessor function.
+     */
+    function basePropertyDeep(path) {
+      return function(object) {
+        return baseGet(object, path);
+      };
     }
-  }
 
-  // Generates a 4-bit vector representing the location of a point relative to
-  // the small circle's bounding box.
-  function code(λ, φ) {
-    var r = smallRadius ? radius : π - radius,
-        code = 0;
-    if (λ < -r) code |= 1; // left
-    else if (λ > r) code |= 2; // right
-    if (φ < -r) code |= 4; // below
-    else if (φ > r) code |= 8; // above
-    return code;
-  }
-}
+    /**
+     * The base implementation of `_.pullAllBy` without support for iteratee
+     * shorthands.
+     *
+     * @private
+     * @param {Array} array The array to modify.
+     * @param {Array} values The values to remove.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns `array`.
+     */
+    function basePullAll(array, values, iteratee, comparator) {
+      var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
+          index = -1,
+          length = values.length,
+          seen = array;
 
-// Liang–Barsky line clipping.
-function d3_geom_clipLine(x0, y0, x1, y1) {
-  return function(line) {
-    var a = line.a,
-        b = line.b,
-        ax = a.x,
-        ay = a.y,
-        bx = b.x,
-        by = b.y,
-        t0 = 0,
-        t1 = 1,
-        dx = bx - ax,
-        dy = by - ay,
-        r;
+      if (array === values) {
+        values = copyArray(values);
+      }
+      if (iteratee) {
+        seen = arrayMap(array, baseUnary(iteratee));
+      }
+      while (++index < length) {
+        var fromIndex = 0,
+            value = values[index],
+            computed = iteratee ? iteratee(value) : value;
 
-    r = x0 - ax;
-    if (!dx && r > 0) return;
-    r /= dx;
-    if (dx < 0) {
-      if (r < t0) return;
-      if (r < t1) t1 = r;
-    } else if (dx > 0) {
-      if (r > t1) return;
-      if (r > t0) t0 = r;
-    }
-
-    r = x1 - ax;
-    if (!dx && r < 0) return;
-    r /= dx;
-    if (dx < 0) {
-      if (r > t1) return;
-      if (r > t0) t0 = r;
-    } else if (dx > 0) {
-      if (r < t0) return;
-      if (r < t1) t1 = r;
-    }
-
-    r = y0 - ay;
-    if (!dy && r > 0) return;
-    r /= dy;
-    if (dy < 0) {
-      if (r < t0) return;
-      if (r < t1) t1 = r;
-    } else if (dy > 0) {
-      if (r > t1) return;
-      if (r > t0) t0 = r;
-    }
-
-    r = y1 - ay;
-    if (!dy && r < 0) return;
-    r /= dy;
-    if (dy < 0) {
-      if (r > t1) return;
-      if (r > t0) t0 = r;
-    } else if (dy > 0) {
-      if (r < t0) return;
-      if (r < t1) t1 = r;
-    }
-
-    if (t0 > 0) line.a = {x: ax + t0 * dx, y: ay + t0 * dy};
-    if (t1 < 1) line.b = {x: ax + t1 * dx, y: ay + t1 * dy};
-    return line;
-  };
-}
-
-var d3_geo_clipExtentMAX = 1e9;
-
-d3.geo.clipExtent = function() {
-  var x0, y0, x1, y1,
-      stream,
-      clip,
-      clipExtent = {
-        stream: function(output) {
-          if (stream) stream.valid = false;
-          stream = clip(output);
-          stream.valid = true; // allow caching by d3.geo.path
-          return stream;
-        },
-        extent: function(_) {
-          if (!arguments.length) return [[x0, y0], [x1, y1]];
-          clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
-          if (stream) stream.valid = false, stream = null;
-          return clipExtent;
+        while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
+          if (seen !== array) {
+            splice.call(seen, fromIndex, 1);
+          }
+          splice.call(array, fromIndex, 1);
         }
-      };
-  return clipExtent.extent([[0, 0], [960, 500]]);
-};
+      }
+      return array;
+    }
 
-function d3_geo_clipExtent(x0, y0, x1, y1) {
-  return function(listener) {
-    var listener_ = listener,
-        bufferListener = d3_geo_clipBufferListener(),
-        clipLine = d3_geom_clipLine(x0, y0, x1, y1),
-        segments,
-        polygon,
-        ring;
+    /**
+     * The base implementation of `_.pullAt` without support for individual
+     * indexes or capturing the removed elements.
+     *
+     * @private
+     * @param {Array} array The array to modify.
+     * @param {number[]} indexes The indexes of elements to remove.
+     * @returns {Array} Returns `array`.
+     */
+    function basePullAt(array, indexes) {
+      var length = array ? indexes.length : 0,
+          lastIndex = length - 1;
 
-    var clip = {
-      point: point,
-      lineStart: lineStart,
-      lineEnd: lineEnd,
-      polygonStart: function() {
-        listener = bufferListener;
-        segments = [];
-        polygon = [];
-        clean = true;
-      },
-      polygonEnd: function() {
-        listener = listener_;
-        segments = d3.merge(segments);
-        var clipStartInside = insidePolygon([x0, y1]),
-            inside = clean && clipStartInside,
-            visible = segments.length;
-        if (inside || visible) {
-          listener.polygonStart();
-          if (inside) {
-            listener.lineStart();
-            interpolate(null, null, 1, listener);
-            listener.lineEnd();
+      while (length--) {
+        var index = indexes[length];
+        if (length == lastIndex || index !== previous) {
+          var previous = index;
+          if (isIndex(index)) {
+            splice.call(array, index, 1);
           }
-          if (visible) {
-            d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);
+          else if (!isKey(index, array)) {
+            var path = castPath(index),
+                object = parent(array, path);
+
+            if (object != null) {
+              delete object[toKey(last(path))];
+            }
+          }
+          else {
+            delete array[toKey(index)];
           }
-          listener.polygonEnd();
         }
-        segments = polygon = ring = null;
       }
-    };
+      return array;
+    }
+
+    /**
+     * The base implementation of `_.random` without support for returning
+     * floating-point numbers.
+     *
+     * @private
+     * @param {number} lower The lower bound.
+     * @param {number} upper The upper bound.
+     * @returns {number} Returns the random number.
+     */
+    function baseRandom(lower, upper) {
+      return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
+    }
 
-    function insidePolygon(p) {
-      var wn = 0, // the winding number counter
-          n = polygon.length,
-          y = p[1];
+    /**
+     * The base implementation of `_.range` and `_.rangeRight` which doesn't
+     * coerce arguments.
+     *
+     * @private
+     * @param {number} start The start of the range.
+     * @param {number} end The end of the range.
+     * @param {number} step The value to increment or decrement by.
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Array} Returns the range of numbers.
+     */
+    function baseRange(start, end, step, fromRight) {
+      var index = -1,
+          length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
+          result = Array(length);
 
-      for (var i = 0; i < n; ++i) {
-        for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
-          b = v[j];
-          if (a[1] <= y) {
-            if (b[1] >  y && d3_cross2d(a, b, p) > 0) ++wn;
-          } else {
-            if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;
-          }
-          a = b;
-        }
+      while (length--) {
+        result[fromRight ? length : ++index] = start;
+        start += step;
       }
-      return wn !== 0;
+      return result;
     }
 
-    function interpolate(from, to, direction, listener) {
-      var a = 0, a1 = 0;
-      if (from == null ||
-          (a = corner(from, direction)) !== (a1 = corner(to, direction)) ||
-          comparePoints(from, to) < 0 ^ direction > 0) {
-        do {
-          listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
-        } while ((a = (a + direction + 4) % 4) !== a1);
-      } else {
-        listener.point(to[0], to[1]);
+    /**
+     * The base implementation of `_.repeat` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {string} string The string to repeat.
+     * @param {number} n The number of times to repeat the string.
+     * @returns {string} Returns the repeated string.
+     */
+    function baseRepeat(string, n) {
+      var result = '';
+      if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
+        return result;
       }
-    }
+      // Leverage the exponentiation by squaring algorithm for a faster repeat.
+      // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
+      do {
+        if (n % 2) {
+          result += string;
+        }
+        n = nativeFloor(n / 2);
+        if (n) {
+          string += string;
+        }
+      } while (n);
 
-    function pointVisible(x, y) {
-      return x0 <= x && x <= x1 && y0 <= y && y <= y1;
+      return result;
     }
 
-    function point(x, y) {
-      if (pointVisible(x, y)) listener.point(x, y);
+    /**
+     * The base implementation of `_.rest` which doesn't validate or coerce arguments.
+     *
+     * @private
+     * @param {Function} func The function to apply a rest parameter to.
+     * @param {number} [start=func.length-1] The start position of the rest parameter.
+     * @returns {Function} Returns the new function.
+     */
+    function baseRest(func, start) {
+      return setToString(overRest(func, start, identity), func + '');
     }
 
-    var x__, y__, v__, // first point
-        x_, y_, v_, // previous point
-        first,
-        clean;
+    /**
+     * The base implementation of `_.sample`.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to sample.
+     * @returns {*} Returns the random element.
+     */
+    function baseSample(collection) {
+      return arraySample(values(collection));
+    }
 
-    function lineStart() {
-      clip.point = linePoint;
-      if (polygon) polygon.push(ring = []);
-      first = true;
-      v_ = false;
-      x_ = y_ = NaN;
+    /**
+     * The base implementation of `_.sampleSize` without param guards.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to sample.
+     * @param {number} n The number of elements to sample.
+     * @returns {Array} Returns the random elements.
+     */
+    function baseSampleSize(collection, n) {
+      var array = values(collection);
+      return shuffleSelf(array, baseClamp(n, 0, array.length));
     }
 
-    function lineEnd() {
-      // TODO rather than special-case polygons, simply handle them separately.
-      // Ideally, coincident intersection points should be jittered to avoid
-      // clipping issues.
-      if (segments) {
-        linePoint(x__, y__);
-        if (v__ && v_) bufferListener.rejoin();
-        segments.push(bufferListener.buffer());
+    /**
+     * The base implementation of `_.set`.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to set.
+     * @param {*} value The value to set.
+     * @param {Function} [customizer] The function to customize path creation.
+     * @returns {Object} Returns `object`.
+     */
+    function baseSet(object, path, value, customizer) {
+      if (!isObject(object)) {
+        return object;
       }
-      clip.point = point;
-      if (v_) listener.lineEnd();
-    }
+      path = isKey(path, object) ? [path] : castPath(path);
 
-    function linePoint(x, y) {
-      x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
-      y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
-      var v = pointVisible(x, y);
-      if (polygon) ring.push([x, y]);
-      if (first) {
-        x__ = x, y__ = y, v__ = v;
-        first = false;
-        if (v) {
-          listener.lineStart();
-          listener.point(x, y);
-        }
-      } else {
-        if (v && v_) listener.point(x, y);
-        else {
-          var l = {a: {x: x_, y: y_}, b: {x: x, y: y}};
-          if (clipLine(l)) {
-            if (!v_) {
-              listener.lineStart();
-              listener.point(l.a.x, l.a.y);
-            }
-            listener.point(l.b.x, l.b.y);
-            if (!v) listener.lineEnd();
-            clean = false;
-          } else if (v) {
-            listener.lineStart();
-            listener.point(x, y);
-            clean = false;
+      var index = -1,
+          length = path.length,
+          lastIndex = length - 1,
+          nested = object;
+
+      while (nested != null && ++index < length) {
+        var key = toKey(path[index]),
+            newValue = value;
+
+        if (index != lastIndex) {
+          var objValue = nested[key];
+          newValue = customizer ? customizer(objValue, key, nested) : undefined;
+          if (newValue === undefined) {
+            newValue = isObject(objValue)
+              ? objValue
+              : (isIndex(path[index + 1]) ? [] : {});
           }
         }
+        assignValue(nested, key, newValue);
+        nested = nested[key];
       }
-      x_ = x, y_ = y, v_ = v;
+      return object;
     }
 
-    return clip;
-  };
-
-  function corner(p, direction) {
-    return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3
-        : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1
-        : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0
-        : direction > 0 ? 3 : 2; // abs(p[1] - y1) < ε
-  }
-
-  function compare(a, b) {
-    return comparePoints(a.x, b.x);
-  }
-
-  function comparePoints(a, b) {
-    var ca = corner(a, 1),
-        cb = corner(b, 1);
-    return ca !== cb ? ca - cb
-        : ca === 0 ? b[1] - a[1]
-        : ca === 1 ? a[0] - b[0]
-        : ca === 2 ? a[1] - b[1]
-        : b[0] - a[0];
-  }
-}
-
-function d3_geo_conic(projectAt) {
-  var φ0 = 0,
-      φ1 = π / 3,
-      m = d3_geo_projectionMutator(projectAt),
-      p = m(φ0, φ1);
-
-  p.parallels = function(_) {
-    if (!arguments.length) return [φ0 / π * 180, φ1 / π * 180];
-    return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);
-  };
-
-  return p;
-}
-
-function d3_geo_conicEqualArea(φ0, φ1) {
-  var sinφ0 = Math.sin(φ0),
-      n = (sinφ0 + Math.sin(φ1)) / 2,
-      C = 1 + sinφ0 * (2 * n - sinφ0),
-      ρ0 = Math.sqrt(C) / n;
-
-  function forward(λ, φ) {
-    var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
-    return [
-      ρ * Math.sin(λ *= n),
-      ρ0 - ρ * Math.cos(λ)
-    ];
-  }
-
-  forward.invert = function(x, y) {
-    var ρ0_y = ρ0 - y;
-    return [
-      Math.atan2(x, ρ0_y) / n,
-      d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n))
-    ];
-  };
-
-  return forward;
-}
-
-(d3.geo.conicEqualArea = function() {
-  return d3_geo_conic(d3_geo_conicEqualArea);
-}).raw = d3_geo_conicEqualArea;
-
-// ESRI:102003
-d3.geo.albers = function() {
-  return d3.geo.conicEqualArea()
-      .rotate([96, 0])
-      .center([-.6, 38.7])
-      .parallels([29.5, 45.5])
-      .scale(1070);
-};
-
-// A composite projection for the United States, configured by default for
-// 960×500. Also works quite well at 960×600 with scale 1285. The set of
-// standard parallels for each region comes from USGS, which is published here:
-// http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
-d3.geo.albersUsa = function() {
-  var lower48 = d3.geo.albers();
-
-  // EPSG:3338
-  var alaska = d3.geo.conicEqualArea()
-      .rotate([154, 0])
-      .center([-2, 58.5])
-      .parallels([55, 65]);
-
-  // ESRI:102007
-  var hawaii = d3.geo.conicEqualArea()
-      .rotate([157, 0])
-      .center([-3, 19.9])
-      .parallels([8, 18]);
-
-  var point,
-      pointStream = {point: function(x, y) { point = [x, y]; }},
-      lower48Point,
-      alaskaPoint,
-      hawaiiPoint;
-
-  function albersUsa(coordinates) {
-    var x = coordinates[0], y = coordinates[1];
-    point = null;
-    (lower48Point(x, y), point)
-        || (alaskaPoint(x, y), point)
-        || hawaiiPoint(x, y);
-    return point;
-  }
-
-  albersUsa.invert = function(coordinates) {
-    var k = lower48.scale(),
-        t = lower48.translate(),
-        x = (coordinates[0] - t[0]) / k,
-        y = (coordinates[1] - t[1]) / k;
-    return (y >= .120 && y < .234 && x >= -.425 && x < -.214 ? alaska
-        : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii
-        : lower48).invert(coordinates);
-  };
-
-  // A naïve multi-projection stream.
-  // The projections must have mutually exclusive clip regions on the sphere,
-  // as this will avoid emitting interleaving lines and polygons.
-  albersUsa.stream = function(stream) {
-    var lower48Stream = lower48.stream(stream),
-        alaskaStream = alaska.stream(stream),
-        hawaiiStream = hawaii.stream(stream);
-    return {
-      point: function(x, y) {
-        lower48Stream.point(x, y);
-        alaskaStream.point(x, y);
-        hawaiiStream.point(x, y);
-      },
-      sphere: function() {
-        lower48Stream.sphere();
-        alaskaStream.sphere();
-        hawaiiStream.sphere();
-      },
-      lineStart: function() {
-        lower48Stream.lineStart();
-        alaskaStream.lineStart();
-        hawaiiStream.lineStart();
-      },
-      lineEnd: function() {
-        lower48Stream.lineEnd();
-        alaskaStream.lineEnd();
-        hawaiiStream.lineEnd();
-      },
-      polygonStart: function() {
-        lower48Stream.polygonStart();
-        alaskaStream.polygonStart();
-        hawaiiStream.polygonStart();
-      },
-      polygonEnd: function() {
-        lower48Stream.polygonEnd();
-        alaskaStream.polygonEnd();
-        hawaiiStream.polygonEnd();
-      }
+    /**
+     * The base implementation of `setData` without support for hot loop shorting.
+     *
+     * @private
+     * @param {Function} func The function to associate metadata with.
+     * @param {*} data The metadata.
+     * @returns {Function} Returns `func`.
+     */
+    var baseSetData = !metaMap ? identity : function(func, data) {
+      metaMap.set(func, data);
+      return func;
     };
-  };
-
-  albersUsa.precision = function(_) {
-    if (!arguments.length) return lower48.precision();
-    lower48.precision(_);
-    alaska.precision(_);
-    hawaii.precision(_);
-    return albersUsa;
-  };
 
-  albersUsa.scale = function(_) {
-    if (!arguments.length) return lower48.scale();
-    lower48.scale(_);
-    alaska.scale(_ * .35);
-    hawaii.scale(_);
-    return albersUsa.translate(lower48.translate());
-  };
+    /**
+     * The base implementation of `setToString` without support for hot loop shorting.
+     *
+     * @private
+     * @param {Function} func The function to modify.
+     * @param {Function} string The `toString` result.
+     * @returns {Function} Returns `func`.
+     */
+    var baseSetToString = !defineProperty ? identity : function(func, string) {
+      return defineProperty(func, 'toString', {
+        'configurable': true,
+        'enumerable': false,
+        'value': constant(string),
+        'writable': true
+      });
+    };
 
-  albersUsa.translate = function(_) {
-    if (!arguments.length) return lower48.translate();
-    var k = lower48.scale(), x = +_[0], y = +_[1];
+    /**
+     * The base implementation of `_.shuffle`.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to shuffle.
+     * @returns {Array} Returns the new shuffled array.
+     */
+    function baseShuffle(collection) {
+      return shuffleSelf(values(collection));
+    }
 
-    lower48Point = lower48
-        .translate(_)
-        .clipExtent([[x - .455 * k, y - .238 * k], [x + .455 * k, y + .238 * k]])
-        .stream(pointStream).point;
+    /**
+     * The base implementation of `_.slice` without an iteratee call guard.
+     *
+     * @private
+     * @param {Array} array The array to slice.
+     * @param {number} [start=0] The start position.
+     * @param {number} [end=array.length] The end position.
+     * @returns {Array} Returns the slice of `array`.
+     */
+    function baseSlice(array, start, end) {
+      var index = -1,
+          length = array.length;
 
-    alaskaPoint = alaska
-        .translate([x - .307 * k, y + .201 * k])
-        .clipExtent([[x - .425 * k + ε, y + .120 * k + ε], [x - .214 * k - ε, y + .234 * k - ε]])
-        .stream(pointStream).point;
+      if (start < 0) {
+        start = -start > length ? 0 : (length + start);
+      }
+      end = end > length ? length : end;
+      if (end < 0) {
+        end += length;
+      }
+      length = start > end ? 0 : ((end - start) >>> 0);
+      start >>>= 0;
 
-    hawaiiPoint = hawaii
-        .translate([x - .205 * k, y + .212 * k])
-        .clipExtent([[x - .214 * k + ε, y + .166 * k + ε], [x - .115 * k - ε, y + .234 * k - ε]])
-        .stream(pointStream).point;
+      var result = Array(length);
+      while (++index < length) {
+        result[index] = array[index + start];
+      }
+      return result;
+    }
 
-    return albersUsa;
-  };
+    /**
+     * The base implementation of `_.some` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} predicate The function invoked per iteration.
+     * @returns {boolean} Returns `true` if any element passes the predicate check,
+     *  else `false`.
+     */
+    function baseSome(collection, predicate) {
+      var result;
 
-  return albersUsa.scale(1070);
-};
+      baseEach(collection, function(value, index, collection) {
+        result = predicate(value, index, collection);
+        return !result;
+      });
+      return !!result;
+    }
 
-d3.geo.bounds = (function() {
-  var λ0, φ0, λ1, φ1, // bounds
-      λ_, // previous λ-coordinate
-      λ__, φ__, // first point
-      p0, // previous 3D point
-      dλSum,
-      ranges,
-      range;
-
-  var bound = {
-    point: point,
-    lineStart: lineStart,
-    lineEnd: lineEnd,
-
-    polygonStart: function() {
-      bound.point = ringPoint;
-      bound.lineStart = ringStart;
-      bound.lineEnd = ringEnd;
-      dλSum = 0;
-      d3_geo_area.polygonStart();
-    },
-    polygonEnd: function() {
-      d3_geo_area.polygonEnd();
-      bound.point = point;
-      bound.lineStart = lineStart;
-      bound.lineEnd = lineEnd;
-      if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90);
-      else if (dλSum > ε) φ1 = 90;
-      else if (dλSum < -ε) φ0 = -90;
-      range[0] = λ0, range[1] = λ1;
-    }
-  };
-
-  function point(λ, φ) {
-    ranges.push(range = [λ0 = λ, λ1 = λ]);
-    if (φ < φ0) φ0 = φ;
-    if (φ > φ1) φ1 = φ;
-  }
-
-  function linePoint(λ, φ) {
-    var p = d3_geo_cartesian([λ * d3_radians, φ * d3_radians]);
-    if (p0) {
-      var normal = d3_geo_cartesianCross(p0, p),
-          equatorial = [normal[1], -normal[0], 0],
-          inflection = d3_geo_cartesianCross(equatorial, normal);
-      d3_geo_cartesianNormalize(inflection);
-      inflection = d3_geo_spherical(inflection);
-      var dλ = λ - λ_,
-          s = dλ > 0 ? 1 : -1,
-          λi = inflection[0] * d3_degrees * s,
-          antimeridian = abs(dλ) > 180;
-      if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
-        var φi = inflection[1] * d3_degrees;
-        if (φi > φ1) φ1 = φi;
-      } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
-        var φi = -inflection[1] * d3_degrees;
-        if (φi < φ0) φ0 = φi;
-      } else {
-        if (φ < φ0) φ0 = φ;
-        if (φ > φ1) φ1 = φ;
+    /**
+     * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
+     * performs a binary search of `array` to determine the index at which `value`
+     * should be inserted into `array` in order to maintain its sort order.
+     *
+     * @private
+     * @param {Array} array The sorted array to inspect.
+     * @param {*} value The value to evaluate.
+     * @param {boolean} [retHighest] Specify returning the highest qualified index.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     */
+    function baseSortedIndex(array, value, retHighest) {
+      var low = 0,
+          high = array == null ? low : array.length;
+
+      if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+        while (low < high) {
+          var mid = (low + high) >>> 1,
+              computed = array[mid];
+
+          if (computed !== null && !isSymbol(computed) &&
+              (retHighest ? (computed <= value) : (computed < value))) {
+            low = mid + 1;
+          } else {
+            high = mid;
+          }
+        }
+        return high;
       }
-      if (antimeridian) {
-        if (λ < λ_) {
-          if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
+      return baseSortedIndexBy(array, value, identity, retHighest);
+    }
+
+    /**
+     * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
+     * which invokes `iteratee` for `value` and each element of `array` to compute
+     * their sort ranking. The iteratee is invoked with one argument; (value).
+     *
+     * @private
+     * @param {Array} array The sorted array to inspect.
+     * @param {*} value The value to evaluate.
+     * @param {Function} iteratee The iteratee invoked per element.
+     * @param {boolean} [retHighest] Specify returning the highest qualified index.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     */
+    function baseSortedIndexBy(array, value, iteratee, retHighest) {
+      value = iteratee(value);
+
+      var low = 0,
+          high = array == null ? 0 : array.length,
+          valIsNaN = value !== value,
+          valIsNull = value === null,
+          valIsSymbol = isSymbol(value),
+          valIsUndefined = value === undefined;
+
+      while (low < high) {
+        var mid = nativeFloor((low + high) / 2),
+            computed = iteratee(array[mid]),
+            othIsDefined = computed !== undefined,
+            othIsNull = computed === null,
+            othIsReflexive = computed === computed,
+            othIsSymbol = isSymbol(computed);
+
+        if (valIsNaN) {
+          var setLow = retHighest || othIsReflexive;
+        } else if (valIsUndefined) {
+          setLow = othIsReflexive && (retHighest || othIsDefined);
+        } else if (valIsNull) {
+          setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
+        } else if (valIsSymbol) {
+          setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
+        } else if (othIsNull || othIsSymbol) {
+          setLow = false;
         } else {
-          if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
+          setLow = retHighest ? (computed <= value) : (computed < value);
         }
-      } else {
-        if (λ1 >= λ0) {
-          if (λ < λ0) λ0 = λ;
-          if (λ > λ1) λ1 = λ;
+        if (setLow) {
+          low = mid + 1;
         } else {
-          if (λ > λ_) {
-            if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
-          } else {
-            if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
-          }
+          high = mid;
         }
       }
-    } else {
-      point(λ, φ);
+      return nativeMin(high, MAX_ARRAY_INDEX);
     }
-    p0 = p, λ_ = λ;
-  }
 
-  function lineStart() { bound.point = linePoint; }
-  function lineEnd() {
-    range[0] = λ0, range[1] = λ1;
-    bound.point = point;
-    p0 = null;
-  }
+    /**
+     * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
+     * support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @returns {Array} Returns the new duplicate free array.
+     */
+    function baseSortedUniq(array, iteratee) {
+      var index = -1,
+          length = array.length,
+          resIndex = 0,
+          result = [];
 
-  function ringPoint(λ, φ) {
-    if (p0) {
-      var dλ = λ - λ_;
-      dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
-    } else λ__ = λ, φ__ = φ;
-    d3_geo_area.point(λ, φ);
-    linePoint(λ, φ);
-  }
+      while (++index < length) {
+        var value = array[index],
+            computed = iteratee ? iteratee(value) : value;
 
-  function ringStart() {
-    d3_geo_area.lineStart();
-  }
+        if (!index || !eq(computed, seen)) {
+          var seen = computed;
+          result[resIndex++] = value === 0 ? 0 : value;
+        }
+      }
+      return result;
+    }
 
-  function ringEnd() {
-    ringPoint(λ__, φ__);
-    d3_geo_area.lineEnd();
-    if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
-    range[0] = λ0, range[1] = λ1;
-    p0 = null;
-  }
-
-  // Finds the left-right distance between two longitudes.
-  // This is almost the same as (λ1 - λ0 + 360°) % 360°, except that we want
-  // the distance between ±180° to be 360°.
-  function angle(λ0, λ1) { return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; }
-
-  function compareRanges(a, b) { return a[0] - b[0]; }
-
-  function withinRange(x, range) {
-    return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
-  }
+    /**
+     * The base implementation of `_.toNumber` which doesn't ensure correct
+     * conversions of binary, hexadecimal, or octal string values.
+     *
+     * @private
+     * @param {*} value The value to process.
+     * @returns {number} Returns the number.
+     */
+    function baseToNumber(value) {
+      if (typeof value == 'number') {
+        return value;
+      }
+      if (isSymbol(value)) {
+        return NAN;
+      }
+      return +value;
+    }
 
-  return function(feature) {
-    φ1 = λ1 = -(λ0 = φ0 = Infinity);
-    ranges = [];
+    /**
+     * The base implementation of `_.toString` which doesn't convert nullish
+     * values to empty strings.
+     *
+     * @private
+     * @param {*} value The value to process.
+     * @returns {string} Returns the string.
+     */
+    function baseToString(value) {
+      // Exit early for strings to avoid a performance hit in some environments.
+      if (typeof value == 'string') {
+        return value;
+      }
+      if (isArray(value)) {
+        // Recursively convert values (susceptible to call stack limits).
+        return arrayMap(value, baseToString) + '';
+      }
+      if (isSymbol(value)) {
+        return symbolToString ? symbolToString.call(value) : '';
+      }
+      var result = (value + '');
+      return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
+    }
 
-    d3.geo.stream(feature, bound);
+    /**
+     * The base implementation of `_.uniqBy` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new duplicate free array.
+     */
+    function baseUniq(array, iteratee, comparator) {
+      var index = -1,
+          includes = arrayIncludes,
+          length = array.length,
+          isCommon = true,
+          result = [],
+          seen = result;
 
-    var n = ranges.length;
-    if (n) {
-      // First, sort ranges by their minimum longitudes.
-      ranges.sort(compareRanges);
-
-      // Then, merge any ranges that overlap.
-      for (var i = 1, a = ranges[0], b, merged = [a]; i < n; ++i) {
-        b = ranges[i];
-        if (withinRange(b[0], a) || withinRange(b[1], a)) {
-          if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
-          if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
-        } else {
-          merged.push(a = b);
+      if (comparator) {
+        isCommon = false;
+        includes = arrayIncludesWith;
+      }
+      else if (length >= LARGE_ARRAY_SIZE) {
+        var set = iteratee ? null : createSet(array);
+        if (set) {
+          return setToArray(set);
         }
+        isCommon = false;
+        includes = cacheHas;
+        seen = new SetCache;
       }
-
-      // Finally, find the largest gap between the merged ranges.
-      // The final bounding box will be the inverse of this gap.
-      var best = -Infinity, dλ;
-      for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {
-        b = merged[i];
-        if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
+      else {
+        seen = iteratee ? [] : result;
+      }
+      outer:
+      while (++index < length) {
+        var value = array[index],
+            computed = iteratee ? iteratee(value) : value;
+
+        value = (comparator || value !== 0) ? value : 0;
+        if (isCommon && computed === computed) {
+          var seenIndex = seen.length;
+          while (seenIndex--) {
+            if (seen[seenIndex] === computed) {
+              continue outer;
+            }
+          }
+          if (iteratee) {
+            seen.push(computed);
+          }
+          result.push(value);
+        }
+        else if (!includes(seen, computed, comparator)) {
+          if (seen !== result) {
+            seen.push(computed);
+          }
+          result.push(value);
+        }
       }
+      return result;
     }
-    ranges = range = null;
-
-    return λ0 === Infinity || φ0 === Infinity
-        ? [[NaN, NaN], [NaN, NaN]]
-        : [[λ0, φ0], [λ1, φ1]];
-  };
-})();
-
-d3.geo.centroid = function(object) {
-  d3_geo_centroidW0 = d3_geo_centroidW1 =
-  d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 =
-  d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 =
-  d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
-  d3.geo.stream(object, d3_geo_centroid);
 
-  var x = d3_geo_centroidX2,
-      y = d3_geo_centroidY2,
-      z = d3_geo_centroidZ2,
-      m = x * x + y * y + z * z;
+    /**
+     * The base implementation of `_.unset`.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The property path to unset.
+     * @returns {boolean} Returns `true` if the property is deleted, else `false`.
+     */
+    function baseUnset(object, path) {
+      path = isKey(path, object) ? [path] : castPath(path);
+      object = parent(object, path);
 
-  // If the area-weighted centroid is undefined, fall back to length-weighted centroid.
-  if (m < ε2) {
-    x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
-    // If the feature has zero length, fall back to arithmetic mean of point vectors.
-    if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;
-    m = x * x + y * y + z * z;
-    // If the feature still has an undefined centroid, then return.
-    if (m < ε2) return [NaN, NaN];
-  }
-
-  return [Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees];
-};
-
-var d3_geo_centroidW0,
-    d3_geo_centroidW1,
-    d3_geo_centroidX0,
-    d3_geo_centroidY0,
-    d3_geo_centroidZ0,
-    d3_geo_centroidX1,
-    d3_geo_centroidY1,
-    d3_geo_centroidZ1,
-    d3_geo_centroidX2,
-    d3_geo_centroidY2,
-    d3_geo_centroidZ2;
-
-var d3_geo_centroid = {
-  sphere: d3_noop,
-  point: d3_geo_centroidPoint,
-  lineStart: d3_geo_centroidLineStart,
-  lineEnd: d3_geo_centroidLineEnd,
-  polygonStart: function() {
-    d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
-  },
-  polygonEnd: function() {
-    d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
-  }
-};
+      var key = toKey(last(path));
+      return !(object != null && hasOwnProperty.call(object, key)) || delete object[key];
+    }
 
-// Arithmetic mean of Cartesian vectors.
-function d3_geo_centroidPoint(λ, φ) {
-  λ *= d3_radians;
-  var cosφ = Math.cos(φ *= d3_radians);
-  d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));
-}
+    /**
+     * The base implementation of `_.update`.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to update.
+     * @param {Function} updater The function to produce the updated value.
+     * @param {Function} [customizer] The function to customize path creation.
+     * @returns {Object} Returns `object`.
+     */
+    function baseUpdate(object, path, updater, customizer) {
+      return baseSet(object, path, updater(baseGet(object, path)), customizer);
+    }
 
-function d3_geo_centroidPointXYZ(x, y, z) {
-  ++d3_geo_centroidW0;
-  d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
-  d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
-  d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
-}
+    /**
+     * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
+     * without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array} array The array to query.
+     * @param {Function} predicate The function invoked per iteration.
+     * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Array} Returns the slice of `array`.
+     */
+    function baseWhile(array, predicate, isDrop, fromRight) {
+      var length = array.length,
+          index = fromRight ? length : -1;
 
-function d3_geo_centroidLineStart() {
-  var x0, y0, z0; // previous point
+      while ((fromRight ? index-- : ++index < length) &&
+        predicate(array[index], index, array)) {}
 
-  d3_geo_centroid.point = function(λ, φ) {
-    λ *= d3_radians;
-    var cosφ = Math.cos(φ *= d3_radians);
-    x0 = cosφ * Math.cos(λ);
-    y0 = cosφ * Math.sin(λ);
-    z0 = Math.sin(φ);
-    d3_geo_centroid.point = nextPoint;
-    d3_geo_centroidPointXYZ(x0, y0, z0);
-  };
+      return isDrop
+        ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
+        : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
+    }
 
-  function nextPoint(λ, φ) {
-    λ *= d3_radians;
-    var cosφ = Math.cos(φ *= d3_radians),
-        x = cosφ * Math.cos(λ),
-        y = cosφ * Math.sin(λ),
-        z = Math.sin(φ),
-        w = Math.atan2(
-          Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w),
-          x0 * x + y0 * y + z0 * z);
-    d3_geo_centroidW1 += w;
-    d3_geo_centroidX1 += w * (x0 + (x0 = x));
-    d3_geo_centroidY1 += w * (y0 + (y0 = y));
-    d3_geo_centroidZ1 += w * (z0 + (z0 = z));
-    d3_geo_centroidPointXYZ(x0, y0, z0);
-  }
-}
+    /**
+     * The base implementation of `wrapperValue` which returns the result of
+     * performing a sequence of actions on the unwrapped `value`, where each
+     * successive action is supplied the return value of the previous.
+     *
+     * @private
+     * @param {*} value The unwrapped value.
+     * @param {Array} actions Actions to perform to resolve the unwrapped value.
+     * @returns {*} Returns the resolved value.
+     */
+    function baseWrapperValue(value, actions) {
+      var result = value;
+      if (result instanceof LazyWrapper) {
+        result = result.value();
+      }
+      return arrayReduce(actions, function(result, action) {
+        return action.func.apply(action.thisArg, arrayPush([result], action.args));
+      }, result);
+    }
 
-function d3_geo_centroidLineEnd() {
-  d3_geo_centroid.point = d3_geo_centroidPoint;
-}
+    /**
+     * The base implementation of methods like `_.xor`, without support for
+     * iteratee shorthands, that accepts an array of arrays to inspect.
+     *
+     * @private
+     * @param {Array} arrays The arrays to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of values.
+     */
+    function baseXor(arrays, iteratee, comparator) {
+      var length = arrays.length;
+      if (length < 2) {
+        return length ? baseUniq(arrays[0]) : [];
+      }
+      var index = -1,
+          result = Array(length);
 
-// See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
-// J. Applied Mechanics 42, 239 (1975).
-function d3_geo_centroidRingStart() {
-  var λ00, φ00, // first point
-      x0, y0, z0; // previous point
-
-  d3_geo_centroid.point = function(λ, φ) {
-    λ00 = λ, φ00 = φ;
-    d3_geo_centroid.point = nextPoint;
-    λ *= d3_radians;
-    var cosφ = Math.cos(φ *= d3_radians);
-    x0 = cosφ * Math.cos(λ);
-    y0 = cosφ * Math.sin(λ);
-    z0 = Math.sin(φ);
-    d3_geo_centroidPointXYZ(x0, y0, z0);
-  };
-
-  d3_geo_centroid.lineEnd = function() {
-    nextPoint(λ00, φ00);
-    d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
-    d3_geo_centroid.point = d3_geo_centroidPoint;
-  };
-
-  function nextPoint(λ, φ) {
-    λ *= d3_radians;
-    var cosφ = Math.cos(φ *= d3_radians),
-        x = cosφ * Math.cos(λ),
-        y = cosφ * Math.sin(λ),
-        z = Math.sin(φ),
-        cx = y0 * z - z0 * y,
-        cy = z0 * x - x0 * z,
-        cz = x0 * y - y0 * x,
-        m = Math.sqrt(cx * cx + cy * cy + cz * cz),
-        u = x0 * x + y0 * y + z0 * z,
-        v = m && -d3_acos(u) / m, // area weight
-        w = Math.atan2(m, u); // line weight
-    d3_geo_centroidX2 += v * cx;
-    d3_geo_centroidY2 += v * cy;
-    d3_geo_centroidZ2 += v * cz;
-    d3_geo_centroidW1 += w;
-    d3_geo_centroidX1 += w * (x0 + (x0 = x));
-    d3_geo_centroidY1 += w * (y0 + (y0 = y));
-    d3_geo_centroidZ1 += w * (z0 + (z0 = z));
-    d3_geo_centroidPointXYZ(x0, y0, z0);
-  }
-}
-
-// TODO Unify this code with d3.geom.polygon area?
-
-var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
-  point: d3_noop,
-  lineStart: d3_noop,
-  lineEnd: d3_noop,
-
-  // Only count area for polygon rings.
-  polygonStart: function() {
-    d3_geo_pathAreaPolygon = 0;
-    d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
-  },
-  polygonEnd: function() {
-    d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
-    d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
-  }
-};
+      while (++index < length) {
+        var array = arrays[index],
+            othIndex = -1;
 
-function d3_geo_pathAreaRingStart() {
-  var x00, y00, x0, y0;
+        while (++othIndex < length) {
+          if (othIndex != index) {
+            result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
+          }
+        }
+      }
+      return baseUniq(baseFlatten(result, 1), iteratee, comparator);
+    }
 
-  // For the first point, …
-  d3_geo_pathArea.point = function(x, y) {
-    d3_geo_pathArea.point = nextPoint;
-    x00 = x0 = x, y00 = y0 = y;
-  };
+    /**
+     * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
+     *
+     * @private
+     * @param {Array} props The property identifiers.
+     * @param {Array} values The property values.
+     * @param {Function} assignFunc The function to assign values.
+     * @returns {Object} Returns the new object.
+     */
+    function baseZipObject(props, values, assignFunc) {
+      var index = -1,
+          length = props.length,
+          valsLength = values.length,
+          result = {};
 
-  // For subsequent points, …
-  function nextPoint(x, y) {
-    d3_geo_pathAreaPolygon += y0 * x - x0 * y;
-    x0 = x, y0 = y;
-  }
+      while (++index < length) {
+        var value = index < valsLength ? values[index] : undefined;
+        assignFunc(result, props[index], value);
+      }
+      return result;
+    }
 
-  // For the last point, return to the start.
-  d3_geo_pathArea.lineEnd = function() {
-    nextPoint(x00, y00);
-  };
-}
+    /**
+     * Casts `value` to an empty array if it's not an array like object.
+     *
+     * @private
+     * @param {*} value The value to inspect.
+     * @returns {Array|Object} Returns the cast array-like object.
+     */
+    function castArrayLikeObject(value) {
+      return isArrayLikeObject(value) ? value : [];
+    }
 
-var d3_geo_pathBoundsX0,
-    d3_geo_pathBoundsY0,
-    d3_geo_pathBoundsX1,
-    d3_geo_pathBoundsY1;
+    /**
+     * Casts `value` to `identity` if it's not a function.
+     *
+     * @private
+     * @param {*} value The value to inspect.
+     * @returns {Function} Returns cast function.
+     */
+    function castFunction(value) {
+      return typeof value == 'function' ? value : identity;
+    }
 
-var d3_geo_pathBounds = {
-  point: d3_geo_pathBoundsPoint,
-  lineStart: d3_noop,
-  lineEnd: d3_noop,
-  polygonStart: d3_noop,
-  polygonEnd: d3_noop
-};
+    /**
+     * Casts `value` to a path array if it's not one.
+     *
+     * @private
+     * @param {*} value The value to inspect.
+     * @returns {Array} Returns the cast property path array.
+     */
+    function castPath(value) {
+      return isArray(value) ? value : stringToPath(value);
+    }
 
-function d3_geo_pathBoundsPoint(x, y) {
-  if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
-  if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
-  if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
-  if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
-}
-function d3_geo_pathBuffer() {
-  var pointCircle = d3_geo_pathBufferCircle(4.5),
-      buffer = [];
+    /**
+     * A `baseRest` alias which can be replaced with `identity` by module
+     * replacement plugins.
+     *
+     * @private
+     * @type {Function}
+     * @param {Function} func The function to apply a rest parameter to.
+     * @returns {Function} Returns the new function.
+     */
+    var castRest = baseRest;
 
-  var stream = {
-    point: point,
+    /**
+     * Casts `array` to a slice if it's needed.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {number} start The start position.
+     * @param {number} [end=array.length] The end position.
+     * @returns {Array} Returns the cast slice.
+     */
+    function castSlice(array, start, end) {
+      var length = array.length;
+      end = end === undefined ? length : end;
+      return (!start && end >= length) ? array : baseSlice(array, start, end);
+    }
 
-    // While inside a line, override point to moveTo then lineTo.
-    lineStart: function() { stream.point = pointLineStart; },
-    lineEnd: lineEnd,
+    /**
+     * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
+     *
+     * @private
+     * @param {number|Object} id The timer id or timeout object of the timer to clear.
+     */
+    var clearTimeout = ctxClearTimeout || function(id) {
+      return root.clearTimeout(id);
+    };
 
-    // While inside a polygon, override lineEnd to closePath.
-    polygonStart: function() { stream.lineEnd = lineEndPolygon; },
-    polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; },
+    /**
+     * Creates a clone of  `buffer`.
+     *
+     * @private
+     * @param {Buffer} buffer The buffer to clone.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Buffer} Returns the cloned buffer.
+     */
+    function cloneBuffer(buffer, isDeep) {
+      if (isDeep) {
+        return buffer.slice();
+      }
+      var length = buffer.length,
+          result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
 
-    pointRadius: function(_) {
-      pointCircle = d3_geo_pathBufferCircle(_);
-      return stream;
-    },
+      buffer.copy(result);
+      return result;
+    }
 
-    result: function() {
-      if (buffer.length) {
-        var result = buffer.join("");
-        buffer = [];
-        return result;
-      }
+    /**
+     * Creates a clone of `arrayBuffer`.
+     *
+     * @private
+     * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
+     * @returns {ArrayBuffer} Returns the cloned array buffer.
+     */
+    function cloneArrayBuffer(arrayBuffer) {
+      var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
+      new Uint8Array(result).set(new Uint8Array(arrayBuffer));
+      return result;
     }
-  };
 
-  function point(x, y) {
-    buffer.push("M", x, ",", y, pointCircle);
-  }
+    /**
+     * Creates a clone of `dataView`.
+     *
+     * @private
+     * @param {Object} dataView The data view to clone.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Object} Returns the cloned data view.
+     */
+    function cloneDataView(dataView, isDeep) {
+      var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
+      return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
+    }
 
-  function pointLineStart(x, y) {
-    buffer.push("M", x, ",", y);
-    stream.point = pointLine;
-  }
+    /**
+     * Creates a clone of `map`.
+     *
+     * @private
+     * @param {Object} map The map to clone.
+     * @param {Function} cloneFunc The function to clone values.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Object} Returns the cloned map.
+     */
+    function cloneMap(map, isDeep, cloneFunc) {
+      var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map);
+      return arrayReduce(array, addMapEntry, new map.constructor);
+    }
 
-  function pointLine(x, y) {
-    buffer.push("L", x, ",", y);
-  }
+    /**
+     * Creates a clone of `regexp`.
+     *
+     * @private
+     * @param {Object} regexp The regexp to clone.
+     * @returns {Object} Returns the cloned regexp.
+     */
+    function cloneRegExp(regexp) {
+      var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
+      result.lastIndex = regexp.lastIndex;
+      return result;
+    }
 
-  function lineEnd() {
-    stream.point = point;
-  }
+    /**
+     * Creates a clone of `set`.
+     *
+     * @private
+     * @param {Object} set The set to clone.
+     * @param {Function} cloneFunc The function to clone values.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Object} Returns the cloned set.
+     */
+    function cloneSet(set, isDeep, cloneFunc) {
+      var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set);
+      return arrayReduce(array, addSetEntry, new set.constructor);
+    }
 
-  function lineEndPolygon() {
-    buffer.push("Z");
-  }
+    /**
+     * Creates a clone of the `symbol` object.
+     *
+     * @private
+     * @param {Object} symbol The symbol object to clone.
+     * @returns {Object} Returns the cloned symbol object.
+     */
+    function cloneSymbol(symbol) {
+      return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
+    }
 
-  return stream;
-}
+    /**
+     * Creates a clone of `typedArray`.
+     *
+     * @private
+     * @param {Object} typedArray The typed array to clone.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Object} Returns the cloned typed array.
+     */
+    function cloneTypedArray(typedArray, isDeep) {
+      var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
+      return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
+    }
 
-function d3_geo_pathBufferCircle(radius) {
-  return "m0," + radius
-      + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
-      + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
-      + "z";
-}
+    /**
+     * Compares values to sort them in ascending order.
+     *
+     * @private
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {number} Returns the sort order indicator for `value`.
+     */
+    function compareAscending(value, other) {
+      if (value !== other) {
+        var valIsDefined = value !== undefined,
+            valIsNull = value === null,
+            valIsReflexive = value === value,
+            valIsSymbol = isSymbol(value);
+
+        var othIsDefined = other !== undefined,
+            othIsNull = other === null,
+            othIsReflexive = other === other,
+            othIsSymbol = isSymbol(other);
+
+        if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
+            (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
+            (valIsNull && othIsDefined && othIsReflexive) ||
+            (!valIsDefined && othIsReflexive) ||
+            !valIsReflexive) {
+          return 1;
+        }
+        if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
+            (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
+            (othIsNull && valIsDefined && valIsReflexive) ||
+            (!othIsDefined && valIsReflexive) ||
+            !othIsReflexive) {
+          return -1;
+        }
+      }
+      return 0;
+    }
 
-// TODO Unify this code with d3.geom.polygon centroid?
-// TODO Enforce positive area for exterior, negative area for interior?
+    /**
+     * Used by `_.orderBy` to compare multiple properties of a value to another
+     * and stable sort them.
+     *
+     * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
+     * specify an order of "desc" for descending or "asc" for ascending sort order
+     * of corresponding values.
+     *
+     * @private
+     * @param {Object} object The object to compare.
+     * @param {Object} other The other object to compare.
+     * @param {boolean[]|string[]} orders The order to sort by for each property.
+     * @returns {number} Returns the sort order indicator for `object`.
+     */
+    function compareMultiple(object, other, orders) {
+      var index = -1,
+          objCriteria = object.criteria,
+          othCriteria = other.criteria,
+          length = objCriteria.length,
+          ordersLength = orders.length;
 
-var d3_geo_pathCentroid = {
-  point: d3_geo_pathCentroidPoint,
+      while (++index < length) {
+        var result = compareAscending(objCriteria[index], othCriteria[index]);
+        if (result) {
+          if (index >= ordersLength) {
+            return result;
+          }
+          var order = orders[index];
+          return result * (order == 'desc' ? -1 : 1);
+        }
+      }
+      // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+      // that causes it, under certain circumstances, to provide the same value for
+      // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
+      // for more details.
+      //
+      // This also ensures a stable sort in V8 and other engines.
+      // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
+      return object.index - other.index;
+    }
 
-  // For lines, weight by length.
-  lineStart: d3_geo_pathCentroidLineStart,
-  lineEnd: d3_geo_pathCentroidLineEnd,
+    /**
+     * Creates an array that is the composition of partially applied arguments,
+     * placeholders, and provided arguments into a single array of arguments.
+     *
+     * @private
+     * @param {Array} args The provided arguments.
+     * @param {Array} partials The arguments to prepend to those provided.
+     * @param {Array} holders The `partials` placeholder indexes.
+     * @params {boolean} [isCurried] Specify composing for a curried function.
+     * @returns {Array} Returns the new array of composed arguments.
+     */
+    function composeArgs(args, partials, holders, isCurried) {
+      var argsIndex = -1,
+          argsLength = args.length,
+          holdersLength = holders.length,
+          leftIndex = -1,
+          leftLength = partials.length,
+          rangeLength = nativeMax(argsLength - holdersLength, 0),
+          result = Array(leftLength + rangeLength),
+          isUncurried = !isCurried;
 
-  // For polygons, weight by area.
-  polygonStart: function() {
-    d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
-  },
-  polygonEnd: function() {
-    d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
-    d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
-    d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
-  }
-};
+      while (++leftIndex < leftLength) {
+        result[leftIndex] = partials[leftIndex];
+      }
+      while (++argsIndex < holdersLength) {
+        if (isUncurried || argsIndex < argsLength) {
+          result[holders[argsIndex]] = args[argsIndex];
+        }
+      }
+      while (rangeLength--) {
+        result[leftIndex++] = args[argsIndex++];
+      }
+      return result;
+    }
 
-function d3_geo_pathCentroidPoint(x, y) {
-  d3_geo_centroidX0 += x;
-  d3_geo_centroidY0 += y;
-  ++d3_geo_centroidZ0;
-}
+    /**
+     * This function is like `composeArgs` except that the arguments composition
+     * is tailored for `_.partialRight`.
+     *
+     * @private
+     * @param {Array} args The provided arguments.
+     * @param {Array} partials The arguments to append to those provided.
+     * @param {Array} holders The `partials` placeholder indexes.
+     * @params {boolean} [isCurried] Specify composing for a curried function.
+     * @returns {Array} Returns the new array of composed arguments.
+     */
+    function composeArgsRight(args, partials, holders, isCurried) {
+      var argsIndex = -1,
+          argsLength = args.length,
+          holdersIndex = -1,
+          holdersLength = holders.length,
+          rightIndex = -1,
+          rightLength = partials.length,
+          rangeLength = nativeMax(argsLength - holdersLength, 0),
+          result = Array(rangeLength + rightLength),
+          isUncurried = !isCurried;
+
+      while (++argsIndex < rangeLength) {
+        result[argsIndex] = args[argsIndex];
+      }
+      var offset = argsIndex;
+      while (++rightIndex < rightLength) {
+        result[offset + rightIndex] = partials[rightIndex];
+      }
+      while (++holdersIndex < holdersLength) {
+        if (isUncurried || argsIndex < argsLength) {
+          result[offset + holders[holdersIndex]] = args[argsIndex++];
+        }
+      }
+      return result;
+    }
 
-function d3_geo_pathCentroidLineStart() {
-  var x0, y0;
+    /**
+     * Copies the values of `source` to `array`.
+     *
+     * @private
+     * @param {Array} source The array to copy values from.
+     * @param {Array} [array=[]] The array to copy values to.
+     * @returns {Array} Returns `array`.
+     */
+    function copyArray(source, array) {
+      var index = -1,
+          length = source.length;
 
-  d3_geo_pathCentroid.point = function(x, y) {
-    d3_geo_pathCentroid.point = nextPoint;
-    d3_geo_pathCentroidPoint(x0 = x, y0 = y);
-  };
+      array || (array = Array(length));
+      while (++index < length) {
+        array[index] = source[index];
+      }
+      return array;
+    }
 
-  function nextPoint(x, y) {
-    var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
-    d3_geo_centroidX1 += z * (x0 + x) / 2;
-    d3_geo_centroidY1 += z * (y0 + y) / 2;
-    d3_geo_centroidZ1 += z;
-    d3_geo_pathCentroidPoint(x0 = x, y0 = y);
-  }
-}
+    /**
+     * Copies properties of `source` to `object`.
+     *
+     * @private
+     * @param {Object} source The object to copy properties from.
+     * @param {Array} props The property identifiers to copy.
+     * @param {Object} [object={}] The object to copy properties to.
+     * @param {Function} [customizer] The function to customize copied values.
+     * @returns {Object} Returns `object`.
+     */
+    function copyObject(source, props, object, customizer) {
+      var isNew = !object;
+      object || (object = {});
 
-function d3_geo_pathCentroidLineEnd() {
-  d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
-}
+      var index = -1,
+          length = props.length;
 
-function d3_geo_pathCentroidRingStart() {
-  var x00, y00, x0, y0;
+      while (++index < length) {
+        var key = props[index];
 
-  // For the first point, …
-  d3_geo_pathCentroid.point = function(x, y) {
-    d3_geo_pathCentroid.point = nextPoint;
-    d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
-  };
+        var newValue = customizer
+          ? customizer(object[key], source[key], key, object, source)
+          : undefined;
 
-  // For subsequent points, …
-  function nextPoint(x, y) {
-    var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
-    d3_geo_centroidX1 += z * (x0 + x) / 2;
-    d3_geo_centroidY1 += z * (y0 + y) / 2;
-    d3_geo_centroidZ1 += z;
+        if (newValue === undefined) {
+          newValue = source[key];
+        }
+        if (isNew) {
+          baseAssignValue(object, key, newValue);
+        } else {
+          assignValue(object, key, newValue);
+        }
+      }
+      return object;
+    }
 
-    z = y0 * x - x0 * y;
-    d3_geo_centroidX2 += z * (x0 + x);
-    d3_geo_centroidY2 += z * (y0 + y);
-    d3_geo_centroidZ2 += z * 3;
-    d3_geo_pathCentroidPoint(x0 = x, y0 = y);
-  }
+    /**
+     * Copies own symbols of `source` to `object`.
+     *
+     * @private
+     * @param {Object} source The object to copy symbols from.
+     * @param {Object} [object={}] The object to copy symbols to.
+     * @returns {Object} Returns `object`.
+     */
+    function copySymbols(source, object) {
+      return copyObject(source, getSymbols(source), object);
+    }
 
-  // For the last point, return to the start.
-  d3_geo_pathCentroid.lineEnd = function() {
-    nextPoint(x00, y00);
-  };
-}
+    /**
+     * Copies own and inherited symbols of `source` to `object`.
+     *
+     * @private
+     * @param {Object} source The object to copy symbols from.
+     * @param {Object} [object={}] The object to copy symbols to.
+     * @returns {Object} Returns `object`.
+     */
+    function copySymbolsIn(source, object) {
+      return copyObject(source, getSymbolsIn(source), object);
+    }
 
-function d3_geo_pathContext(context) {
-  var pointRadius = 4.5;
+    /**
+     * Creates a function like `_.groupBy`.
+     *
+     * @private
+     * @param {Function} setter The function to set accumulator values.
+     * @param {Function} [initializer] The accumulator object initializer.
+     * @returns {Function} Returns the new aggregator function.
+     */
+    function createAggregator(setter, initializer) {
+      return function(collection, iteratee) {
+        var func = isArray(collection) ? arrayAggregator : baseAggregator,
+            accumulator = initializer ? initializer() : {};
 
-  var stream = {
-    point: point,
+        return func(collection, setter, getIteratee(iteratee, 2), accumulator);
+      };
+    }
 
-    // While inside a line, override point to moveTo then lineTo.
-    lineStart: function() { stream.point = pointLineStart; },
-    lineEnd: lineEnd,
+    /**
+     * Creates a function like `_.assign`.
+     *
+     * @private
+     * @param {Function} assigner The function to assign values.
+     * @returns {Function} Returns the new assigner function.
+     */
+    function createAssigner(assigner) {
+      return baseRest(function(object, sources) {
+        var index = -1,
+            length = sources.length,
+            customizer = length > 1 ? sources[length - 1] : undefined,
+            guard = length > 2 ? sources[2] : undefined;
+
+        customizer = (assigner.length > 3 && typeof customizer == 'function')
+          ? (length--, customizer)
+          : undefined;
 
-    // While inside a polygon, override lineEnd to closePath.
-    polygonStart: function() { stream.lineEnd = lineEndPolygon; },
-    polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; },
+        if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+          customizer = length < 3 ? undefined : customizer;
+          length = 1;
+        }
+        object = Object(object);
+        while (++index < length) {
+          var source = sources[index];
+          if (source) {
+            assigner(object, source, index, customizer);
+          }
+        }
+        return object;
+      });
+    }
 
-    pointRadius: function(_) {
-      pointRadius = _;
-      return stream;
-    },
+    /**
+     * Creates a `baseEach` or `baseEachRight` function.
+     *
+     * @private
+     * @param {Function} eachFunc The function to iterate over a collection.
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Function} Returns the new base function.
+     */
+    function createBaseEach(eachFunc, fromRight) {
+      return function(collection, iteratee) {
+        if (collection == null) {
+          return collection;
+        }
+        if (!isArrayLike(collection)) {
+          return eachFunc(collection, iteratee);
+        }
+        var length = collection.length,
+            index = fromRight ? length : -1,
+            iterable = Object(collection);
 
-    result: d3_noop
-  };
-
-  function point(x, y) {
-    context.moveTo(x + pointRadius, y);
-    context.arc(x, y, pointRadius, 0, τ);
-  }
+        while ((fromRight ? index-- : ++index < length)) {
+          if (iteratee(iterable[index], index, iterable) === false) {
+            break;
+          }
+        }
+        return collection;
+      };
+    }
 
-  function pointLineStart(x, y) {
-    context.moveTo(x, y);
-    stream.point = pointLine;
-  }
+    /**
+     * Creates a base function for methods like `_.forIn` and `_.forOwn`.
+     *
+     * @private
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Function} Returns the new base function.
+     */
+    function createBaseFor(fromRight) {
+      return function(object, iteratee, keysFunc) {
+        var index = -1,
+            iterable = Object(object),
+            props = keysFunc(object),
+            length = props.length;
+
+        while (length--) {
+          var key = props[fromRight ? length : ++index];
+          if (iteratee(iterable[key], key, iterable) === false) {
+            break;
+          }
+        }
+        return object;
+      };
+    }
 
-  function pointLine(x, y) {
-    context.lineTo(x, y);
-  }
+    /**
+     * Creates a function that wraps `func` to invoke it with the optional `this`
+     * binding of `thisArg`.
+     *
+     * @private
+     * @param {Function} func The function to wrap.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @param {*} [thisArg] The `this` binding of `func`.
+     * @returns {Function} Returns the new wrapped function.
+     */
+    function createBind(func, bitmask, thisArg) {
+      var isBind = bitmask & WRAP_BIND_FLAG,
+          Ctor = createCtor(func);
 
-  function lineEnd() {
-    stream.point = point;
-  }
+      function wrapper() {
+        var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
+        return fn.apply(isBind ? thisArg : this, arguments);
+      }
+      return wrapper;
+    }
 
-  function lineEndPolygon() {
-    context.closePath();
-  }
+    /**
+     * Creates a function like `_.lowerFirst`.
+     *
+     * @private
+     * @param {string} methodName The name of the `String` case method to use.
+     * @returns {Function} Returns the new case function.
+     */
+    function createCaseFirst(methodName) {
+      return function(string) {
+        string = toString(string);
 
-  return stream;
-}
+        var strSymbols = hasUnicode(string)
+          ? stringToArray(string)
+          : undefined;
 
-function d3_geo_resample(project) {
-  var δ2 = .5, // precision, px²
-      cosMinDistance = Math.cos(30 * d3_radians), // cos(minimum angular distance)
-      maxDepth = 16;
+        var chr = strSymbols
+          ? strSymbols[0]
+          : string.charAt(0);
 
-  function resample(stream) {
-    return (maxDepth ? resampleRecursive : resampleNone)(stream);
-  }
+        var trailing = strSymbols
+          ? castSlice(strSymbols, 1).join('')
+          : string.slice(1);
 
-  function resampleNone(stream) {
-    return d3_geo_transformPoint(stream, function(x, y) {
-      x = project(x, y);
-      stream.point(x[0], x[1]);
-    });
-  }
+        return chr[methodName]() + trailing;
+      };
+    }
 
-  function resampleRecursive(stream) {
-    var λ00, φ00, x00, y00, a00, b00, c00, // first point
-        λ0, x0, y0, a0, b0, c0; // previous point
+    /**
+     * Creates a function like `_.camelCase`.
+     *
+     * @private
+     * @param {Function} callback The function to combine each word.
+     * @returns {Function} Returns the new compounder function.
+     */
+    function createCompounder(callback) {
+      return function(string) {
+        return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
+      };
+    }
 
-    var resample = {
-      point: point,
-      lineStart: lineStart,
-      lineEnd: lineEnd,
-      polygonStart: function() { stream.polygonStart(); resample.lineStart = ringStart; },
-      polygonEnd: function() { stream.polygonEnd(); resample.lineStart = lineStart; }
-    };
+    /**
+     * Creates a function that produces an instance of `Ctor` regardless of
+     * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+     *
+     * @private
+     * @param {Function} Ctor The constructor to wrap.
+     * @returns {Function} Returns the new wrapped function.
+     */
+    function createCtor(Ctor) {
+      return function() {
+        // Use a `switch` statement to work with class constructors. See
+        // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
+        // for more details.
+        var args = arguments;
+        switch (args.length) {
+          case 0: return new Ctor;
+          case 1: return new Ctor(args[0]);
+          case 2: return new Ctor(args[0], args[1]);
+          case 3: return new Ctor(args[0], args[1], args[2]);
+          case 4: return new Ctor(args[0], args[1], args[2], args[3]);
+          case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
+          case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
+          case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
+        }
+        var thisBinding = baseCreate(Ctor.prototype),
+            result = Ctor.apply(thisBinding, args);
+
+        // Mimic the constructor's `return` behavior.
+        // See https://es5.github.io/#x13.2.2 for more details.
+        return isObject(result) ? result : thisBinding;
+      };
+    }
 
-    function point(x, y) {
-      x = project(x, y);
-      stream.point(x[0], x[1]);
+    /**
+     * Creates a function that wraps `func` to enable currying.
+     *
+     * @private
+     * @param {Function} func The function to wrap.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @param {number} arity The arity of `func`.
+     * @returns {Function} Returns the new wrapped function.
+     */
+    function createCurry(func, bitmask, arity) {
+      var Ctor = createCtor(func);
+
+      function wrapper() {
+        var length = arguments.length,
+            args = Array(length),
+            index = length,
+            placeholder = getHolder(wrapper);
+
+        while (index--) {
+          args[index] = arguments[index];
+        }
+        var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
+          ? []
+          : replaceHolders(args, placeholder);
+
+        length -= holders.length;
+        if (length < arity) {
+          return createRecurry(
+            func, bitmask, createHybrid, wrapper.placeholder, undefined,
+            args, holders, undefined, undefined, arity - length);
+        }
+        var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
+        return apply(fn, this, args);
+      }
+      return wrapper;
     }
 
-    function lineStart() {
-      x0 = NaN;
-      resample.point = linePoint;
-      stream.lineStart();
+    /**
+     * Creates a `_.find` or `_.findLast` function.
+     *
+     * @private
+     * @param {Function} findIndexFunc The function to find the collection index.
+     * @returns {Function} Returns the new find function.
+     */
+    function createFind(findIndexFunc) {
+      return function(collection, predicate, fromIndex) {
+        var iterable = Object(collection);
+        if (!isArrayLike(collection)) {
+          var iteratee = getIteratee(predicate, 3);
+          collection = keys(collection);
+          predicate = function(key) { return iteratee(iterable[key], key, iterable); };
+        }
+        var index = findIndexFunc(collection, predicate, fromIndex);
+        return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
+      };
     }
 
-    function linePoint(λ, φ) {
-      var c = d3_geo_cartesian([λ, φ]), p = project(λ, φ);
-      resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
-      stream.point(x0, y0);
+    /**
+     * Creates a `_.flow` or `_.flowRight` function.
+     *
+     * @private
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Function} Returns the new flow function.
+     */
+    function createFlow(fromRight) {
+      return flatRest(function(funcs) {
+        var length = funcs.length,
+            index = length,
+            prereq = LodashWrapper.prototype.thru;
+
+        if (fromRight) {
+          funcs.reverse();
+        }
+        while (index--) {
+          var func = funcs[index];
+          if (typeof func != 'function') {
+            throw new TypeError(FUNC_ERROR_TEXT);
+          }
+          if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
+            var wrapper = new LodashWrapper([], true);
+          }
+        }
+        index = wrapper ? index : length;
+        while (++index < length) {
+          func = funcs[index];
+
+          var funcName = getFuncName(func),
+              data = funcName == 'wrapper' ? getData(func) : undefined;
+
+          if (data && isLaziable(data[0]) &&
+                data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
+                !data[4].length && data[9] == 1
+              ) {
+            wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
+          } else {
+            wrapper = (func.length == 1 && isLaziable(func))
+              ? wrapper[funcName]()
+              : wrapper.thru(func);
+          }
+        }
+        return function() {
+          var args = arguments,
+              value = args[0];
+
+          if (wrapper && args.length == 1 &&
+              isArray(value) && value.length >= LARGE_ARRAY_SIZE) {
+            return wrapper.plant(value).value();
+          }
+          var index = 0,
+              result = length ? funcs[index].apply(this, args) : value;
+
+          while (++index < length) {
+            result = funcs[index].call(this, result);
+          }
+          return result;
+        };
+      });
     }
 
-    function lineEnd() {
-      resample.point = point;
-      stream.lineEnd();
+    /**
+     * Creates a function that wraps `func` to invoke it with optional `this`
+     * binding of `thisArg`, partial application, and currying.
+     *
+     * @private
+     * @param {Function|string} func The function or method name to wrap.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @param {*} [thisArg] The `this` binding of `func`.
+     * @param {Array} [partials] The arguments to prepend to those provided to
+     *  the new function.
+     * @param {Array} [holders] The `partials` placeholder indexes.
+     * @param {Array} [partialsRight] The arguments to append to those provided
+     *  to the new function.
+     * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+     * @param {Array} [argPos] The argument positions of the new function.
+     * @param {number} [ary] The arity cap of `func`.
+     * @param {number} [arity] The arity of `func`.
+     * @returns {Function} Returns the new wrapped function.
+     */
+    function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+      var isAry = bitmask & WRAP_ARY_FLAG,
+          isBind = bitmask & WRAP_BIND_FLAG,
+          isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
+          isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
+          isFlip = bitmask & WRAP_FLIP_FLAG,
+          Ctor = isBindKey ? undefined : createCtor(func);
+
+      function wrapper() {
+        var length = arguments.length,
+            args = Array(length),
+            index = length;
+
+        while (index--) {
+          args[index] = arguments[index];
+        }
+        if (isCurried) {
+          var placeholder = getHolder(wrapper),
+              holdersCount = countHolders(args, placeholder);
+        }
+        if (partials) {
+          args = composeArgs(args, partials, holders, isCurried);
+        }
+        if (partialsRight) {
+          args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
+        }
+        length -= holdersCount;
+        if (isCurried && length < arity) {
+          var newHolders = replaceHolders(args, placeholder);
+          return createRecurry(
+            func, bitmask, createHybrid, wrapper.placeholder, thisArg,
+            args, newHolders, argPos, ary, arity - length
+          );
+        }
+        var thisBinding = isBind ? thisArg : this,
+            fn = isBindKey ? thisBinding[func] : func;
+
+        length = args.length;
+        if (argPos) {
+          args = reorder(args, argPos);
+        } else if (isFlip && length > 1) {
+          args.reverse();
+        }
+        if (isAry && ary < length) {
+          args.length = ary;
+        }
+        if (this && this !== root && this instanceof wrapper) {
+          fn = Ctor || createCtor(fn);
+        }
+        return fn.apply(thisBinding, args);
+      }
+      return wrapper;
     }
 
-    function ringStart() {
-      lineStart();
-      resample.point = ringPoint;
-      resample.lineEnd = ringEnd;
+    /**
+     * Creates a function like `_.invertBy`.
+     *
+     * @private
+     * @param {Function} setter The function to set accumulator values.
+     * @param {Function} toIteratee The function to resolve iteratees.
+     * @returns {Function} Returns the new inverter function.
+     */
+    function createInverter(setter, toIteratee) {
+      return function(object, iteratee) {
+        return baseInverter(object, setter, toIteratee(iteratee), {});
+      };
     }
 
-    function ringPoint(λ, φ) {
-      linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
-      resample.point = linePoint;
+    /**
+     * Creates a function that performs a mathematical operation on two values.
+     *
+     * @private
+     * @param {Function} operator The function to perform the operation.
+     * @param {number} [defaultValue] The value used for `undefined` arguments.
+     * @returns {Function} Returns the new mathematical operation function.
+     */
+    function createMathOperation(operator, defaultValue) {
+      return function(value, other) {
+        var result;
+        if (value === undefined && other === undefined) {
+          return defaultValue;
+        }
+        if (value !== undefined) {
+          result = value;
+        }
+        if (other !== undefined) {
+          if (result === undefined) {
+            return other;
+          }
+          if (typeof value == 'string' || typeof other == 'string') {
+            value = baseToString(value);
+            other = baseToString(other);
+          } else {
+            value = baseToNumber(value);
+            other = baseToNumber(other);
+          }
+          result = operator(value, other);
+        }
+        return result;
+      };
     }
 
-    function ringEnd() {
-      resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
-      resample.lineEnd = lineEnd;
-      lineEnd();
+    /**
+     * Creates a function like `_.over`.
+     *
+     * @private
+     * @param {Function} arrayFunc The function to iterate over iteratees.
+     * @returns {Function} Returns the new over function.
+     */
+    function createOver(arrayFunc) {
+      return flatRest(function(iteratees) {
+        iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
+        return baseRest(function(args) {
+          var thisArg = this;
+          return arrayFunc(iteratees, function(iteratee) {
+            return apply(iteratee, thisArg, args);
+          });
+        });
+      });
     }
 
-    return resample;
-  }
+    /**
+     * Creates the padding for `string` based on `length`. The `chars` string
+     * is truncated if the number of characters exceeds `length`.
+     *
+     * @private
+     * @param {number} length The padding length.
+     * @param {string} [chars=' '] The string used as padding.
+     * @returns {string} Returns the padding for `string`.
+     */
+    function createPadding(length, chars) {
+      chars = chars === undefined ? ' ' : baseToString(chars);
 
-  function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
-    var dx = x1 - x0,
-        dy = y1 - y0,
-        d2 = dx * dx + dy * dy;
-    if (d2 > 4 * δ2 && depth--) {
-      var a = a0 + a1,
-          b = b0 + b1,