diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..6f3a2913e
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "liveServer.settings.port": 5501
+}
\ No newline at end of file
diff --git a/5years/HydroFlask5Years.csv b/5years/HydroFlask5Years.csv
new file mode 100644
index 000000000..9476f8b05
--- /dev/null
+++ b/5years/HydroFlask5Years.csv
@@ -0,0 +1,54 @@
+Category: Shopping
+
+Region,Hydro Flask: (2/23/19 - 2/23/24)
+Hawaii,100
+California,88
+South Dakota,77
+Oregon,74
+Nebraska,72
+North Dakota,69
+Arizona,67
+Utah,67
+Iowa,66
+Nevada,66
+New Hampshire,64
+Colorado,61
+Montana,61
+Minnesota,59
+Idaho,59
+Washington,58
+Vermont,56
+Massachusetts,54
+Wyoming,53
+Rhode Island,50
+Connecticut,50
+Maine,48
+Kansas,48
+Alaska,46
+Wisconsin,45
+New Jersey,43
+Virginia,41
+Pennsylvania,41
+Illinois,40
+Missouri,40
+New Mexico,37
+Indiana,35
+Michigan,35
+Tennessee,35
+Texas,35
+Ohio,35
+North Carolina,33
+Delaware,33
+Maryland,33
+District of Columbia,32
+South Carolina,30
+New York,30
+Kentucky,30
+Alabama,29
+Oklahoma,27
+Georgia,25
+Arkansas,25
+Mississippi,24
+West Virginia,24
+Louisiana,22
+Florida,22
diff --git a/5years/MultiTimeline5.csv b/5years/MultiTimeline5.csv
new file mode 100644
index 000000000..4dc52faff
--- /dev/null
+++ b/5years/MultiTimeline5.csv
@@ -0,0 +1,54 @@
+Category: Shopping
+
+Region,Hydro Flask: (2/23/19 - 2/23/24),Nalgene: (2/23/19 - 2/23/24),YETI: (2/23/19 - 2/23/24),Owala®: (2/23/19 - 2/23/24),Stanley: (2/23/19 - 2/23/24)
+Hawaii,29%,<1%,57%,2%,12%
+California,40%,1%,35%,2%,22%
+South Dakota,28%,1%,33%,4%,34%
+Nebraska,27%,1%,37%,4%,31%
+Oregon,36%,3%,36%,2%,23%
+North Dakota,26%,2%,39%,3%,30%
+Arizona,31%,1%,36%,2%,30%
+Nevada,36%,2%,34%,3%,25%
+Iowa,25%,1%,35%,5%,34%
+Utah,24%,2%,28%,6%,40%
+New Hampshire,23%,1%,52%,2%,22%
+Idaho,25%,3%,36%,2%,34%
+Colorado,28%,4%,43%,3%,22%
+Montana,22%,5%,48%,1%,24%
+Minnesota,25%,3%,42%,4%,26%
+Washington,32%,4%,36%,2%,26%
+Vermont,25%,4%,51%,1%,19%
+Massachusetts,22%,2%,50%,3%,23%
+Rhode Island,22%,3%,47%,4%,24%
+Connecticut,23%,2%,48%,2%,25%
+Alaska,26%,8%,45%,1%,20%
+Kansas,21%,2%,40%,4%,33%
+Maine,18%,2%,53%,3%,24%
+Wisconsin,21%,2%,45%,4%,28%
+Wyoming,18%,4%,53%,,25%
+New Jersey,24%,1%,44%,3%,28%
+Virginia,22%,2%,46%,3%,27%
+Pennsylvania,18%,2%,53%,3%,24%
+Illinois,20%,2%,48%,3%,27%
+Missouri,20%,2%,39%,4%,35%
+Texas,16%,1%,49%,2%,32%
+Tennessee,17%,2%,40%,4%,37%
+Indiana,18%,1%,42%,4%,35%
+Michigan,16%,1%,54%,3%,26%
+New Mexico,19%,1%,53%,2%,25%
+Ohio,17%,1%,49%,4%,29%
+North Carolina,16%,3%,48%,4%,29%
+Maryland,20%,2%,47%,3%,28%
+Delaware,15%,2%,55%,3%,25%
+District of Columbia,25%,4%,47%,4%,20%
+South Carolina,14%,1%,48%,4%,33%
+Kentucky,14%,1%,40%,4%,41%
+New York,21%,2%,50%,3%,24%
+Alabama,13%,1%,42%,4%,40%
+Oklahoma,15%,1%,41%,3%,40%
+Arkansas,13%,1%,40%,3%,43%
+Georgia,15%,2%,47%,3%,33%
+West Virginia,12%,1%,47%,2%,38%
+Louisiana,15%,1%,41%,4%,39%
+Mississippi,12%,<1%,43%,2%,43%
+Florida,13%,1%,54%,2%,30%
diff --git a/5years/Nalgene5Years.csv b/5years/Nalgene5Years.csv
new file mode 100644
index 000000000..47378a34f
--- /dev/null
+++ b/5years/Nalgene5Years.csv
@@ -0,0 +1,54 @@
+Category: Shopping
+
+Region,Nalgene: (2/23/19 - 2/23/24)
+Alaska,100
+Maine,87
+Montana,87
+Colorado,75
+Utah,62
+Wyoming,62
+Idaho,62
+Washington,50
+Minnesota,50
+Oregon,50
+South Dakota,50
+West Virginia,50
+Massachusetts,37
+North Carolina,37
+District of Columbia,37
+Vermont,37
+Nebraska,37
+Tennessee,37
+Rhode Island,37
+New Hampshire,37
+Hawaii,37
+Pennsylvania,37
+Missouri,37
+Virginia,37
+South Carolina,37
+Wisconsin,37
+Connecticut,37
+Kansas,25
+Iowa,25
+Kentucky,25
+New York,25
+California,25
+New Mexico,25
+Georgia,25
+Michigan,25
+Illinois,25
+Nevada,25
+Indiana,25
+Arizona,25
+Ohio,25
+Maryland,25
+North Dakota,25
+New Jersey,12
+Arkansas,12
+Oklahoma,12
+Texas,12
+Louisiana,12
+Delaware,12
+Alabama,12
+Florida,12
+Mississippi,<1
diff --git a/5years/Owala5Years.csv b/5years/Owala5Years.csv
new file mode 100644
index 000000000..5ce243c49
--- /dev/null
+++ b/5years/Owala5Years.csv
@@ -0,0 +1,54 @@
+Category: Shopping
+
+Region,Owala®: (2/23/19 - 2/23/24)
+Utah,100
+Iowa,66
+Nebraska,58
+South Dakota,50
+Minnesota,50
+Kentucky,50
+Wisconsin,50
+Alabama,41
+Indiana,41
+South Carolina,41
+North Dakota,41
+Tennessee,41
+Kansas,41
+North Carolina,41
+Delaware,41
+Ohio,41
+Missouri,41
+Illinois,33
+Massachusetts,33
+Maine,33
+New Hampshire,33
+Virginia,33
+Michigan,33
+Pennsylvania,33
+Oklahoma,33
+Rhode Island,33
+Colorado,33
+Texas,33
+Arkansas,33
+Hawaii,25
+Georgia,25
+Connecticut,25
+California,25
+Louisiana,25
+New Jersey,25
+Idaho,25
+Nevada,25
+Mississippi,25
+Maryland,25
+Washington,25
+Florida,25
+West Virginia,16
+New York,16
+Arizona,16
+District of Columbia,16
+New Mexico,16
+Oregon,16
+Alaska,16
+Wyoming,8
+Montana,8
+Vermont,
diff --git a/5years/Stanley.csv b/5years/Stanley.csv
new file mode 100644
index 000000000..2d3c4e333
--- /dev/null
+++ b/5years/Stanley.csv
@@ -0,0 +1,54 @@
+Category: Shopping
+
+Region,Stanley: (2/23/19 - 2/23/24)
+Utah,100
+South Dakota,81
+Iowa,79
+Kentucky,78
+Mississippi,76
+Alabama,76
+Arkansas,76
+Nebraska,76
+North Dakota,75
+Idaho,75
+West Virginia,75
+Kansas,71
+Tennessee,68
+South Carolina,66
+Oklahoma,65
+Texas,65
+Missouri,65
+Indiana,62
+Wyoming,59
+Maine,59
+Arizona,57
+Montana,57
+Louisiana,56
+Minnesota,55
+Wisconsin,55
+North Carolina,55
+New Hampshire,52
+Ohio,52
+Georgia,52
+Michigan,50
+Illinois,50
+Florida,49
+Pennsylvania,49
+Massachusetts,49
+Delaware,47
+Rhode Island,47
+Connecticut,46
+New Jersey,44
+Virginia,44
+Colorado,44
+California,43
+Maryland,43
+Washington,43
+Hawaii,42
+Nevada,40
+New Mexico,40
+Oregon,40
+Vermont,39
+Alaska,33
+New York,30
+District of Columbia,26
diff --git a/5years/Yeti5Years.csv b/5years/Yeti5Years.csv
new file mode 100644
index 000000000..aeaabce68
--- /dev/null
+++ b/5years/Yeti5Years.csv
@@ -0,0 +1,54 @@
+Category: Shopping
+
+Region,YETI: (2/23/19 - 2/23/24)
+Hawaii,100
+New Hampshire,75
+Maine,72
+Wyoming,65
+Montana,65
+Massachusetts,60
+Texas,59
+Vermont,58
+Pennsylvania,57
+Delaware,57
+North Dakota,55
+Michigan,53
+South Carolina,53
+Rhode Island,52
+West Virginia,52
+North Carolina,52
+Connecticut,52
+Wisconsin,50
+Minnesota,50
+Nebraska,50
+Ohio,49
+New Mexico,49
+Colorado,48
+Florida,47
+Kansas,46
+South Dakota,46
+Alabama,46
+Idaho,46
+Iowa,45
+Virginia,43
+Mississippi,43
+Georgia,43
+Kentucky,42
+Illinois,42
+Indiana,42
+Alaska,41
+New Jersey,41
+Tennessee,41
+Maryland,40
+Missouri,39
+California,39
+Arkansas,39
+Utah,39
+Arizona,39
+New York,38
+Oklahoma,37
+Oregon,37
+Washington,32
+Louisiana,32
+Nevada,31
+District of Columbia,31
diff --git a/5years/multiTimeline.csv b/5years/multiTimeline.csv
new file mode 100644
index 000000000..ef2ae8cf2
--- /dev/null
+++ b/5years/multiTimeline.csv
@@ -0,0 +1,264 @@
+Category: Shopping
+
+Week,Hydro Flask: (United States),Nalgene: (United States),YETI: (United States),Owala®: (United States),Stanley: (United States)
+2019-02-24,3,<1,0,0,0
+2019-03-03,2,<1,0,0,0
+2019-03-10,2,1,<1,0,0
+2019-03-17,2,<1,<1,0,0
+2019-03-24,2,<1,0,<1,0
+2019-03-31,3,<1,0,0,0
+2019-04-07,3,<1,0,0,0
+2019-04-14,3,<1,0,0,0
+2019-04-21,3,1,0,0,0
+2019-04-28,3,<1,1,0,0
+2019-05-05,3,<1,5,0,<1
+2019-05-12,3,1,5,<1,<1
+2019-05-19,2,<1,7,0,0
+2019-05-26,3,<1,7,0,0
+2019-06-02,4,<1,7,0,<1
+2019-06-09,4,<1,8,0,0
+2019-06-16,4,1,7,0,<1
+2019-06-23,6,1,7,0,<1
+2019-06-30,5,<1,4,<1,<1
+2019-07-07,5,1,1,0,0
+2019-07-14,5,<1,0,0,0
+2019-07-21,9,<1,<1,0,0
+2019-07-28,8,<1,0,0,0
+2019-08-04,8,1,<1,0,0
+2019-08-11,8,1,0,0,0
+2019-08-18,9,1,0,0,0
+2019-08-25,8,1,0,0,<1
+2019-09-01,9,1,<1,0,0
+2019-09-08,7,<1,0,0,<1
+2019-09-15,7,<1,0,0,<1
+2019-09-22,8,<1,0,0,0
+2019-09-29,7,<1,0,0,<1
+2019-10-06,6,<1,0,0,<1
+2019-10-13,5,<1,0,<1,0
+2019-10-20,6,<1,0,0,<1
+2019-10-27,6,<1,0,0,<1
+2019-11-03,5,<1,0,0,0
+2019-11-10,6,1,0,0,<1
+2019-11-17,7,<1,<1,0,<1
+2019-11-24,20,0,0,0,<1
+2019-12-01,12,1,<1,0,<1
+2019-12-08,12,<1,0,<1,<1
+2019-12-15,11,<1,0,0,<1
+2019-12-22,10,<1,0,0,0
+2019-12-29,4,<1,<1,0,<1
+2020-01-05,6,<1,<1,0,0
+2020-01-12,5,<1,0,0,0
+2020-01-19,3,1,0,0,<1
+2020-01-26,2,<1,<1,<1,<1
+2020-02-02,3,<1,0,<1,<1
+2020-02-09,3,<1,0,0,0
+2020-02-16,2,<1,0,0,1
+2020-02-23,2,<1,<1,0,<1
+2020-03-01,2,<1,0,<1,0
+2020-03-08,2,<1,0,<1,<1
+2020-03-15,1,<1,0,0,<1
+2020-03-22,2,<1,1,0,0
+2020-03-29,1,<1,3,<1,0
+2020-04-05,1,<1,5,0,0
+2020-04-12,2,<1,6,0,0
+2020-04-19,1,<1,7,<1,0
+2020-04-26,2,<1,8,0,0
+2020-05-03,2,<1,10,<1,<1
+2020-05-10,3,<1,8,<1,<1
+2020-05-17,2,<1,9,0,0
+2020-05-24,2,<1,10,<1,<1
+2020-05-31,3,0,11,0,<1
+2020-06-07,3,1,13,0,<1
+2020-06-14,4,<1,14,0,<1
+2020-06-21,3,<1,11,<1,<1
+2020-06-28,4,<1,9,0,<1
+2020-07-05,3,1,9,0,<1
+2020-07-12,4,1,12,<1,<1
+2020-07-19,4,1,11,0,<1
+2020-07-26,4,<1,12,0,<1
+2020-08-02,4,<1,10,0,<1
+2020-08-09,5,<1,10,0,0
+2020-08-16,4,<1,10,0,0
+2020-08-23,3,<1,9,0,<1
+2020-08-30,3,1,8,0,<1
+2020-09-06,2,<1,8,0,<1
+2020-09-13,2,<1,6,0,<1
+2020-09-20,2,<1,5,0,<1
+2020-09-27,2,<1,6,0,<1
+2020-10-04,2,<1,7,0,<1
+2020-10-11,2,<1,8,0,<1
+2020-10-18,1,<1,7,0,<1
+2020-10-25,1,<1,7,0,<1
+2020-11-01,1,<1,8,0,0
+2020-11-08,3,<1,11,0,<1
+2020-11-15,4,<1,15,0,<1
+2020-11-22,11,1,27,0,<1
+2020-11-29,7,1,25,0,1
+2020-12-06,6,<1,23,0,<1
+2020-12-13,5,<1,19,0,<1
+2020-12-20,4,0,17,0,<1
+2020-12-27,3,<1,9,0,<1
+2021-01-03,3,0,7,0,<1
+2021-01-10,3,<1,6,0,<1
+2021-01-17,3,1,6,<1,<1
+2021-01-24,3,<1,6,<1,<1
+2021-01-31,3,<1,6,0,<1
+2021-02-07,3,<1,6,0,0
+2021-02-14,2,<1,7,0,<1
+2021-02-21,3,<1,8,0,<1
+2021-02-28,3,<1,7,0,<1
+2021-03-07,2,<1,7,0,<1
+2021-03-14,3,<1,7,0,<1
+2021-03-21,3,<1,7,0,0
+2021-03-28,3,<1,8,0,<1
+2021-04-04,1,<1,7,0,0
+2021-04-11,1,<1,9,0,1
+2021-04-18,1,<1,9,0,<1
+2021-04-25,1,1,10,0,1
+2021-05-02,1,<1,10,0,<1
+2021-05-09,1,<1,10,0,<1
+2021-05-16,1,<1,10,0,0
+2021-05-23,1,<1,11,1,<1
+2021-05-30,1,<1,13,0,1
+2021-06-06,1,<1,14,0,1
+2021-06-13,<1,<1,16,0,<1
+2021-06-20,<1,1,12,0,<1
+2021-06-27,1,<1,12,0,<1
+2021-07-04,2,1,13,0,<1
+2021-07-11,1,<1,13,0,<1
+2021-07-18,<1,<1,13,0,<1
+2021-07-25,1,<1,13,0,<1
+2021-08-01,4,<1,12,<1,<1
+2021-08-08,4,1,12,<1,<1
+2021-08-15,4,<1,12,<1,<1
+2021-08-22,4,<1,12,0,<1
+2021-08-29,4,1,11,0,<1
+2021-09-05,3,<1,11,0,0
+2021-09-12,3,<1,9,0,<1
+2021-09-19,3,1,7,0,<1
+2021-09-26,5,<1,8,0,<1
+2021-10-03,4,0,8,<1,<1
+2021-10-10,3,<1,8,<1,1
+2021-10-17,4,<1,10,<1,<1
+2021-10-24,3,<1,9,<1,<1
+2021-10-31,5,<1,12,<1,0
+2021-11-07,6,<1,13,0,<1
+2021-11-14,7,<1,16,<1,<1
+2021-11-21,15,1,40,<1,1
+2021-11-28,9,<1,29,<1,1
+2021-12-05,8,<1,20,<1,1
+2021-12-12,6,1,21,<1,1
+2021-12-19,6,<1,17,<1,1
+2021-12-26,4,<1,10,<1,<1
+2022-01-02,4,<1,7,0,1
+2022-01-09,3,<1,8,<1,1
+2022-01-16,3,<1,7,0,<1
+2022-01-23,4,<1,4,<1,1
+2022-01-30,3,<1,7,<1,1
+2022-02-06,4,<1,8,0,<1
+2022-02-13,3,<1,6,<1,<1
+2022-02-20,4,<1,8,<1,<1
+2022-02-27,5,1,8,<1,1
+2022-03-06,5,<1,8,<1,1
+2022-03-13,4,<1,8,1,1
+2022-03-20,4,<1,7,<1,2
+2022-03-27,4,<1,7,0,1
+2022-04-03,4,<1,7,<1,2
+2022-04-10,5,<1,8,<1,1
+2022-04-17,5,<1,9,0,3
+2022-04-24,5,1,10,<1,2
+2022-05-01,5,1,11,<1,2
+2022-05-08,4,<1,11,<1,2
+2022-05-15,5,1,11,0,1
+2022-05-22,5,1,12,<1,2
+2022-05-29,6,<1,14,<1,3
+2022-06-05,5,<1,13,<1,2
+2022-06-12,5,<1,17,0,2
+2022-06-19,5,1,14,<1,2
+2022-06-26,6,1,14,<1,2
+2022-07-03,6,1,13,<1,2
+2022-07-10,7,1,14,<1,3
+2022-07-17,8,1,14,<1,2
+2022-07-24,8,1,13,1,2
+2022-07-31,8,1,13,1,2
+2022-08-07,8,1,13,1,3
+2022-08-14,8,1,11,1,5
+2022-08-21,7,1,11,<1,4
+2022-08-28,6,1,12,<1,4
+2022-09-04,8,1,11,<1,3
+2022-09-11,6,1,9,1,6
+2022-09-18,5,<1,10,1,4
+2022-09-25,6,1,8,1,4
+2022-10-02,7,<1,9,<1,6
+2022-10-09,6,<1,9,1,5
+2022-10-16,6,<1,10,1,5
+2022-10-23,5,1,9,1,4
+2022-10-30,5,<1,8,1,4
+2022-11-06,7,<1,10,1,6
+2022-11-13,8,1,16,1,11
+2022-11-20,17,1,39,2,19
+2022-11-27,13,1,29,1,11
+2022-12-04,10,1,23,1,10
+2022-12-11,10,1,22,1,15
+2022-12-18,9,<1,19,1,14
+2022-12-25,6,1,12,1,19
+2023-01-01,5,1,7,1,14
+2023-01-08,5,<1,7,1,14
+2023-01-15,5,<1,7,1,13
+2023-01-22,4,<1,7,1,12
+2023-01-29,4,<1,7,1,13
+2023-02-05,5,<1,7,1,13
+2023-02-12,5,1,8,1,10
+2023-02-19,4,1,8,1,8
+2023-02-26,4,<1,7,1,9
+2023-03-05,4,1,9,1,11
+2023-03-12,4,<1,9,1,12
+2023-03-19,3,<1,8,1,9
+2023-03-26,4,1,8,1,10
+2023-04-02,2,<1,8,1,10
+2023-04-09,2,1,8,1,10
+2023-04-16,2,<1,11,1,10
+2023-04-23,3,<1,10,1,11
+2023-04-30,2,<1,10,1,12
+2023-05-07,3,<1,11,1,17
+2023-05-14,4,1,10,1,12
+2023-05-21,4,1,10,1,10
+2023-05-28,6,<1,12,1,9
+2023-06-04,5,<1,13,2,11
+2023-06-11,4,<1,14,1,11
+2023-06-18,5,<1,12,2,11
+2023-06-25,3,<1,12,2,11
+2023-07-02,5,<1,13,2,10
+2023-07-09,6,1,13,2,11
+2023-07-16,7,1,14,2,11
+2023-07-23,6,1,14,2,11
+2023-07-30,8,<1,12,2,15
+2023-08-06,7,<1,12,3,14
+2023-08-13,7,1,12,3,14
+2023-08-20,6,<1,11,2,15
+2023-08-27,6,<1,12,3,14
+2023-09-03,4,1,11,2,16
+2023-09-10,4,<1,11,2,13
+2023-09-17,3,<1,11,2,14
+2023-09-24,3,<1,9,2,13
+2023-10-01,4,<1,9,2,12
+2023-10-08,3,<1,10,2,14
+2023-10-15,4,<1,9,2,13
+2023-10-22,4,<1,9,2,18
+2023-10-29,4,<1,12,3,22
+2023-11-05,5,1,13,3,30
+2023-11-12,7,<1,17,4,36
+2023-11-19,13,<1,43,10,100
+2023-11-26,9,1,32,7,61
+2023-12-03,8,1,23,5,50
+2023-12-10,9,1,25,6,58
+2023-12-17,8,<1,22,4,60
+2023-12-24,6,<1,16,4,58
+2023-12-31,5,<1,11,4,72
+2024-01-07,5,<1,10,4,54
+2024-01-14,4,<1,9,5,41
+2024-01-21,4,<1,9,4,34
+2024-01-28,5,<1,8,6,31
+2024-02-04,4,<1,8,6,25
+2024-02-11,4,<1,7,6,25
+2024-02-18,4,0,9,7,20
diff --git a/README.md b/README.md
index d557c1091..dbe9c3c09 100644
--- a/README.md
+++ b/README.md
@@ -1,125 +1,31 @@
Final Project - Interactive Data Visualization
===
-The key learning experience of this course is the final project.
-You will design a web site and interactive visualizations that answer questions you have, provide an exploratory interface to some topic of your own choosing, or take on a more ambitious experiment than A3.
-You will acquire the data, design your visualizations, implement them, and critically evaluate the results.
-
-The path to a good visualization is going to involve mistakes and wrong turns.
-It is therefore important to recognize that mistakes are valuable in finding the path to a solution, to broadly explore the design space, and to iterate designs to improve possible solutions.
-To help you explore the design space, we will hold events such as feedback sessions in which you propose your idea and initial designs and receive feedback from the class and staff.
-
-Proposals / Idea Generation
----
-
-Submit project ideas using [this Google Form](https://docs.google.com/forms/d/e/1FAIpQLSc72vId8keotkEvLrB9Ef3Nt0e1uh_-mWmQ5okyPM5_q2a89Q/viewform?usp=sf_link).
-
-You're encouraged to submit many ideas-- staff will help you identify the most promising ones and possible roadblocks.
-
-Please stick to 1-4 folks per team.
-
Final Project Materials
---
-For your final project you must hand in the following items.
-
-### Process Book
-
-An important part of your project is your process book. Your process book details your steps in developing your solution, including the alternative designs you tried, and the insights you got. Develop your process book out of the project proposal. Equally important to your final results is how you got there! Your process book is the place you describe and document the space of possibilities you explored at each step of your project. It is not, however, a journal or lab notebook that describes every detail - you should think carefully about the important decisions you made and insights you gained and present your reasoning in a concise way.
-
-We strongly advise you to include many figures in your process book, including photos of your sketches of potential designs, screen shots from different visualization tools you explored, inspirations of visualizations you found online, etc. Several images illustrating changes in your design or focus over time will be far more informative than text describing those changes. Instead, use text to describe the rationale behind the evolution of your project.
-
-Your process book should include the following topics. Depending on your project type the amount of discussion you devote to each of them will vary:
-
-- Overview and Motivation: Provide an overview of the project goals and the motivation for it. Consider that this will be read by people who did not see your project proposal.
-- Related Work: Anything that inspired you, such as a paper, a web site, visualizations we discussed in class, etc.
-- Questions: What questions are you trying to answer? How did these questions evolve over the course of the project? What new questions did you consider in the course of your analysis?
-- Data: Source, scraping method, cleanup, etc.
-- Exploratory Data Analysis: What visualizations did you use to initially look at your data? What insights did you gain? How did these insights inform your design?
-- Design Evolution: What are the different visualizations you considered? Justify the design decisions you made using the perceptual and design principles you learned in the course. Did you deviate from your proposal?
-- Implementation: Describe the intent and functionality of the interactive visualizations you implemented. Provide clear and well-referenced images showing the key design and interaction elements.
-- Evaluation: What did you learn about the data by using your visualizations? How did you answer your questions? How well does your visualization work, and how could you further improve it?
-
-As this will be your only chance to describe your project in detail make sure that your process book is a standalone document that fully describes your results and the final design.
-[Here](http://dataviscourse.net/2015/assets/process_books/bansal_cao_hou.pdf) are a [few examples](http://dataviscourse.net/2015/assets/process_books/walsh_trevino_bett.pdf) of process books from a similar course final.
-
-Tip: Start your process book on Day 1. Make entries after each meeting, and trim / edit as needed towards the end of the project. Many folks use either slides software (like PowerPoint) or Google Docs to make this book, as both allow for flexible layouts and export to PDF.
-
-
-### Project Website
-
-Create a public website for your project using GitHub pages or another web hosting service of your choice.
-The web site should contain your interactive visualization, summarize the main results of the project, and tell a story.
-Consider your audience (the site should be public if possible, unless you're running an experiment, etc.) and keep the level of discussion at the appropriate level.
-Your process book and data should be linked from the web site as well.
-Also embed your interactive visualization and your screen-cast in your website.
-If you are not able to publish your work (e.g., due to confidential data) please let us know in your project proposal.
-
-### Project Screen-Cast
-
-Each team will create a two minute screen-cast with narration showing a demo of your visualization and/or some slides.
+[Video](https://youtu.be/VbCk6CSi4iM)
-You can use any screencast tool of your choice, such as Camtasia or Loom (new and recommended).
-Please make sure that the sound quality of your video is good -- it may be worthwhile to invest in an external USB microphone-- campus IT should have some you can borrow.
-Upload the video to an online video-platform such as YouTube or Vimeo and embed it into your project web page.
-For our final project presentation day, we will show as many videos in class as possible, and ask teams to field questions.
+[Process Book](https://docs.google.com/presentation/d/1Iz2fUi5wetALkWzXyHJfAC_ioYpeF0vQSNt6nnwLatU/edit?usp=sharing)
-We will strictly enforce the two minute time limit for the video, so please make sure you are not running longer.
-Use principles of good storytelling and presentations to get your key points across. Focus the majority of your screencast on your main contributions rather than on technical details.
-What do you feel is the best part of your project?
-What insights did you gain?
-What is the single most important thing you would like your audience to take away? Make sure it is front and center rather than at the end.
-Outside Libraries/References
----
-
-For this project you *do not* have to write everything from scratch.
-
-You may *reference* demo programs from books or the web, and *include* popular web libraries like Material UI, React, Svelte, etcetera.
-
-Please *do not* use libraries on top of d3 without consulting staff, however.
-Libraries like nvd3.js look tempting, but such libraries often have poor defaults and result in poor visualizations.
-There may be exceptions.
-Instead, draw from the numerous existing d3 examples on the web.
-
-If you use outside sources please provide a References section with links at the end of your Readme.
-
-Resources
----
-The "[Data is Plural](https://tinyletter.com/data-is-plural/archive)" weekly letter often contains interesting datasets.
-
-KAGGLE IS BANNED! You may propose to use a dataset from there if you really have a deep/cool idea, but please run it by me first.
-
-Think of something you're interested in, go find data on it! Include data collection and processing as part of your work on this project.
-
-Requirements
+References
---
-Store the following in your GitHub repository:
+- This final project is adapted from https://www.dataviscourse.net/2020/project/
-- Code - All web site files and libraries assuming they are not too big to include
-- Data - Include all the data that you used in your project. If the data is too large for github store it on a cloud storage provider, such as Dropbox or Yousendit.
-- Process Book- Your Process Book in PDF format.
-- README - The README file must give an overview of what you are handing in: which parts are your code, which parts are libraries, and so on. The README must contain URLs to your project websites and screencast videos. The README must also explain any non-obvious features of your interface.
+- https://observablehq.com/@d3/bar-chart/2
-GitHub Details
----
+-[usa projection ](https://observablehq.com/@harrystevens/introducing-d3-geo-scale-bar)
-- Fork the repo. You now have a copy associated with your username.
-- Make changes to index.html to fulfill the project requirements.
-- Make sure your "main" branch matches your "gh-pages" branch. See the GitHub Guides referenced above if you need help.
-- Edit the README.md with a link to your gh-pages or other external site: for example http://YourUsernameGoesHere.github.io/DataVisFinal/index.html
-- To submit, make a [Pull Request](https://help.github.com/articles/using-pull-requests/) on the original repository.
+- [cartogram](https://observablehq.com/@tophtucker/cartogram)
-Grading
----
+- [tooltip](https://d3-graph-gallery.com/graph/interactivity_tooltip.html)
-- Process Book - Are you following a design process that is well documented in your process book?
-- Solution - Is your visualization effective in answering your intended questions? Was it designed following visualization principles?
-- Implementation - What is the quality of your implementation? Is it appropriately polished, robust, and reliable?
-- Presentation - Are your web site and screencast clear, engaging, and effective?
-Your individual project score will also be influenced by your peer evaluations.
+Technical Achievements
+- Two visualizations with a main view
+- State Search
-References
----
-
-- This final project is adapted from https://www.dataviscourse.net/2020/project/
+Design Achievements
+- Animations to switch between visualizations
+- Tool tip
+ - Click to show zoomed view
\ No newline at end of file
diff --git a/RatingsByState.csv b/RatingsByState.csv
new file mode 100644
index 000000000..151388fc0
--- /dev/null
+++ b/RatingsByState.csv
@@ -0,0 +1,51 @@
+Region,Owala,Stanley,YETI,HydroFlask,Nalgene
+AL,41,76,46,29,12
+AK,16,33,41,46,100
+AZ,16,57,39,67,25
+AR,33,76,39,25,12
+CA,25,43,39,88,25
+CO,33,44,48,61,75
+CT,25,46,52,50,37
+DE,41,47,57,33,12
+FL,25,49,47,22,12
+GA,25,52,43,25,25
+HI,25,42,100,100,37
+ID,25,75,46,59,62
+IL,33,50,42,40,25
+IN,41,62,42,35,25
+IA,66,79,45,66,25
+KS,41,71,46,48,25
+KY,50,78,42,30,25
+LA,25,56,32,22,12
+ME,33,59,72,48,87
+MD,25,43,40,33,25
+MA,33,49,60,54,37
+MI,33,50,53,35,25
+MN,50,55,50,59,50
+MS,25,76,43,24,0
+MO,41,65,39,40,37
+MT,8,57,65,61,87
+NE,58,76,50,72,37
+NV,25,40,31,66,25
+NH,33,52,75,64,37
+NJ,25,44,41,43,12
+NM,16,40,49,37,25
+NY,16,30,38,30,25
+NC,41,55,52,33,37
+ND,41,75,55,69,25
+OH,41,52,49,35,25
+OK,33,65,37,27,12
+OR,16,40,37,74,50
+PA,33,49,57,41,37
+RI,33,47,52,50,37
+SC,41,66,53,30,37
+SD,50,81,46,77,50
+TN,41,68,41,35,37
+TX,33,65,59,35,12
+UT,100,100,39,67,62
+VT,,39,58,56,37
+VA,33,44,43,41,37
+WA,25,43,32,58,50
+WV,16,75,52,24,50
+WI,50,55,50,45,37
+WY,8,59,65,53,62
diff --git a/Water bottle trends.pdf b/Water bottle trends.pdf
new file mode 100644
index 000000000..a1b97c892
Binary files /dev/null and b/Water bottle trends.pdf differ
diff --git a/index.html b/index.html
new file mode 100644
index 000000000..395c82aa5
--- /dev/null
+++ b/index.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+ Trendiest bottle
+
+
+
+
+
What's your state's favorite bottle?
+
+
+
+
Over the years water bottles have become more and more of a trend and even form of expression.
+ Here I want to compare of the trend of the “most searched water bottle” between states as well as specific brands.
+ These comparisons are limited to the USA and trends of the past 5 years
+
+
+ As mentioned in the process book, evaluating major search trends is not an easy process
+ something can be tagged one way but have a different meaning than inteded.
+ Filters were applied to alleviate this, but it still may not be perfect. This project
+ wants to aknowledge this but still recognize the larger trends going on.
+
+
+
+
Findings
+
+ Highlights in this data include:
+
+
Areas towards the West have higher searches in general but search Stanley the most
+
Areas on the East Coast generally search less for all the brands but largely search YETI
+
HI and AK have the greatest range in searches. With brands either at index 100 or below 50.
+
Utah contains peak index for the least and most searched brands, Owala and Stanley respectively
+
+
+
+
+
+
+
diff --git a/mock.ipynb b/mock.ipynb
new file mode 100644
index 000000000..9145ce48d
--- /dev/null
+++ b/mock.ipynb
@@ -0,0 +1,67 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "FileNotFoundError",
+ "evalue": "[Errno 2] No such file or directory: '5years/HydroFlask5Years.csv'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_23736\\4016431818.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mmatplotlib\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpyplot\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mplt\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mhf\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"5years/HydroFlask5Years.csv\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[0mnalgene\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"5years/Nalegene5Years.csv\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[0mowala\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"5years/Owala5Years.csv\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32mc:\\Users\\kylie\\anaconda3\\lib\\site-packages\\pandas\\util\\_decorators.py\u001b[0m in \u001b[0;36mwrapper\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m 309\u001b[0m \u001b[0mstacklevel\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mstacklevel\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 310\u001b[0m )\n\u001b[1;32m--> 311\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 312\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 313\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32mc:\\Users\\kylie\\anaconda3\\lib\\site-packages\\pandas\\io\\parsers\\readers.py\u001b[0m in \u001b[0;36mread_csv\u001b[1;34m(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, error_bad_lines, warn_bad_lines, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options)\u001b[0m\n\u001b[0;32m 676\u001b[0m \u001b[0mkwds\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkwds_defaults\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 677\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 678\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0m_read\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfilepath_or_buffer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 679\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 680\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32mc:\\Users\\kylie\\anaconda3\\lib\\site-packages\\pandas\\io\\parsers\\readers.py\u001b[0m in \u001b[0;36m_read\u001b[1;34m(filepath_or_buffer, kwds)\u001b[0m\n\u001b[0;32m 573\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 574\u001b[0m \u001b[1;31m# Create the parser.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 575\u001b[1;33m \u001b[0mparser\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mTextFileReader\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfilepath_or_buffer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 576\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 577\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mchunksize\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0miterator\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32mc:\\Users\\kylie\\anaconda3\\lib\\site-packages\\pandas\\io\\parsers\\readers.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, f, engine, **kwds)\u001b[0m\n\u001b[0;32m 930\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 931\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhandles\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mIOHandles\u001b[0m \u001b[1;33m|\u001b[0m \u001b[1;32mNone\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 932\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_engine\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_make_engine\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mf\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mengine\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 933\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 934\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mclose\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32mc:\\Users\\kylie\\anaconda3\\lib\\site-packages\\pandas\\io\\parsers\\readers.py\u001b[0m in \u001b[0;36m_make_engine\u001b[1;34m(self, f, engine)\u001b[0m\n\u001b[0;32m 1214\u001b[0m \u001b[1;31m# \"Union[str, PathLike[str], ReadCsvBuffer[bytes], ReadCsvBuffer[str]]\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1215\u001b[0m \u001b[1;31m# , \"str\", \"bool\", \"Any\", \"Any\", \"Any\", \"Any\", \"Any\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1216\u001b[1;33m self.handles = get_handle( # type: ignore[call-overload]\n\u001b[0m\u001b[0;32m 1217\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1218\u001b[0m \u001b[0mmode\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32mc:\\Users\\kylie\\anaconda3\\lib\\site-packages\\pandas\\io\\common.py\u001b[0m in \u001b[0;36mget_handle\u001b[1;34m(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)\u001b[0m\n\u001b[0;32m 784\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mioargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mencoding\u001b[0m \u001b[1;32mand\u001b[0m \u001b[1;34m\"b\"\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mioargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmode\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 785\u001b[0m \u001b[1;31m# Encoding\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 786\u001b[1;33m handle = open(\n\u001b[0m\u001b[0;32m 787\u001b[0m \u001b[0mhandle\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 788\u001b[0m \u001b[0mioargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmode\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '5years/HydroFlask5Years.csv'"
+ ]
+ }
+ ],
+ "source": [
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "hf = pd.read_csv(\"/5yearsHydroFlask5Years.csv\")\n",
+ "nalgene = pd.read_csv(\"/5years/Nalegene5Years.csv\")\n",
+ "owala = pd.read_csv(\"/5years/Owala5Years.csv\")\n",
+ "stanley = pd.read_csv(\"/5years/Stanley5Years.csv\")\n",
+ "yeti = pd.read_csv(\"/5years/Yeti5Years.csv\")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "base",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.13"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/multiTimeline1Year.csv b/multiTimeline1Year.csv
new file mode 100644
index 000000000..dfe3b90f1
--- /dev/null
+++ b/multiTimeline1Year.csv
@@ -0,0 +1,55 @@
+Category: Shopping
+
+Week,Hydro Flask: (United States),Nalgene: (United States),YETI: (United States),Owala®: (United States),Stanley: (United States)
+2023-02-26,4,<1,8,1,9
+2023-03-05,4,1,9,1,11
+2023-03-12,4,<1,9,1,12
+2023-03-19,3,<1,8,1,8
+2023-03-26,4,<1,8,1,10
+2023-04-02,3,<1,8,1,10
+2023-04-09,2,<1,9,1,10
+2023-04-16,2,<1,11,1,10
+2023-04-23,3,<1,10,1,11
+2023-04-30,2,<1,10,1,12
+2023-05-07,3,<1,11,1,17
+2023-05-14,4,1,10,1,12
+2023-05-21,4,1,11,1,10
+2023-05-28,6,<1,12,2,9
+2023-06-04,5,<1,13,2,11
+2023-06-11,4,1,15,1,11
+2023-06-18,5,<1,12,2,11
+2023-06-25,3,<1,12,2,11
+2023-07-02,5,<1,13,2,10
+2023-07-09,7,1,13,2,10
+2023-07-16,7,1,14,2,11
+2023-07-23,6,1,14,2,11
+2023-07-30,8,<1,13,3,15
+2023-08-06,7,1,13,3,14
+2023-08-13,8,1,13,3,15
+2023-08-20,6,<1,11,2,15
+2023-08-27,6,<1,12,3,14
+2023-09-03,4,1,12,2,16
+2023-09-10,4,<1,11,2,13
+2023-09-17,3,<1,12,2,14
+2023-09-24,3,<1,9,2,13
+2023-10-01,4,<1,9,2,12
+2023-10-08,3,<1,10,2,14
+2023-10-15,4,1,10,2,13
+2023-10-22,4,1,9,2,18
+2023-10-29,4,1,12,3,22
+2023-11-05,6,1,14,3,31
+2023-11-12,7,<1,17,4,37
+2023-11-19,13,<1,44,10,100
+2023-11-26,10,<1,32,7,62
+2023-12-03,8,1,23,5,51
+2023-12-10,9,1,26,6,56
+2023-12-17,7,<1,22,4,60
+2023-12-24,6,1,16,4,58
+2023-12-31,5,<1,11,5,72
+2024-01-07,5,<1,11,4,55
+2024-01-14,4,<1,9,5,41
+2024-01-21,4,1,9,3,34
+2024-01-28,5,<1,8,6,32
+2024-02-04,4,1,8,6,25
+2024-02-11,4,1,7,6,25
+2024-02-18,4,1,10,7,20
diff --git a/node_modules/.bin/geo2svg b/node_modules/.bin/geo2svg
new file mode 100644
index 000000000..01acfb83f
--- /dev/null
+++ b/node_modules/.bin/geo2svg
@@ -0,0 +1,12 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../d3-geo-projection/bin/geo2svg.js" "$@"
+else
+ exec node "$basedir/../d3-geo-projection/bin/geo2svg.js" "$@"
+fi
diff --git a/node_modules/.bin/geo2svg.cmd b/node_modules/.bin/geo2svg.cmd
new file mode 100644
index 000000000..2824b9bbb
--- /dev/null
+++ b/node_modules/.bin/geo2svg.cmd
@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\d3-geo-projection\bin\geo2svg.js" %*
diff --git a/node_modules/.bin/geo2svg.ps1 b/node_modules/.bin/geo2svg.ps1
new file mode 100644
index 000000000..1ef2e49c6
--- /dev/null
+++ b/node_modules/.bin/geo2svg.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geo2svg.js" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geo2svg.js" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../d3-geo-projection/bin/geo2svg.js" $args
+ } else {
+ & "node$exe" "$basedir/../d3-geo-projection/bin/geo2svg.js" $args
+ }
+ $ret=$LASTEXITCODE
+}
+exit $ret
diff --git a/node_modules/.bin/geograticule b/node_modules/.bin/geograticule
new file mode 100644
index 000000000..15e473fec
--- /dev/null
+++ b/node_modules/.bin/geograticule
@@ -0,0 +1,12 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../d3-geo-projection/bin/geograticule.js" "$@"
+else
+ exec node "$basedir/../d3-geo-projection/bin/geograticule.js" "$@"
+fi
diff --git a/node_modules/.bin/geograticule.cmd b/node_modules/.bin/geograticule.cmd
new file mode 100644
index 000000000..85f09c4c9
--- /dev/null
+++ b/node_modules/.bin/geograticule.cmd
@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\d3-geo-projection\bin\geograticule.js" %*
diff --git a/node_modules/.bin/geograticule.ps1 b/node_modules/.bin/geograticule.ps1
new file mode 100644
index 000000000..911c65abb
--- /dev/null
+++ b/node_modules/.bin/geograticule.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geograticule.js" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geograticule.js" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../d3-geo-projection/bin/geograticule.js" $args
+ } else {
+ & "node$exe" "$basedir/../d3-geo-projection/bin/geograticule.js" $args
+ }
+ $ret=$LASTEXITCODE
+}
+exit $ret
diff --git a/node_modules/.bin/geoproject b/node_modules/.bin/geoproject
new file mode 100644
index 000000000..738cad41a
--- /dev/null
+++ b/node_modules/.bin/geoproject
@@ -0,0 +1,12 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../d3-geo-projection/bin/geoproject.js" "$@"
+else
+ exec node "$basedir/../d3-geo-projection/bin/geoproject.js" "$@"
+fi
diff --git a/node_modules/.bin/geoproject.cmd b/node_modules/.bin/geoproject.cmd
new file mode 100644
index 000000000..d204cd5e4
--- /dev/null
+++ b/node_modules/.bin/geoproject.cmd
@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\d3-geo-projection\bin\geoproject.js" %*
diff --git a/node_modules/.bin/geoproject.ps1 b/node_modules/.bin/geoproject.ps1
new file mode 100644
index 000000000..b020d3a9c
--- /dev/null
+++ b/node_modules/.bin/geoproject.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geoproject.js" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geoproject.js" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../d3-geo-projection/bin/geoproject.js" $args
+ } else {
+ & "node$exe" "$basedir/../d3-geo-projection/bin/geoproject.js" $args
+ }
+ $ret=$LASTEXITCODE
+}
+exit $ret
diff --git a/node_modules/.bin/geoquantize b/node_modules/.bin/geoquantize
new file mode 100644
index 000000000..3e0879b03
--- /dev/null
+++ b/node_modules/.bin/geoquantize
@@ -0,0 +1,12 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../d3-geo-projection/bin/geoquantize.js" "$@"
+else
+ exec node "$basedir/../d3-geo-projection/bin/geoquantize.js" "$@"
+fi
diff --git a/node_modules/.bin/geoquantize.cmd b/node_modules/.bin/geoquantize.cmd
new file mode 100644
index 000000000..a861fd7fd
--- /dev/null
+++ b/node_modules/.bin/geoquantize.cmd
@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\d3-geo-projection\bin\geoquantize.js" %*
diff --git a/node_modules/.bin/geoquantize.ps1 b/node_modules/.bin/geoquantize.ps1
new file mode 100644
index 000000000..d47b64990
--- /dev/null
+++ b/node_modules/.bin/geoquantize.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geoquantize.js" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geoquantize.js" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../d3-geo-projection/bin/geoquantize.js" $args
+ } else {
+ & "node$exe" "$basedir/../d3-geo-projection/bin/geoquantize.js" $args
+ }
+ $ret=$LASTEXITCODE
+}
+exit $ret
diff --git a/node_modules/.bin/geostitch b/node_modules/.bin/geostitch
new file mode 100644
index 000000000..0b075eee5
--- /dev/null
+++ b/node_modules/.bin/geostitch
@@ -0,0 +1,12 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../d3-geo-projection/bin/geostitch.js" "$@"
+else
+ exec node "$basedir/../d3-geo-projection/bin/geostitch.js" "$@"
+fi
diff --git a/node_modules/.bin/geostitch.cmd b/node_modules/.bin/geostitch.cmd
new file mode 100644
index 000000000..2164d8edd
--- /dev/null
+++ b/node_modules/.bin/geostitch.cmd
@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\d3-geo-projection\bin\geostitch.js" %*
diff --git a/node_modules/.bin/geostitch.ps1 b/node_modules/.bin/geostitch.ps1
new file mode 100644
index 000000000..ae8da0029
--- /dev/null
+++ b/node_modules/.bin/geostitch.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geostitch.js" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../d3-geo-projection/bin/geostitch.js" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../d3-geo-projection/bin/geostitch.js" $args
+ } else {
+ & "node$exe" "$basedir/../d3-geo-projection/bin/geostitch.js" $args
+ }
+ $ret=$LASTEXITCODE
+}
+exit $ret
diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json
new file mode 100644
index 000000000..d94937e2f
--- /dev/null
+++ b/node_modules/.package-lock.json
@@ -0,0 +1,65 @@
+{
+ "name": "final",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "node_modules/commander": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-geo": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz",
+ "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==",
+ "dependencies": {
+ "d3-array": "2.5.0 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-geo-projection": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz",
+ "integrity": "sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==",
+ "dependencies": {
+ "commander": "7",
+ "d3-array": "1 - 3",
+ "d3-geo": "1.12.0 - 3"
+ },
+ "bin": {
+ "geo2svg": "bin/geo2svg.js",
+ "geograticule": "bin/geograticule.js",
+ "geoproject": "bin/geoproject.js",
+ "geoquantize": "bin/geoquantize.js",
+ "geostitch": "bin/geostitch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "engines": {
+ "node": ">=12"
+ }
+ }
+ }
+}
diff --git a/node_modules/commander/CHANGELOG.md b/node_modules/commander/CHANGELOG.md
new file mode 100644
index 000000000..0b55881b5
--- /dev/null
+++ b/node_modules/commander/CHANGELOG.md
@@ -0,0 +1,440 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). (Format adopted after v3.0.0.)
+
+
+
+
+## [7.2.0] (2021-03-26)
+
+### Added
+
+- TypeScript typing for `parent` property on `Command` ([#1475])
+- TypeScript typing for `.attributeName()` on `Option` ([#1483])
+- support information in package ([#1477])
+
+### Changed
+
+- improvements to error messages, README, and tests
+- update dependencies
+
+## [7.1.0] (2021-02-15)
+
+### Added
+
+- support for named imports from ECMAScript modules ([#1440])
+- add `.cjs` to list of expected script file extensions ([#1449])
+- allow using option choices and variadic together ([#1454])
+
+### Fixed
+
+- replace use of deprecated `process.mainModule` ([#1448])
+- regression for legacy `command('*')` and call when command line includes options ([#1464])
+- regression for `on('command:*', ...)` and call when command line includes unknown options ([#1464])
+- display best error for combination of unknown command and unknown option (i.e. unknown command) ([#1464])
+
+### Changed
+
+- make TypeScript typings tests stricter ([#1453])
+- improvements to README and tests
+
+## [7.0.0] (2021-01-15)
+
+### Added
+
+- `.enablePositionalOptions()` to let program and subcommand reuse same option ([#1427])
+- `.passThroughOptions()` to pass options through to other programs without needing `--` ([#1427])
+- `.allowExcessArguments(false)` to show an error message if there are too many command-arguments on command line for the action handler ([#1409])
+- `.configureOutput()` to modify use of stdout and stderr or customise display of errors ([#1387])
+- use `.addHelpText()` to add text before or after the built-in help, for just current command or also for all subcommands ([#1296])
+- enhance Option class ([#1331])
+ - allow hiding options from help
+ - allow restricting option arguments to a list of choices
+ - allow setting how default value is shown in help
+- `.createOption()` to support subclassing of automatically created options (like `.createCommand()`) ([#1380])
+- refactor the code generating the help into a separate public Help class ([#1365])
+ - support sorting subcommands and options in help
+ - support specifying wrap width (columns)
+ - allow subclassing Help class
+ - allow configuring Help class without subclassing
+
+### Changed
+
+- *Breaking:* options are stored safely by default, not as properties on the command ([#1409])
+ - this especially affects accessing options on program, use `program.opts()`
+ - revert behaviour with `.storeOptionsAsProperties()`
+- *Breaking:* action handlers are passed options and command separately ([#1409])
+- deprecated callback parameter to `.help()` and `.outputHelp()` (removed from README) ([#1296])
+- *Breaking:* errors now displayed using `process.stderr.write()` instead of `console.error()`
+- deprecate `.on('--help')` (removed from README) ([#1296])
+- initialise the command description to empty string (previously undefined) ([#1365])
+- document and annotate deprecated routines ([#1349])
+
+### Fixed
+
+- wrapping bugs in help ([#1365])
+ - first line of command description was wrapping two characters early
+ - pad width calculation was not including help option and help command
+ - pad width calculation was including hidden options and commands
+- improve backwards compatibility for custom command event listeners ([#1403])
+
+### Deleted
+
+- *Breaking:* `.passCommandToAction()` ([#1409])
+ - no longer needed as action handler is passed options and command
+- *Breaking:* "extra arguments" parameter to action handler ([#1409])
+ - if being used to detect excess arguments, there is now an error available by setting `.allowExcessArguments(false)`
+
+### Migration Tips
+
+The biggest change is the parsed option values. Previously the options were stored by default as properties on the command object, and now the options are stored separately.
+
+If you wish to restore the old behaviour and get running quickly you can call `.storeOptionsAsProperties()`.
+To allow you to move to the new code patterns incrementally, the action handler will be passed the command _twice_,
+to match the new "options" and "command" parameters (see below).
+
+**program options**
+
+Use the `.opts()` method to access the options. This is available on any command but is used most with the program.
+
+```js
+program.option('-d, --debug');
+program.parse();
+// Old code before Commander 7
+if (program.debug) console.log(`Program name is ${program.name()}`);
+```
+
+```js
+// New code
+const options = program.opts();
+if (options.debug) console.log(`Program name is ${program.name()}`);
+```
+
+**action handler**
+
+The action handler gets passed a parameter for each command-argument you declared. Previously by default the next parameter was the command object with the options as properties. Now the next two parameters are instead the options and the command. If you
+only accessed the options there may be no code changes required.
+
+```js
+program
+ .command('compress ')
+ .option('-t, --trace')
+ // Old code before Commander 7
+ .action((filename, cmd)) => {
+ if (cmd.trace) console.log(`Command name is ${cmd.name()}`);
+ });
+```
+
+```js
+ // New code
+ .action((filename, options, command)) => {
+ if (options.trace) console.log(`Command name is ${command.name()}`);
+ });
+```
+
+If you already set `.storeOptionsAsProperties(false)` you may still need to adjust your code.
+
+```js
+program
+ .command('compress ')
+ .storeOptionsAsProperties(false)
+ .option('-t, --trace')
+ // Old code before Commander 7
+ .action((filename, command)) => {
+ if (command.opts().trace) console.log(`Command name is ${command.name()}`);
+ });
+```
+
+```js
+ // New code
+ .action((filename, options, command)) => {
+ if (command.opts().trace) console.log(`Command name is ${command.name()}`);
+ });
+```
+
+## [7.0.0-2] (2020-12-14)
+
+(Released in 7.0.0)
+
+## [7.0.0-1] (2020-11-21)
+
+(Released in 7.0.0)
+
+## [7.0.0-0] (2020-10-25)
+
+(Released in 7.0.0)
+
+## [6.2.1] (2020-12-13)
+
+### Fixed
+
+- some tests failed if directory path included a space ([1390])
+
+## [6.2.0] (2020-10-25)
+
+### Added
+
+- added 'tsx' file extension for stand-alone executable subcommands ([#1368])
+- documented second parameter to `.description()` to describe command arguments ([#1353])
+- documentation of special cases with options taking varying numbers of option-arguments ([#1332])
+- documentation for terminology ([#1361])
+
+### Fixed
+
+- add missing TypeScript definition for `.addHelpCommand()' ([#1375])
+- removed blank line after "Arguments:" in help, to match "Options:" and "Commands:" ([#1360])
+
+### Changed
+
+- update dependencies
+
+## [6.1.0] (2020-08-28)
+
+### Added
+
+- include URL to relevant section of README for error for potential conflict between Command properties and option values ([#1306])
+- `.combineFlagAndOptionalValue(false)` to ease upgrade path from older versions of Commander ([#1326])
+- allow disabling the built-in help option using `.helpOption(false)` ([#1325])
+- allow just some arguments in `argumentDescription` to `.description()` ([#1323])
+
+### Changed
+
+- tidy async test and remove lint override ([#1312])
+
+### Fixed
+
+- executable subcommand launching when script path not known ([#1322])
+
+## [6.0.0] (2020-07-21)
+
+### Added
+
+- add support for variadic options ([#1250])
+- allow options to be added with just a short flag ([#1256])
+ - *Breaking* the option property has same case as flag. e.g. flag `-n` accessed as `opts().n` (previously uppercase)
+- *Breaking* throw an error if there might be a clash between option name and a Command property, with advice on how to resolve ([#1275])
+
+### Fixed
+
+- Options which contain -no- in the middle of the option flag should not be treated as negatable. ([#1301])
+
+## [6.0.0-0] (2020-06-20)
+
+(Released in 6.0.0)
+
+## [5.1.0] (2020-04-25)
+
+### Added
+
+- support for multiple command aliases, the first of which is shown in the auto-generated help ([#531], [#1236])
+- configuration support in `addCommand()` for `hidden` and `isDefault` ([#1232])
+
+### Fixed
+
+- omit masked help flags from the displayed help ([#645], [#1247])
+- remove old short help flag when change help flags using `helpOption` ([#1248])
+
+### Changed
+
+- remove use of `arguments` to improve auto-generated help in editors ([#1235])
+- rename `.command()` configuration `noHelp` to `hidden` (but not remove old support) ([#1232])
+- improvements to documentation
+- update dependencies
+- update tested versions of node
+- eliminate lint errors in TypeScript ([#1208])
+
+## [5.0.0] (2020-03-14)
+
+### Added
+
+* support for nested commands with action-handlers ([#1] [#764] [#1149])
+* `.addCommand()` for adding a separately configured command ([#764] [#1149])
+* allow a non-executable to be set as the default command ([#742] [#1149])
+* implicit help command when there are subcommands (previously only if executables) ([#1149])
+* customise implicit help command with `.addHelpCommand()` ([#1149])
+* display error message for unknown subcommand, by default ([#432] [#1088] [#1149])
+* display help for missing subcommand, by default ([#1088] [#1149])
+* combined short options as single argument may include boolean flags and value flag and value (e.g. `-a -b -p 80` can be written as `-abp80`) ([#1145])
+* `.parseOption()` includes short flag and long flag expansions ([#1145])
+* `.helpInformation()` returns help text as a string, previously a private routine ([#1169])
+* `.parse()` implicitly uses `process.argv` if arguments not specified ([#1172])
+* optionally specify where `.parse()` arguments "from", if not following node conventions ([#512] [#1172])
+* suggest help option along with unknown command error ([#1179])
+* TypeScript definition for `commands` property of `Command` ([#1184])
+* export `program` property ([#1195])
+* `createCommand` factory method to simplify subclassing ([#1191])
+
+### Fixed
+
+* preserve argument order in subcommands ([#508] [#962] [#1138])
+* do not emit `command:*` for executable subcommands ([#809] [#1149])
+* action handler called whether or not there are non-option arguments ([#1062] [#1149])
+* combining option short flag and value in single argument now works for subcommands ([#1145])
+* only add implicit help command when it will not conflict with other uses of argument ([#1153] [#1149])
+* implicit help command works with command aliases ([#948] [#1149])
+* options are validated whether or not there is an action handler ([#1149])
+
+### Changed
+
+* *Breaking* `.args` contains command arguments with just recognised options removed ([#1032] [#1138])
+* *Breaking* display error if required argument for command is missing ([#995] [#1149])
+* tighten TypeScript definition of custom option processing function passed to `.option()` ([#1119])
+* *Breaking* `.allowUnknownOption()` ([#802] [#1138])
+ * unknown options included in arguments passed to command action handler
+ * unknown options included in `.args`
+* only recognised option short flags and long flags are expanded (e.g. `-ab` or `--foo=bar`) ([#1145])
+* *Breaking* `.parseOptions()` ([#1138])
+ * `args` in returned result renamed `operands` and does not include anything after first unknown option
+ * `unknown` in returned result has arguments after first unknown option including operands, not just options and values
+* *Breaking* `.on('command:*', callback)` and other command events passed (changed) results from `.parseOptions`, i.e. operands and unknown ([#1138])
+* refactor Option from prototype to class ([#1133])
+* refactor Command from prototype to class ([#1159])
+* changes to error handling ([#1165])
+ * throw for author error, not just display message
+ * preflight for variadic error
+ * add tips to missing subcommand executable
+* TypeScript fluent return types changed to be more subclass friendly, return `this` rather than `Command` ([#1180])
+* `.parseAsync` returns `Promise` to be consistent with `.parse()` ([#1180])
+* update dependencies
+
+### Removed
+
+* removed EventEmitter from TypeScript definition for Command, eliminating implicit peer dependency on `@types/node` ([#1146])
+* removed private function `normalize` (the functionality has been integrated into `parseOptions`) ([#1145])
+* `parseExpectedArgs` is now private ([#1149])
+
+### Migration Tips
+
+If you use `.on('command:*')` or more complicated tests to detect an unrecognised subcommand, you may be able to delete the code and rely on the default behaviour.
+
+If you use `program.args` or more complicated tests to detect a missing subcommand, you may be able to delete the code and rely on the default behaviour.
+
+If you use `.command('*')` to add a default command, you may be be able to switch to `isDefault:true` with a named command.
+
+If you want to continue combining short options with optional values as though they were boolean flags, set `combineFlagAndOptionalValue(false)`
+to expand `-fb` to `-f -b` rather than `-f b`.
+
+## [5.0.0-4] (2020-03-03)
+
+(Released in 5.0.0)
+
+## [5.0.0-3] (2020-02-20)
+
+(Released in 5.0.0)
+
+## [5.0.0-2] (2020-02-10)
+
+(Released in 5.0.0)
+
+## [5.0.0-1] (2020-02-08)
+
+(Released in 5.0.0)
+
+## [5.0.0-0] (2020-02-02)
+
+(Released in 5.0.0)
+
+## Older versions
+
+* [4.x](./changelogs/CHANGELOG-4.md)
+* [3.x](./changelogs/CHANGELOG-3.md)
+* [2.x](./changelogs/CHANGELOG-2.md)
+* [1.x](./changelogs/CHANGELOG-1.md)
+* [0.x](./changelogs/CHANGELOG-0.md)
+
+[#1]: https://github.com/tj/commander.js/issues/1
+[#432]: https://github.com/tj/commander.js/issues/432
+[#508]: https://github.com/tj/commander.js/issues/508
+[#512]: https://github.com/tj/commander.js/issues/512
+[#531]: https://github.com/tj/commander.js/issues/531
+[#645]: https://github.com/tj/commander.js/issues/645
+[#742]: https://github.com/tj/commander.js/issues/742
+[#764]: https://github.com/tj/commander.js/issues/764
+[#802]: https://github.com/tj/commander.js/issues/802
+[#809]: https://github.com/tj/commander.js/issues/809
+[#948]: https://github.com/tj/commander.js/issues/948
+[#962]: https://github.com/tj/commander.js/issues/962
+[#995]: https://github.com/tj/commander.js/issues/995
+[#1032]: https://github.com/tj/commander.js/issues/1032
+[#1062]: https://github.com/tj/commander.js/pull/1062
+[#1088]: https://github.com/tj/commander.js/issues/1088
+[#1119]: https://github.com/tj/commander.js/pull/1119
+[#1133]: https://github.com/tj/commander.js/pull/1133
+[#1138]: https://github.com/tj/commander.js/pull/1138
+[#1145]: https://github.com/tj/commander.js/pull/1145
+[#1146]: https://github.com/tj/commander.js/pull/1146
+[#1149]: https://github.com/tj/commander.js/pull/1149
+[#1153]: https://github.com/tj/commander.js/issues/1153
+[#1159]: https://github.com/tj/commander.js/pull/1159
+[#1165]: https://github.com/tj/commander.js/pull/1165
+[#1169]: https://github.com/tj/commander.js/pull/1169
+[#1172]: https://github.com/tj/commander.js/pull/1172
+[#1179]: https://github.com/tj/commander.js/pull/1179
+[#1180]: https://github.com/tj/commander.js/pull/1180
+[#1184]: https://github.com/tj/commander.js/pull/1184
+[#1191]: https://github.com/tj/commander.js/pull/1191
+[#1195]: https://github.com/tj/commander.js/pull/1195
+[#1208]: https://github.com/tj/commander.js/pull/1208
+[#1232]: https://github.com/tj/commander.js/pull/1232
+[#1235]: https://github.com/tj/commander.js/pull/1235
+[#1236]: https://github.com/tj/commander.js/pull/1236
+[#1247]: https://github.com/tj/commander.js/pull/1247
+[#1248]: https://github.com/tj/commander.js/pull/1248
+[#1250]: https://github.com/tj/commander.js/pull/1250
+[#1256]: https://github.com/tj/commander.js/pull/1256
+[#1275]: https://github.com/tj/commander.js/pull/1275
+[#1296]: https://github.com/tj/commander.js/pull/1296
+[#1301]: https://github.com/tj/commander.js/issues/1301
+[#1306]: https://github.com/tj/commander.js/pull/1306
+[#1312]: https://github.com/tj/commander.js/pull/1312
+[#1322]: https://github.com/tj/commander.js/pull/1322
+[#1323]: https://github.com/tj/commander.js/pull/1323
+[#1325]: https://github.com/tj/commander.js/pull/1325
+[#1326]: https://github.com/tj/commander.js/pull/1326
+[#1331]: https://github.com/tj/commander.js/pull/1331
+[#1332]: https://github.com/tj/commander.js/pull/1332
+[#1349]: https://github.com/tj/commander.js/pull/1349
+[#1353]: https://github.com/tj/commander.js/pull/1353
+[#1360]: https://github.com/tj/commander.js/pull/1360
+[#1361]: https://github.com/tj/commander.js/pull/1361
+[#1365]: https://github.com/tj/commander.js/pull/1365
+[#1368]: https://github.com/tj/commander.js/pull/1368
+[#1375]: https://github.com/tj/commander.js/pull/1375
+[#1380]: https://github.com/tj/commander.js/pull/1380
+[#1387]: https://github.com/tj/commander.js/pull/1387
+[#1390]: https://github.com/tj/commander.js/pull/1390
+[#1403]: https://github.com/tj/commander.js/pull/1403
+[#1409]: https://github.com/tj/commander.js/pull/1409
+[#1427]: https://github.com/tj/commander.js/pull/1427
+[#1440]: https://github.com/tj/commander.js/pull/1440
+[#1448]: https://github.com/tj/commander.js/pull/1448
+[#1449]: https://github.com/tj/commander.js/pull/1449
+[#1453]: https://github.com/tj/commander.js/pull/1453
+[#1454]: https://github.com/tj/commander.js/pull/1454
+[#1464]: https://github.com/tj/commander.js/pull/1464
+[#1475]: https://github.com/tj/commander.js/pull/1475
+[#1477]: https://github.com/tj/commander.js/pull/1477
+[#1483]: https://github.com/tj/commander.js/pull/1483
+
+[Unreleased]: https://github.com/tj/commander.js/compare/master...develop
+[7.2.0]: https://github.com/tj/commander.js/compare/v7.1.0...v7.2.0
+[7.1.0]: https://github.com/tj/commander.js/compare/v7.0.0...v7.1.0
+[7.0.0]: https://github.com/tj/commander.js/compare/v6.2.1...v7.0.0
+[7.0.0-2]: https://github.com/tj/commander.js/compare/v7.0.0-1...v7.0.0-2
+[7.0.0-1]: https://github.com/tj/commander.js/compare/v7.0.0-0...v7.0.0-1
+[7.0.0-0]: https://github.com/tj/commander.js/compare/v6.2.0...v7.0.0-0
+[6.2.1]: https://github.com/tj/commander.js/compare/v6.2.0..v6.2.1
+[6.2.0]: https://github.com/tj/commander.js/compare/v6.1.0..v6.2.0
+[6.1.0]: https://github.com/tj/commander.js/compare/v6.0.0..v6.1.0
+[6.0.0]: https://github.com/tj/commander.js/compare/v5.1.0..v6.0.0
+[6.0.0-0]: https://github.com/tj/commander.js/compare/v5.1.0..v6.0.0-0
+[5.1.0]: https://github.com/tj/commander.js/compare/v5.0.0..v5.1.0
+[5.0.0]: https://github.com/tj/commander.js/compare/v4.1.1..v5.0.0
+[5.0.0-4]: https://github.com/tj/commander.js/compare/v5.0.0-3..v5.0.0-4
+[5.0.0-3]: https://github.com/tj/commander.js/compare/v5.0.0-2..v5.0.0-3
+[5.0.0-2]: https://github.com/tj/commander.js/compare/v5.0.0-1..v5.0.0-2
+[5.0.0-1]: https://github.com/tj/commander.js/compare/v5.0.0-0..v5.0.0-1
+[5.0.0-0]: https://github.com/tj/commander.js/compare/v4.1.1..v5.0.0-0
diff --git a/node_modules/commander/LICENSE b/node_modules/commander/LICENSE
new file mode 100644
index 000000000..10f997ab1
--- /dev/null
+++ b/node_modules/commander/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2011 TJ Holowaychuk
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/commander/Readme.md b/node_modules/commander/Readme.md
new file mode 100644
index 000000000..d2a88a7b2
--- /dev/null
+++ b/node_modules/commander/Readme.md
@@ -0,0 +1,917 @@
+# Commander.js
+
+[](https://github.com/tj/commander.js/actions?query=workflow%3A%22build%22)
+[](https://www.npmjs.org/package/commander)
+[](https://npmcharts.com/compare/commander?minimal=true)
+[](https://packagephobia.now.sh/result?p=commander)
+
+The complete solution for [node.js](http://nodejs.org) command-line interfaces.
+
+Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
+
+- [Commander.js](#commanderjs)
+ - [Installation](#installation)
+ - [Declaring _program_ variable](#declaring-program-variable)
+ - [Options](#options)
+ - [Common option types, boolean and value](#common-option-types-boolean-and-value)
+ - [Default option value](#default-option-value)
+ - [Other option types, negatable boolean and boolean|value](#other-option-types-negatable-boolean-and-booleanvalue)
+ - [Required option](#required-option)
+ - [Variadic option](#variadic-option)
+ - [Version option](#version-option)
+ - [More configuration](#more-configuration)
+ - [Custom option processing](#custom-option-processing)
+ - [Commands](#commands)
+ - [Specify the argument syntax](#specify-the-argument-syntax)
+ - [Action handler](#action-handler)
+ - [Stand-alone executable (sub)commands](#stand-alone-executable-subcommands)
+ - [Automated help](#automated-help)
+ - [Custom help](#custom-help)
+ - [Display help from code](#display-help-from-code)
+ - [.usage and .name](#usage-and-name)
+ - [.helpOption(flags, description)](#helpoptionflags-description)
+ - [.addHelpCommand()](#addhelpcommand)
+ - [More configuration](#more-configuration-1)
+ - [Custom event listeners](#custom-event-listeners)
+ - [Bits and pieces](#bits-and-pieces)
+ - [.parse() and .parseAsync()](#parse-and-parseasync)
+ - [Parsing Configuration](#parsing-configuration)
+ - [Legacy options as properties](#legacy-options-as-properties)
+ - [TypeScript](#typescript)
+ - [createCommand()](#createcommand)
+ - [Node options such as `--harmony`](#node-options-such-as---harmony)
+ - [Debugging stand-alone executable subcommands](#debugging-stand-alone-executable-subcommands)
+ - [Override exit and output handling](#override-exit-and-output-handling)
+ - [Additional documentation](#additional-documentation)
+ - [Examples](#examples)
+ - [Support](#support)
+ - [Commander for enterprise](#commander-for-enterprise)
+
+For information about terms used in this document see: [terminology](./docs/terminology.md)
+
+## Installation
+
+```bash
+npm install commander
+```
+
+## Declaring _program_ variable
+
+Commander exports a global object which is convenient for quick programs.
+This is used in the examples in this README for brevity.
+
+```js
+const { program } = require('commander');
+program.version('0.0.1');
+```
+
+For larger programs which may use commander in multiple ways, including unit testing, it is better to create a local Command object to use.
+
+```js
+const { Command } = require('commander');
+const program = new Command();
+program.version('0.0.1');
+```
+
+For named imports in ECMAScript modules, import from `commander/esm.mjs`.
+
+```js
+// index.mjs
+import { Command } from 'commander/esm.mjs';
+const program = new Command();
+```
+
+And in TypeScript:
+
+```ts
+// index.ts
+import { Command } from 'commander';
+const program = new Command();
+```
+
+
+## Options
+
+Options are defined with the `.option()` method, also serving as documentation for the options. Each option can have a short flag (single character) and a long name, separated by a comma or space or vertical bar ('|').
+
+The parsed options can be accessed by calling `.opts()` on a `Command` object, and are passed to the action handler. Multi-word options such as "--template-engine" are camel-cased, becoming `program.opts().templateEngine` etc.
+
+Multiple short flags may optionally be combined in a single argument following the dash: boolean flags, followed by a single option taking a value (possibly followed by the value).
+For example `-a -b -p 80` may be written as `-ab -p80` or even `-abp80`.
+
+You can use `--` to indicate the end of the options, and any remaining arguments will be used without being interpreted.
+
+By default options on the command line are not positional, and can be specified before or after other arguments.
+
+### Common option types, boolean and value
+
+The two most used option types are a boolean option, and an option which takes its value
+from the following argument (declared with angle brackets like `--expect `). Both are `undefined` unless specified on command line.
+
+Example file: [options-common.js](./examples/options-common.js)
+
+```js
+program
+ .option('-d, --debug', 'output extra debugging')
+ .option('-s, --small', 'small pizza size')
+ .option('-p, --pizza-type ', 'flavour of pizza');
+
+program.parse(process.argv);
+
+const options = program.opts();
+if (options.debug) console.log(options);
+console.log('pizza details:');
+if (options.small) console.log('- small pizza size');
+if (options.pizzaType) console.log(`- ${options.pizzaType}`);
+```
+
+```bash
+$ pizza-options -d
+{ debug: true, small: undefined, pizzaType: undefined }
+pizza details:
+$ pizza-options -p
+error: option '-p, --pizza-type ' argument missing
+$ pizza-options -ds -p vegetarian
+{ debug: true, small: true, pizzaType: 'vegetarian' }
+pizza details:
+- small pizza size
+- vegetarian
+$ pizza-options --pizza-type=cheese
+pizza details:
+- cheese
+```
+
+`program.parse(arguments)` processes the arguments, leaving any args not consumed by the program options in the `program.args` array. The parameter is optional and defaults to `process.argv`.
+
+### Default option value
+
+You can specify a default value for an option which takes a value.
+
+Example file: [options-defaults.js](./examples/options-defaults.js)
+
+```js
+program
+ .option('-c, --cheese ', 'add the specified type of cheese', 'blue');
+
+program.parse();
+
+console.log(`cheese: ${program.opts().cheese}`);
+```
+
+```bash
+$ pizza-options
+cheese: blue
+$ pizza-options --cheese stilton
+cheese: stilton
+```
+
+### Other option types, negatable boolean and boolean|value
+
+You can define a boolean option long name with a leading `no-` to set the option value to false when used.
+Defined alone this also makes the option true by default.
+
+If you define `--foo` first, adding `--no-foo` does not change the default value from what it would
+otherwise be. You can specify a default boolean value for a boolean option and it can be overridden on command line.
+
+Example file: [options-negatable.js](./examples/options-negatable.js)
+
+```js
+program
+ .option('--no-sauce', 'Remove sauce')
+ .option('--cheese ', 'cheese flavour', 'mozzarella')
+ .option('--no-cheese', 'plain with no cheese')
+ .parse();
+
+const options = program.opts();
+const sauceStr = options.sauce ? 'sauce' : 'no sauce';
+const cheeseStr = (options.cheese === false) ? 'no cheese' : `${options.cheese} cheese`;
+console.log(`You ordered a pizza with ${sauceStr} and ${cheeseStr}`);
+```
+
+```bash
+$ pizza-options
+You ordered a pizza with sauce and mozzarella cheese
+$ pizza-options --sauce
+error: unknown option '--sauce'
+$ pizza-options --cheese=blue
+You ordered a pizza with sauce and blue cheese
+$ pizza-options --no-sauce --no-cheese
+You ordered a pizza with no sauce and no cheese
+```
+
+You can specify an option which may be used as a boolean option but may optionally take an option-argument
+(declared with square brackets like `--optional [value]`).
+
+Example file: [options-boolean-or-value.js](./examples/options-boolean-or-value.js)
+
+```js
+program
+ .option('-c, --cheese [type]', 'Add cheese with optional type');
+
+program.parse(process.argv);
+
+const options = program.opts();
+if (options.cheese === undefined) console.log('no cheese');
+else if (options.cheese === true) console.log('add cheese');
+else console.log(`add cheese type ${options.cheese}`);
+```
+
+```bash
+$ pizza-options
+no cheese
+$ pizza-options --cheese
+add cheese
+$ pizza-options --cheese mozzarella
+add cheese type mozzarella
+```
+
+For information about possible ambiguous cases, see [options taking varying arguments](./docs/options-taking-varying-arguments.md).
+
+### Required option
+
+You may specify a required (mandatory) option using `.requiredOption`. The option must have a value after parsing, usually specified on the command line, or perhaps from a default value (say from environment). The method is otherwise the same as `.option` in format, taking flags and description, and optional default value or custom processing.
+
+Example file: [options-required.js](./examples/options-required.js)
+
+```js
+program
+ .requiredOption('-c, --cheese ', 'pizza must have cheese');
+
+program.parse();
+```
+
+```bash
+$ pizza
+error: required option '-c, --cheese ' not specified
+```
+
+### Variadic option
+
+You may make an option variadic by appending `...` to the value placeholder when declaring the option. On the command line you
+can then specify multiple option-arguments, and the parsed option value will be an array. The extra arguments
+are read until the first argument starting with a dash. The special argument `--` stops option processing entirely. If a value
+is specified in the same argument as the option then no further values are read.
+
+Example file: [options-variadic.js](./examples/options-variadic.js)
+
+```js
+program
+ .option('-n, --number ', 'specify numbers')
+ .option('-l, --letter [letters...]', 'specify letters');
+
+program.parse();
+
+console.log('Options: ', program.opts());
+console.log('Remaining arguments: ', program.args);
+```
+
+```bash
+$ collect -n 1 2 3 --letter a b c
+Options: { number: [ '1', '2', '3' ], letter: [ 'a', 'b', 'c' ] }
+Remaining arguments: []
+$ collect --letter=A -n80 operand
+Options: { number: [ '80' ], letter: [ 'A' ] }
+Remaining arguments: [ 'operand' ]
+$ collect --letter -n 1 -n 2 3 -- operand
+Options: { number: [ '1', '2', '3' ], letter: true }
+Remaining arguments: [ 'operand' ]
+```
+
+For information about possible ambiguous cases, see [options taking varying arguments](./docs/options-taking-varying-arguments.md).
+
+### Version option
+
+The optional `version` method adds handling for displaying the command version. The default option flags are `-V` and `--version`, and when present the command prints the version number and exits.
+
+```js
+program.version('0.0.1');
+```
+
+```bash
+$ ./examples/pizza -V
+0.0.1
+```
+
+You may change the flags and description by passing additional parameters to the `version` method, using
+the same syntax for flags as the `option` method.
+
+```js
+program.version('0.0.1', '-v, --vers', 'output the current version');
+```
+
+### More configuration
+
+You can add most options using the `.option()` method, but there are some additional features available
+by constructing an `Option` explicitly for less common cases.
+
+Example file: [options-extra.js](./examples/options-extra.js)
+
+```js
+program
+ .addOption(new Option('-s, --secret').hideHelp())
+ .addOption(new Option('-t, --timeout ', 'timeout in seconds').default(60, 'one minute'))
+ .addOption(new Option('-d, --drink ', 'drink size').choices(['small', 'medium', 'large']));
+```
+
+```bash
+$ extra --help
+Usage: help [options]
+
+Options:
+ -t, --timeout timeout in seconds (default: one minute)
+ -d, --drink drink cup size (choices: "small", "medium", "large")
+ -h, --help display help for command
+
+$ extra --drink huge
+error: option '-d, --drink ' argument 'huge' is invalid. Allowed choices are small, medium, large.
+```
+
+### Custom option processing
+
+You may specify a function to do custom processing of option-arguments. The callback function receives two parameters,
+the user specified option-argument and the previous value for the option. It returns the new value for the option.
+
+This allows you to coerce the option-argument to the desired type, or accumulate values, or do entirely custom processing.
+
+You can optionally specify the default/starting value for the option after the function parameter.
+
+Example file: [options-custom-processing.js](./examples/options-custom-processing.js)
+
+```js
+function myParseInt(value, dummyPrevious) {
+ // parseInt takes a string and a radix
+ const parsedValue = parseInt(value, 10);
+ if (isNaN(parsedValue)) {
+ throw new commander.InvalidOptionArgumentError('Not a number.');
+ }
+ return parsedValue;
+}
+
+function increaseVerbosity(dummyValue, previous) {
+ return previous + 1;
+}
+
+function collect(value, previous) {
+ return previous.concat([value]);
+}
+
+function commaSeparatedList(value, dummyPrevious) {
+ return value.split(',');
+}
+
+program
+ .option('-f, --float ', 'float argument', parseFloat)
+ .option('-i, --integer ', 'integer argument', myParseInt)
+ .option('-v, --verbose', 'verbosity that can be increased', increaseVerbosity, 0)
+ .option('-c, --collect ', 'repeatable value', collect, [])
+ .option('-l, --list ', 'comma separated list', commaSeparatedList)
+;
+
+program.parse();
+
+const options = program.opts();
+if (options.float !== undefined) console.log(`float: ${options.float}`);
+if (options.integer !== undefined) console.log(`integer: ${options.integer}`);
+if (options.verbose > 0) console.log(`verbosity: ${options.verbose}`);
+if (options.collect.length > 0) console.log(options.collect);
+if (options.list !== undefined) console.log(options.list);
+```
+
+```bash
+$ custom -f 1e2
+float: 100
+$ custom --integer 2
+integer: 2
+$ custom -v -v -v
+verbose: 3
+$ custom -c a -c b -c c
+[ 'a', 'b', 'c' ]
+$ custom --list x,y,z
+[ 'x', 'y', 'z' ]
+```
+
+## Commands
+
+You can specify (sub)commands using `.command()` or `.addCommand()`. There are two ways these can be implemented: using an action handler attached to the command, or as a stand-alone executable file (described in more detail later). The subcommands may be nested ([example](./examples/nestedCommands.js)).
+
+In the first parameter to `.command()` you specify the command name and any command-arguments. The arguments may be `` or `[optional]`, and the last argument may also be `variadic...`.
+
+You can use `.addCommand()` to add an already configured subcommand to the program.
+
+For example:
+
+```js
+// Command implemented using action handler (description is supplied separately to `.command`)
+// Returns new command for configuring.
+program
+ .command('clone [destination]')
+ .description('clone a repository into a newly created directory')
+ .action((source, destination) => {
+ console.log('clone command called');
+ });
+
+// Command implemented using stand-alone executable file (description is second parameter to `.command`)
+// Returns `this` for adding more commands.
+program
+ .command('start ', 'start named service')
+ .command('stop [service]', 'stop named service, or all if no name supplied');
+
+// Command prepared separately.
+// Returns `this` for adding more commands.
+program
+ .addCommand(build.makeBuildCommand());
+```
+
+Configuration options can be passed with the call to `.command()` and `.addCommand()`. Specifying `hidden: true` will
+remove the command from the generated help output. Specifying `isDefault: true` will run the subcommand if no other
+subcommand is specified ([example](./examples/defaultCommand.js)).
+
+### Specify the argument syntax
+
+You use `.arguments` to specify the expected command-arguments for the top-level command, and for subcommands they are usually
+included in the `.command` call. Angled brackets (e.g. ``) indicate required command-arguments.
+Square brackets (e.g. `[optional]`) indicate optional command-arguments.
+You can optionally describe the arguments in the help by supplying a hash as second parameter to `.description()`.
+
+Example file: [arguments.js](./examples/arguments.js)
+
+```js
+program
+ .version('0.1.0')
+ .arguments(' [password]')
+ .description('test command', {
+ username: 'user to login',
+ password: 'password for user, if required'
+ })
+ .action((username, password) => {
+ console.log('username:', username);
+ console.log('environment:', password || 'no password given');
+ });
+```
+
+ The last argument of a command can be variadic, and only the last argument. To make an argument variadic you
+ append `...` to the argument name. For example:
+
+```js
+program
+ .version('0.1.0')
+ .command('rmdir ')
+ .action(function (dirs) {
+ dirs.forEach((dir) => {
+ console.log('rmdir %s', dir);
+ });
+ });
+```
+
+The variadic argument is passed to the action handler as an array.
+
+### Action handler
+
+The action handler gets passed a parameter for each command-argument you declared, and two additional parameters
+which are the parsed options and the command object itself.
+
+Example file: [thank.js](./examples/thank.js)
+
+```js
+program
+ .arguments('')
+ .option('-t, --title ', 'title to use before name')
+ .option('-d, --debug', 'display some debugging')
+ .action((name, options, command) => {
+ if (options.debug) {
+ console.error('Called %s with options %o', command.name(), options);
+ }
+ const title = options.title ? `${options.title} ` : '';
+ console.log(`Thank-you ${title}${name}`);
+ });
+```
+
+You may supply an `async` action handler, in which case you call `.parseAsync` rather than `.parse`.
+
+```js
+async function run() { /* code goes here */ }
+
+async function main() {
+ program
+ .command('run')
+ .action(run);
+ await program.parseAsync(process.argv);
+}
+```
+
+A command's options and arguments on the command line are validated when the command is used. Any unknown options or missing arguments will be reported as an error. You can suppress the unknown option checks with `.allowUnknownOption()`. By default it is not an error to
+pass more arguments than declared, but you can make this an error with `.allowExcessArguments(false)`.
+
+### Stand-alone executable (sub)commands
+
+When `.command()` is invoked with a description argument, this tells Commander that you're going to use stand-alone executables for subcommands.
+Commander will search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-subcommand`, like `pm-install`, `pm-search`.
+You can specify a custom name with the `executableFile` configuration option.
+
+You handle the options for an executable (sub)command in the executable, and don't declare them at the top-level.
+
+Example file: [pm](./examples/pm)
+
+```js
+program
+ .version('0.1.0')
+ .command('install [name]', 'install one or more packages')
+ .command('search [query]', 'search with optional query')
+ .command('update', 'update installed packages', { executableFile: 'myUpdateSubCommand' })
+ .command('list', 'list packages installed', { isDefault: true });
+
+program.parse(process.argv);
+```
+
+If the program is designed to be installed globally, make sure the executables have proper modes, like `755`.
+
+## Automated help
+
+The help information is auto-generated based on the information commander already knows about your program. The default
+help option is `-h,--help`.
+
+Example file: [pizza](./examples/pizza)
+
+```bash
+$ node ./examples/pizza --help
+Usage: pizza [options]
+
+An application for pizza ordering
+
+Options:
+ -p, --peppers Add peppers
+ -c, --cheese Add the specified type of cheese (default: "marble")
+ -C, --no-cheese You do not want any cheese
+ -h, --help display help for command
+```
+
+A `help` command is added by default if your command has subcommands. It can be used alone, or with a subcommand name to show
+further help for the subcommand. These are effectively the same if the `shell` program has implicit help:
+
+```bash
+shell help
+shell --help
+
+shell help spawn
+shell spawn --help
+```
+
+### Custom help
+
+You can add extra text to be displayed along with the built-in help.
+
+Example file: [custom-help](./examples/custom-help)
+
+```js
+program
+ .option('-f, --foo', 'enable some foo');
+
+program.addHelpText('after', `
+
+Example call:
+ $ custom-help --help`);
+```
+
+Yields the following help output:
+
+```Text
+Usage: custom-help [options]
+
+Options:
+ -f, --foo enable some foo
+ -h, --help display help for command
+
+Example call:
+ $ custom-help --help
+```
+
+The positions in order displayed are:
+
+- `beforeAll`: add to the program for a global banner or header
+- `before`: display extra information before built-in help
+- `after`: display extra information after built-in help
+- `afterAll`: add to the program for a global footer (epilog)
+
+The positions "beforeAll" and "afterAll" apply to the command and all its subcommands.
+
+The second parameter can be a string, or a function returning a string. The function is passed a context object for your convenience. The properties are:
+
+- error: a boolean for whether the help is being displayed due to a usage error
+- command: the Command which is displaying the help
+
+### Display help from code
+
+`.help()`: display help information and exit immediately. You can optionally pass `{ error: true }` to display on stderr and exit with an error status.
+
+`.outputHelp()`: output help information without exiting. You can optionally pass `{ error: true }` to display on stderr.
+
+`.helpInformation()`: get the built-in command help information as a string for processing or displaying yourself.
+
+### .usage and .name
+
+These allow you to customise the usage description in the first line of the help. The name is otherwise
+deduced from the (full) program arguments. Given:
+
+```js
+program
+ .name("my-command")
+ .usage("[global options] command")
+```
+
+The help will start with:
+
+```Text
+Usage: my-command [global options] command
+```
+
+### .helpOption(flags, description)
+
+By default every command has a help option. Override the default help flags and description. Pass false to disable the built-in help option.
+
+```js
+program
+ .helpOption('-e, --HELP', 'read more information');
+```
+
+### .addHelpCommand()
+
+A help command is added by default if your command has subcommands. You can explicitly turn on or off the implicit help command with `.addHelpCommand()` and `.addHelpCommand(false)`.
+
+You can both turn on and customise the help command by supplying the name and description:
+
+```js
+program.addHelpCommand('assist [command]', 'show assistance');
+```
+
+### More configuration
+
+The built-in help is formatted using the Help class.
+You can configure the Help behaviour by modifying data properties and methods using `.configureHelp()`, or by subclassing using `.createHelp()` if you prefer.
+
+The data properties are:
+
+- `helpWidth`: specify the wrap width, useful for unit tests
+- `sortSubcommands`: sort the subcommands alphabetically
+- `sortOptions`: sort the options alphabetically
+
+There are methods getting the visible lists of arguments, options, and subcommands. There are methods for formatting the items in the lists, with each item having a _term_ and _description_. Take a look at `.formatHelp()` to see how they are used.
+
+Example file: [configure-help.js](./examples/configure-help.js)
+
+```
+program.configureHelp({
+ sortSubcommands: true,
+ subcommandTerm: (cmd) => cmd.name() // Just show the name, instead of short usage.
+});
+```
+
+## Custom event listeners
+
+You can execute custom actions by listening to command and option events.
+
+```js
+program.on('option:verbose', function () {
+ process.env.VERBOSE = this.opts().verbose;
+});
+
+program.on('command:*', function (operands) {
+ console.error(`error: unknown command '${operands[0]}'`);
+ const availableCommands = program.commands.map(cmd => cmd.name());
+ mySuggestBestMatch(operands[0], availableCommands);
+ process.exitCode = 1;
+});
+```
+
+## Bits and pieces
+
+### .parse() and .parseAsync()
+
+The first argument to `.parse` is the array of strings to parse. You may omit the parameter to implicitly use `process.argv`.
+
+If the arguments follow different conventions than node you can pass a `from` option in the second parameter:
+
+- 'node': default, `argv[0]` is the application and `argv[1]` is the script being run, with user parameters after that
+- 'electron': `argv[1]` varies depending on whether the electron application is packaged
+- 'user': all of the arguments from the user
+
+For example:
+
+```js
+program.parse(process.argv); // Explicit, node conventions
+program.parse(); // Implicit, and auto-detect electron
+program.parse(['-f', 'filename'], { from: 'user' });
+```
+
+### Parsing Configuration
+
+If the default parsing does not suit your needs, there are some behaviours to support other usage patterns.
+
+By default program options are recognised before and after subcommands. To only look for program options before subcommands, use `.enablePositionalOptions()`. This lets you use
+an option for a different purpose in subcommands.
+
+Example file: [positional-options.js](./examples/positional-options.js)
+
+With positional options, the `-b` is a program option in the first line and a subcommand option in the second line:
+
+```sh
+program -b subcommand
+program subcommand -b
+```
+
+By default options are recognised before and after command-arguments. To only process options that come
+before the command-arguments, use `.passThroughOptions()`. This lets you pass the arguments and following options through to another program
+without needing to use `--` to end the option processing.
+To use pass through options in a subcommand, the program needs to enable positional options.
+
+Example file: [pass-through-options.js](./examples/pass-through-options.js)
+
+With pass through options, the `--port=80` is a program option in the first line and passed through as a command-argument in the second line:
+
+```sh
+program --port=80 arg
+program arg --port=80
+```
+
+By default the option processing shows an error for an unknown option. To have an unknown option treated as an ordinary command-argument and continue looking for options, use `.allowUnknownOption()`. This lets you mix known and unknown options.
+
+By default the argument processing does not display an error for more command-arguments than expected.
+To display an error for excess arguments, use`.allowExcessArguments(false)`.
+
+### Legacy options as properties
+
+Before Commander 7, the option values were stored as properties on the command.
+This was convenient to code but the downside was possible clashes with
+existing properties of `Command`. You can revert to the old behaviour to run unmodified legacy code by using `.storeOptionsAsProperties()`.
+
+```js
+program
+ .storeOptionsAsProperties()
+ .option('-d, --debug')
+ .action((commandAndOptions) => {
+ if (commandAndOptions.debug) {
+ console.error(`Called ${commandAndOptions.name()}`);
+ }
+ });
+```
+
+### TypeScript
+
+If you use `ts-node` and stand-alone executable subcommands written as `.ts` files, you need to call your program through node to get the subcommands called correctly. e.g.
+
+```bash
+node -r ts-node/register pm.ts
+```
+
+### createCommand()
+
+This factory function creates a new command. It is exported and may be used instead of using `new`, like:
+
+```js
+const { createCommand } = require('commander');
+const program = createCommand();
+```
+
+`createCommand` is also a method of the Command object, and creates a new command rather than a subcommand. This gets used internally
+when creating subcommands using `.command()`, and you may override it to
+customise the new subcommand (example file [custom-command-class.js](./examples/custom-command-class.js)).
+
+### Node options such as `--harmony`
+
+You can enable `--harmony` option in two ways:
+
+- Use `#! /usr/bin/env node --harmony` in the subcommands scripts. (Note Windows does not support this pattern.)
+- Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning subcommand process.
+
+### Debugging stand-alone executable subcommands
+
+An executable subcommand is launched as a separate child process.
+
+If you are using the node inspector for [debugging](https://nodejs.org/en/docs/guides/debugging-getting-started/) executable subcommands using `node --inspect` et al,
+the inspector port is incremented by 1 for the spawned subcommand.
+
+If you are using VSCode to debug executable subcommands you need to set the `"autoAttachChildProcesses": true` flag in your launch.json configuration.
+
+### Override exit and output handling
+
+By default Commander calls `process.exit` when it detects errors, or after displaying the help or version. You can override
+this behaviour and optionally supply a callback. The default override throws a `CommanderError`.
+
+The override callback is passed a `CommanderError` with properties `exitCode` number, `code` string, and `message`. The default override behaviour is to throw the error, except for async handling of executable subcommand completion which carries on. The normal display of error messages or version or help
+is not affected by the override which is called after the display.
+
+```js
+program.exitOverride();
+
+try {
+ program.parse(process.argv);
+} catch (err) {
+ // custom processing...
+}
+```
+
+By default Commander is configured for a command-line application and writes to stdout and stderr.
+You can modify this behaviour for custom applications. In addition, you can modify the display of error messages.
+
+Example file: [configure-output.js](./examples/configure-output.js)
+
+
+```js
+function errorColor(str) {
+ // Add ANSI escape codes to display text in red.
+ return `\x1b[31m${str}\x1b[0m`;
+}
+
+program
+ .configureOutput({
+ // Visibly override write routines as example!
+ writeOut: (str) => process.stdout.write(`[OUT] ${str}`),
+ writeErr: (str) => process.stdout.write(`[ERR] ${str}`),
+ // Highlight errors in color.
+ outputError: (str, write) => write(errorColor(str))
+ });
+```
+
+### Additional documentation
+
+There is more information available about:
+
+- [deprecated](./docs/deprecated.md) features still supported for backwards compatibility
+- [options taking varying arguments](./docs/options-taking-varying-arguments.md)
+
+## Examples
+
+In a single command program, you might not need an action handler.
+
+Example file: [pizza](./examples/pizza)
+
+```js
+const { program } = require('commander');
+
+program
+ .description('An application for pizza ordering')
+ .option('-p, --peppers', 'Add peppers')
+ .option('-c, --cheese ', 'Add the specified type of cheese', 'marble')
+ .option('-C, --no-cheese', 'You do not want any cheese');
+
+program.parse();
+
+const options = program.opts();
+console.log('you ordered a pizza with:');
+if (options.peppers) console.log(' - peppers');
+const cheese = !options.cheese ? 'no' : options.cheese;
+console.log(' - %s cheese', cheese);
+```
+
+In a multi-command program, you will have action handlers for each command (or stand-alone executables for the commands).
+
+Example file: [deploy](./examples/deploy)
+
+```js
+const { Command } = require('commander');
+const program = new Command();
+
+program
+ .version('0.0.1')
+ .option('-c, --config ', 'set config path', './deploy.conf');
+
+program
+ .command('setup [env]')
+ .description('run setup commands for all envs')
+ .option('-s, --setup_mode ', 'Which setup mode to use', 'normal')
+ .action((env, options) => {
+ env = env || 'all';
+ console.log('read config from %s', program.opts().config);
+ console.log('setup for %s env(s) with %s mode', env, options.setup_mode);
+ });
+
+program
+ .command('exec
+```
+
+For legacy environments, you can load d3-array’s UMD bundle; a `d3` global is exported:
+
+```html
+
+
+```
+
+## API Reference
+
+* [Statistics](#statistics)
+* [Search](#search)
+* [Transformations](#transformations)
+* [Iterables](#iterables)
+* [Sets](#sets)
+* [Bins](#bins)
+* [Interning](#interning)
+
+### Statistics
+
+Methods for computing basic summary statistics.
+
+# d3.min(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/min.js), [Examples](https://observablehq.com/@d3/d3-extent)
+
+Returns the minimum value in the given *iterable* using natural order. If the iterable contains no comparable values, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the minimum value.
+
+Unlike the built-in [Math.min](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/min), this method ignores undefined, null and NaN values; this is useful for ignoring missing data. In addition, elements are compared using natural order rather than numeric order. For example, the minimum of the strings [“20”, “3”] is “20”, while the minimum of the numbers [20, 3] is 3.
+
+See also [extent](#extent).
+
+# d3.minIndex(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/minIndex.js), [Examples](https://observablehq.com/@d3/d3-extent)
+
+Returns the index of the minimum value in the given *iterable* using natural order. If the iterable contains no comparable values, returns -1. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the minimum value.
+
+Unlike the built-in [Math.min](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/min), this method ignores undefined, null and NaN values; this is useful for ignoring missing data. In addition, elements are compared using natural order rather than numeric order. For example, the minimum of the strings [“20”, “3”] is “20”, while the minimum of the numbers [20, 3] is 3.
+
+# d3.max(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/max.js), [Examples](https://observablehq.com/@d3/d3-extent)
+
+Returns the maximum value in the given *iterable* using natural order. If the iterable contains no comparable values, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the maximum value.
+
+Unlike the built-in [Math.max](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/max), this method ignores undefined values; this is useful for ignoring missing data. In addition, elements are compared using natural order rather than numeric order. For example, the maximum of the strings [“20”, “3”] is “3”, while the maximum of the numbers [20, 3] is 20.
+
+See also [extent](#extent).
+
+# d3.maxIndex(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/maxIndex.js), [Examples](https://observablehq.com/@d3/d3-extent)
+
+Returns the index of the maximum value in the given *iterable* using natural order. If the iterable contains no comparable values, returns -1. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the maximum value.
+
+Unlike the built-in [Math.max](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/max), this method ignores undefined values; this is useful for ignoring missing data. In addition, elements are compared using natural order rather than numeric order. For example, the maximum of the strings [“20”, “3”] is “3”, while the maximum of the numbers [20, 3] is 20.
+
+# d3.extent(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/extent.js), [Examples](https://observablehq.com/@d3/d3-extent)
+
+Returns the [minimum](#min) and [maximum](#max) value in the given *iterable* using natural order. If the iterable contains no comparable values, returns [undefined, undefined]. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the extent.
+
+# d3.mode(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/mode.js), [Examples](https://observablehq.com/@d3/d3-mode)
+
+Returns the mode of the given *iterable*, *i.e.* the value which appears the most often. In case of equality, returns the first of the relevant values. If the iterable contains no comparable values, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the mode. This method ignores undefined, null and NaN values; this is useful for ignoring missing data.
+
+# d3.sum(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/sum.js), [Examples](https://observablehq.com/@d3/d3-sum)
+
+Returns the sum of the given *iterable* of numbers. If the iterable contains no numbers, returns 0. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the sum. This method ignores undefined and NaN values; this is useful for ignoring missing data.
+
+# d3.mean(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/mean.js), [Examples](https://observablehq.com/@d3/d3-mean-d3-median-and-friends)
+
+Returns the mean of the given *iterable* of numbers. If the iterable contains no numbers, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the mean. This method ignores undefined and NaN values; this is useful for ignoring missing data.
+
+# d3.median(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/median.js), [Examples](https://observablehq.com/@d3/d3-mean-d3-median-and-friends)
+
+Returns the median of the given *iterable* of numbers using the [R-7 method](https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample). If the iterable contains no numbers, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the median. This method ignores undefined and NaN values; this is useful for ignoring missing data.
+
+# d3.medianIndex(array[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/median.js)
+
+Similar to *median*, but returns the index of the element to the left of the median.
+
+# d3.cumsum(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/cumsum.js), [Examples](https://observablehq.com/@d3/d3-cumsum)
+
+Returns the cumulative sum of the given *iterable* of numbers, as a Float64Array of the same length. If the iterable contains no numbers, returns zeros. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the cumulative sum. This method ignores undefined and NaN values; this is useful for ignoring missing data.
+
+# d3.quantile(iterable, p[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/quantile.js), [Examples](https://observablehq.com/@d3/d3-mean-d3-median-and-friends)
+
+Returns the *p*-quantile of the given *iterable* of numbers, where *p* is a number in the range [0, 1]. For example, the median can be computed using *p* = 0.5, the first quartile at *p* = 0.25, and the third quartile at *p* = 0.75. This particular implementation uses the [R-7 method](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population), which is the default for the R programming language and Excel. For example:
+
+```js
+var a = [0, 10, 30];
+d3.quantile(a, 0); // 0
+d3.quantile(a, 0.5); // 10
+d3.quantile(a, 1); // 30
+d3.quantile(a, 0.25); // 5
+d3.quantile(a, 0.75); // 20
+d3.quantile(a, 0.1); // 2
+```
+
+An optional *accessor* function may be specified, which is equivalent to calling *array*.map(*accessor*) before computing the quantile.
+
+# d3.quantileIndex(array, p[, accessor]) [Source](https://github.com/d3/d3-array/blob/main/src/quantile.js "Source")
+
+Similar to *quantile*, but returns the index to the left of *p*.
+
+# d3.quantileSorted(array, p[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/quantile.js), [Examples](https://observablehq.com/@d3/d3-mean-d3-median-and-friends)
+
+Similar to *quantile*, but expects the input to be a **sorted** *array* of values. In contrast with *quantile*, the accessor is only called on the elements needed to compute the quantile.
+
+# d3.rank(iterable[, comparator]) · [Source](https://github.com/d3/d3-array/blob/main/src/rank.js), [Examples](https://observablehq.com/@d3/rank)
+ # d3.rank(iterable[, accessor])
+
+Returns an array with the rank of each value in the *iterable*, *i.e.* the zero-based index of the value when the iterable is sorted. Nullish values are sorted to the end and ranked NaN. An optional *comparator* or *accessor* function may be specified; the latter is equivalent to calling *array*.map(*accessor*) before computing the ranks. If *comparator* is not specified, it defaults to [ascending](#ascending). Ties (equivalent values) all get the same rank, defined as the first time the value is found.
+
+```js
+d3.rank([{x: 1}, {}, {x: 2}, {x: 0}], d => d.x); // [1, NaN, 2, 0]
+d3.rank(["b", "c", "b", "a"]); // [1, 3, 1, 0]
+d3.rank([1, 2, 3], d3.descending); // [2, 1, 0]
+```
+
+# d3.variance(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/variance.js), [Examples](https://observablehq.com/@d3/d3-mean-d3-median-and-friends)
+
+Returns an [unbiased estimator of the population variance](http://mathworld.wolfram.com/SampleVariance.html) of the given *iterable* of numbers using [Welford’s algorithm](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm). If the iterable has fewer than two numbers, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the variance. This method ignores undefined and NaN values; this is useful for ignoring missing data.
+
+# d3.deviation(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/deviation.js), [Examples](https://observablehq.com/@d3/d3-mean-d3-median-and-friends)
+
+Returns the standard deviation, defined as the square root of the [bias-corrected variance](#variance), of the given *iterable* of numbers. If the iterable has fewer than two numbers, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the standard deviation. This method ignores undefined and NaN values; this is useful for ignoring missing data.
+
+# d3.fsum([values][, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/fsum.js), [Examples](https://observablehq.com/@d3/d3-fsum)
+
+Returns a full precision summation of the given *values*.
+
+```js
+d3.fsum([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1]); // 1
+d3.sum([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1]); // 0.9999999999999999
+```
+
+Although slower, d3.fsum can replace d3.sum wherever greater precision is needed. Uses d3.Adder.
+
+# d3.fcumsum([values][, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/fsum.js), [Examples](https://observablehq.com/@d3/d3-fcumsum)
+
+Returns a full precision cumulative sum of the given *values*.
+
+```js
+d3.fcumsum([1, 1e-14, -1]); // [1, 1.00000000000001, 1e-14]
+d3.cumsum([1, 1e-14, -1]); // [1, 1.00000000000001, 9.992e-15]
+```
+
+Although slower, d3.fcumsum can replace d3.cumsum when greater precision is needed. Uses d3.Adder.
+
+# new d3.Adder()
+
+Creates a full precision adder for [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) floating point numbers, setting its initial value to 0.
+
+# *adder*.add(number)
+
+Adds the specified *number* to the adder’s current value and returns the adder.
+
+# *adder*.valueOf()
+
+Returns the IEEE 754 double precision representation of the adder’s current value. Most useful as the short-hand notation `+adder`.
+
+### Search
+
+Methods for searching arrays for a specific element.
+
+# d3.least(iterable[, comparator]) · [Source](https://github.com/d3/d3-array/blob/main/src/least.js), [Examples](https://observablehq.com/@d3/d3-least)
+ # d3.least(iterable[, accessor])
+
+Returns the least element of the specified *iterable* according to the specified *comparator* or *accessor*. If the given *iterable* contains no comparable elements (*i.e.*, the comparator returns NaN when comparing each element to itself), returns undefined. If *comparator* is not specified, it defaults to [ascending](#ascending). For example:
+
+```js
+const array = [{foo: 42}, {foo: 91}];
+d3.least(array, (a, b) => a.foo - b.foo); // {foo: 42}
+d3.least(array, (a, b) => b.foo - a.foo); // {foo: 91}
+d3.least(array, a => a.foo); // {foo: 42}
+```
+
+This function is similar to [min](#min), except it allows the use of a comparator rather than an accessor.
+
+# d3.leastIndex(iterable[, comparator]) · [Source](https://github.com/d3/d3-array/blob/main/src/leastIndex.js), [Examples](https://observablehq.com/@d3/d3-least)
+ # d3.leastIndex(iterable[, accessor])
+
+Returns the index of the least element of the specified *iterable* according to the specified *comparator* or *accessor*. If the given *iterable* contains no comparable elements (*i.e.*, the comparator returns NaN when comparing each element to itself), returns -1. If *comparator* is not specified, it defaults to [ascending](#ascending). For example:
+
+```js
+const array = [{foo: 42}, {foo: 91}];
+d3.leastIndex(array, (a, b) => a.foo - b.foo); // 0
+d3.leastIndex(array, (a, b) => b.foo - a.foo); // 1
+d3.leastIndex(array, a => a.foo); // 0
+```
+
+This function is similar to [minIndex](#minIndex), except it allows the use of a comparator rather than an accessor.
+
+# d3.greatest(iterable[, comparator]) · [Source](https://github.com/d3/d3-array/blob/main/src/greatest.js), [Examples](https://observablehq.com/@d3/d3-least)
+ # d3.greatest(iterable[, accessor])
+
+Returns the greatest element of the specified *iterable* according to the specified *comparator* or *accessor*. If the given *iterable* contains no comparable elements (*i.e.*, the comparator returns NaN when comparing each element to itself), returns undefined. If *comparator* is not specified, it defaults to [ascending](#ascending). For example:
+
+```js
+const array = [{foo: 42}, {foo: 91}];
+d3.greatest(array, (a, b) => a.foo - b.foo); // {foo: 91}
+d3.greatest(array, (a, b) => b.foo - a.foo); // {foo: 42}
+d3.greatest(array, a => a.foo); // {foo: 91}
+```
+
+This function is similar to [max](#max), except it allows the use of a comparator rather than an accessor.
+
+# d3.greatestIndex(iterable[, comparator]) · [Source](https://github.com/d3/d3-array/blob/main/src/greatestIndex.js), [Examples](https://observablehq.com/@d3/d3-least)
+ # d3.greatestIndex(iterable[, accessor])
+
+Returns the index of the greatest element of the specified *iterable* according to the specified *comparator* or *accessor*. If the given *iterable* contains no comparable elements (*i.e.*, the comparator returns NaN when comparing each element to itself), returns -1. If *comparator* is not specified, it defaults to [ascending](#ascending). For example:
+
+```js
+const array = [{foo: 42}, {foo: 91}];
+d3.greatestIndex(array, (a, b) => a.foo - b.foo); // 1
+d3.greatestIndex(array, (a, b) => b.foo - a.foo); // 0
+d3.greatestIndex(array, a => a.foo); // 1
+```
+
+This function is similar to [maxIndex](#maxIndex), except it allows the use of a comparator rather than an accessor.
+
+# d3.bisectLeft(array, x[, lo[, hi]]) · [Source](https://github.com/d3/d3-array/blob/main/src/bisect.js)
+
+Returns the insertion point for *x* in *array* to maintain sorted order. The arguments *lo* and *hi* may be used to specify a subset of the array which should be considered; by default the entire array is used. If *x* is already present in *array*, the insertion point will be before (to the left of) any existing entries. The return value is suitable for use as the first argument to [splice](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) assuming that *array* is already sorted. The returned insertion point *i* partitions the *array* into two halves so that all *v* < *x* for *v* in *array*.slice(*lo*, *i*) for the left side and all *v* >= *x* for *v* in *array*.slice(*i*, *hi*) for the right side.
+
+# d3.bisect(array, x[, lo[, hi]]) · [Source](https://github.com/d3/d3-array/blob/main/src/bisect.js), [Examples](https://observablehq.com/@d3/d3-bisect)
+ # d3.bisectRight(array, x[, lo[, hi]])
+
+Similar to [bisectLeft](#bisectLeft), but returns an insertion point which comes after (to the right of) any existing entries of *x* in *array*. The returned insertion point *i* partitions the *array* into two halves so that all *v* <= *x* for *v* in *array*.slice(*lo*, *i*) for the left side and all *v* > *x* for *v* in *array*.slice(*i*, *hi*) for the right side.
+
+# d3.bisectCenter(array, x[, lo[, hi]]) · [Source](https://github.com/d3/d3-array/blob/main/src/bisect.js), [Examples](https://observablehq.com/@d3/multi-line-chart)
+
+Returns the index of the value closest to *x* in the given *array* of numbers. The arguments *lo* (inclusive) and *hi* (exclusive) may be used to specify a subset of the array which should be considered; by default the entire array is used.
+
+See [*bisector*.center](#bisector_center).
+
+# d3.bisector(accessor) · [Source](https://github.com/d3/d3-array/blob/main/src/bisector.js)
+ # d3.bisector(comparator)
+
+Returns a new bisector using the specified *accessor* or *comparator* function. This method can be used to bisect arrays of objects instead of being limited to simple arrays of primitives. For example, given the following array of objects:
+
+```js
+var data = [
+ {date: new Date(2011, 1, 1), value: 0.5},
+ {date: new Date(2011, 2, 1), value: 0.6},
+ {date: new Date(2011, 3, 1), value: 0.7},
+ {date: new Date(2011, 4, 1), value: 0.8}
+];
+```
+
+A suitable bisect function could be constructed as:
+
+```js
+var bisectDate = d3.bisector(function(d) { return d.date; }).right;
+```
+
+This is equivalent to specifying a comparator:
+
+```js
+var bisectDate = d3.bisector(function(d, x) { return d.date - x; }).right;
+```
+
+And then applied as *bisectDate*(*array*, *date*), returning an index. Note that the comparator is always passed the search value *x* as the second argument. Use a comparator rather than an accessor if you want values to be sorted in an order different than natural order, such as in descending rather than ascending order.
+
+#bisector.left(array, x[, lo[, hi]]) · [Source](https://github.com/d3/d3-array/blob/main/src/bisector.js)
+
+Equivalent to [bisectLeft](#bisectLeft), but uses this bisector’s associated comparator.
+
+#bisector.right(array, x[, lo[, hi]]) · [Source](https://github.com/d3/d3-array/blob/main/src/bisector.js)
+
+Equivalent to [bisectRight](#bisectRight), but uses this bisector’s associated comparator.
+
+#bisector.center(array, x[, lo[, hi]]) · [Source](https://github.com/d3/d3-array/blob/main/src/bisector.js)
+
+Returns the index of the closest value to *x* in the given sorted *array*. This expects that the bisector’s associated accessor returns a quantitative value, or that the bisector’s associated comparator returns a signed distance; otherwise, this method is equivalent to *bisector*.left.
+
+# d3.quickselect(array, k, left = 0, right = array.length - 1, compare = ascending) · [Source](https://github.com/d3/d3-array/blob/main/src/quickselect.js), [Examples](https://observablehq.com/@d3/d3-quickselect)
+
+See [mourner/quickselect](https://github.com/mourner/quickselect/blob/master/README.md).
+
+# d3.ascending(a, b) · [Source](https://github.com/d3/d3-array/blob/main/src/ascending.js), [Examples](https://observablehq.com/@d3/d3-ascending)
+
+Returns -1 if *a* is less than *b*, or 1 if *a* is greater than *b*, or 0. This is the comparator function for natural order, and can be used in conjunction with the built-in [*array*.sort](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) method to arrange elements in ascending order. It is implemented as:
+
+```js
+function ascending(a, b) {
+ return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+}
+```
+
+Note that if no comparator function is specified to the built-in sort method, the default order is lexicographic (alphabetical), not natural! This can lead to surprising behavior when sorting an array of numbers.
+
+# d3.descending(a, b) · [Source](https://github.com/d3/d3-array/blob/main/src/descending.js), [Examples](https://observablehq.com/@d3/d3-ascending)
+
+Returns -1 if *a* is greater than *b*, or 1 if *a* is less than *b*, or 0. This is the comparator function for reverse natural order, and can be used in conjunction with the built-in array sort method to arrange elements in descending order. It is implemented as:
+
+```js
+function descending(a, b) {
+ return a == null || b == null ? NaN : b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+}
+```
+
+Note that if no comparator function is specified to the built-in sort method, the default order is lexicographic (alphabetical), not natural! This can lead to surprising behavior when sorting an array of numbers.
+
+### Transformations
+
+Methods for transforming arrays and for generating new arrays.
+
+# d3.group(iterable, ...keys) · [Source](https://github.com/d3/d3-array/blob/main/src/group.js), [Examples](https://observablehq.com/@d3/d3-group-d3-rollup)
+
+Groups the specified *iterable* of values into an [InternMap](#InternMap) from *key* to array of value. For example, given some data:
+
+```js
+data = [
+ {name: "jim", amount: "34.0", date: "11/12/2015"},
+ {name: "carl", amount: "120.11", date: "11/12/2015"},
+ {name: "stacy", amount: "12.01", date: "01/04/2016"},
+ {name: "stacy", amount: "34.05", date: "01/04/2016"}
+]
+```
+
+To group the data by name:
+
+```js
+d3.group(data, d => d.name)
+```
+
+This produces:
+
+```js
+Map(3) {
+ "jim" => Array(1)
+ "carl" => Array(1)
+ "stacy" => Array(2)
+}
+```
+
+If more than one *key* is specified, a nested InternMap is returned. For example:
+
+```js
+d3.group(data, d => d.name, d => d.date)
+```
+
+This produces:
+
+```js
+Map(3) {
+ "jim" => Map(1) {
+ "11/12/2015" => Array(1)
+ }
+ "carl" => Map(1) {
+ "11/12/2015" => Array(1)
+ }
+ "stacy" => Map(1) {
+ "01/04/2016" => Array(2)
+ }
+}
+```
+
+To convert a Map to an Array, use [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from). For example:
+
+```js
+Array.from(d3.group(data, d => d.name))
+```
+
+This produces:
+
+```js
+[
+ ["jim", Array(1)],
+ ["carl", Array(1)],
+ ["stacy", Array(2)]
+]
+```
+
+You can also simultaneously convert the [*key*, *value*] to some other representation by passing a map function to Array.from:
+
+```js
+Array.from(d3.group(data, d => d.name), ([key, value]) => ({key, value}))
+```
+
+This produces:
+
+```js
+[
+ {key: "jim", value: Array(1)},
+ {key: "carl", value: Array(1)},
+ {key: "stacy", value: Array(2)}
+]
+```
+
+[*selection*.data](https://github.com/d3/d3-selection/blob/main/README.md#selection_data) accepts iterables directly, meaning that you can use a Map (or Set or other iterable) to perform a data join without first needing to convert to an array.
+
+# d3.groups(iterable, ...keys) · [Source](https://github.com/d3/d3-array/blob/main/src/group.js), [Examples](https://observablehq.com/@d3/d3-group-d3-rollup)
+
+Equivalent to [group](#group), but returns nested arrays instead of nested maps.
+
+# d3.flatGroup(iterable, ...keys) · [Source](https://github.com/d3/d3-array/blob/main/src/group.js), [Examples](https://observablehq.com/@d3/d3-flatgroup)
+
+Equivalent to [group](#group), but returns a flat array of [*key0*, *key1*, …, *values*] instead of nested maps.
+
+# d3.index(iterable, ...keys) · [Source](https://github.com/d3/d3-array/blob/main/src/group.js), [Examples](https://observablehq.com/@d3/d3-group)
+
+Equivalent to [group](#group) but returns a unique value per compound key instead of an array, throwing if the key is not unique.
+
+For example, given the data defined above,
+
+```js
+d3.index(data, d => d.amount)
+```
+
+returns
+
+```js
+Map(4) {
+ "34.0" => Object {name: "jim", amount: "34.0", date: "11/12/2015"}
+ "120.11" => Object {name: "carl", amount: "120.11", date: "11/12/2015"}
+ "12.01" => Object {name: "stacy", amount: "12.01", date: "01/04/2016"}
+ "34.05" => Object {name: "stacy", amount: "34.05", date: "01/04/2016"}
+}
+```
+
+On the other hand,
+
+```js
+d3.index(data, d => d.name)
+```
+
+throws an error because two objects share the same name.
+
+# d3.indexes(iterable, ...keys) · [Source](https://github.com/d3/d3-array/blob/main/src/group.js), [Examples](https://observablehq.com/@d3/d3-group)
+
+Equivalent to [index](#index), but returns nested arrays instead of nested maps.
+
+# d3.rollup(iterable, reduce, ...keys) · [Source](https://github.com/d3/d3-array/blob/main/src/group.js), [Examples](https://observablehq.com/@d3/d3-group-d3-rollup)
+
+[Groups](#group) and reduces the specified *iterable* of values into an InternMap from *key* to value. For example, given some data:
+
+```js
+data = [
+ {name: "jim", amount: "34.0", date: "11/12/2015"},
+ {name: "carl", amount: "120.11", date: "11/12/2015"},
+ {name: "stacy", amount: "12.01", date: "01/04/2016"},
+ {name: "stacy", amount: "34.05", date: "01/04/2016"}
+]
+```
+
+To count the number of elements by name:
+
+```js
+d3.rollup(data, v => v.length, d => d.name)
+```
+
+This produces:
+
+```js
+Map(3) {
+ "jim" => 1
+ "carl" => 1
+ "stacy" => 2
+}
+```
+
+If more than one *key* is specified, a nested Map is returned. For example:
+
+```js
+d3.rollup(data, v => v.length, d => d.name, d => d.date)
+```
+
+This produces:
+
+```js
+Map(3) {
+ "jim" => Map(1) {
+ "11/12/2015" => 1
+ }
+ "carl" => Map(1) {
+ "11/12/2015" => 1
+ }
+ "stacy" => Map(1) {
+ "01/04/2016" => 2
+ }
+}
+```
+
+To convert a Map to an Array, use [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from). See [d3.group](#group) for examples.
+
+# d3.rollups(iterable, reduce, ...keys) · [Source](https://github.com/d3/d3-array/blob/main/src/group.js), [Examples](https://observablehq.com/@d3/d3-group-d3-rollup)
+
+Equivalent to [rollup](#rollup), but returns nested arrays instead of nested maps.
+
+# d3.flatRollup(iterable, reduce, ...keys) · [Source](https://github.com/d3/d3-array/blob/main/src/group.js), [Examples](https://observablehq.com/@d3/d3-flatgroup)
+
+Equivalent to [rollup](#rollup), but returns a flat array of [*key0*, *key1*, …, *value*] instead of nested maps.
+
+# d3.groupSort(iterable, comparator, key) · [Source](https://github.com/d3/d3-array/blob/main/src/groupSort.js), [Examples](https://observablehq.com/@d3/d3-groupsort)
+ # d3.groupSort(iterable, accessor, key)
+
+Groups the specified *iterable* of elements according to the specified *key* function, sorts the groups according to the specified *comparator*, and then returns an array of keys in sorted order. For example, if you had a table of barley yields for different varieties, sites, and years, to sort the barley varieties by ascending median yield:
+
+```js
+d3.groupSort(barley, g => d3.median(g, d => d.yield), d => d.variety)
+```
+
+For descending order, negate the group value:
+
+```js
+d3.groupSort(barley, g => -d3.median(g, d => d.yield), d => d.variety)
+```
+
+If a *comparator* is passed instead of an *accessor* (i.e., if the second argument is a function that takes exactly two arguments), it will be asked to compare two groups *a* and *b* and should return a negative value if *a* should be before *b*, a positive value if *a* should be after *b*, or zero for a partial ordering.
+
+# d3.count(iterable[, accessor]) · [Source](https://github.com/d3/d3-array/blob/main/src/count.js), [Examples](https://observablehq.com/@d3/d3-count)
+
+Returns the number of valid number values (*i.e.*, not null, NaN, or undefined) in the specified *iterable*; accepts an accessor.
+
+For example:
+
+```js
+d3.count([{n: "Alice", age: NaN}, {n: "Bob", age: 18}, {n: "Other"}], d => d.age) // 1
+```
+# d3.cross(...iterables[, reducer]) · [Source](https://github.com/d3/d3-array/blob/main/src/cross.js), [Examples](https://observablehq.com/@d3/d3-cross)
+
+Returns the [Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product) of the specified *iterables*. For example, if two iterables *a* and *b* are specified, for each element *i* in the iterable *a* and each element *j* in the iterable *b*, in order, invokes the specified *reducer* function passing the element *i* and element *j*. If a *reducer* is not specified, it defaults to a function which creates a two-element array for each pair:
+
+```js
+function pair(a, b) {
+ return [a, b];
+}
+```
+
+For example:
+
+```js
+d3.cross([1, 2], ["x", "y"]); // returns [[1, "x"], [1, "y"], [2, "x"], [2, "y"]]
+d3.cross([1, 2], ["x", "y"], (a, b) => a + b); // returns ["1x", "1y", "2x", "2y"]
+```
+
+# d3.merge(iterables) · [Source](https://github.com/d3/d3-array/blob/main/src/merge.js), [Examples](https://observablehq.com/@d3/d3-merge)
+
+Merges the specified iterable of *iterables* into a single array. This method is similar to the built-in array concat method; the only difference is that it is more convenient when you have an array of arrays.
+
+```js
+d3.merge([[1], [2, 3]]); // returns [1, 2, 3]
+```
+
+# d3.pairs(iterable[, reducer]) · [Source](https://github.com/d3/d3-array/blob/main/src/pairs.js), [Examples](https://observablehq.com/@d3/d3-pairs)
+
+For each adjacent pair of elements in the specified *iterable*, in order, invokes the specified *reducer* function passing the element *i* and element *i* - 1. If a *reducer* is not specified, it defaults to a function which creates a two-element array for each pair:
+
+```js
+function pair(a, b) {
+ return [a, b];
+}
+```
+
+For example:
+
+```js
+d3.pairs([1, 2, 3, 4]); // returns [[1, 2], [2, 3], [3, 4]]
+d3.pairs([1, 2, 3, 4], (a, b) => b - a); // returns [1, 1, 1];
+```
+
+If the specified iterable has fewer than two elements, returns the empty array.
+
+# d3.permute(source, keys) · [Source](https://github.com/d3/d3-array/blob/main/src/permute.js), [Examples](https://observablehq.com/@d3/d3-permute)
+
+Returns a permutation of the specified *source* object (or array) using the specified iterable of *keys*. The returned array contains the corresponding property of the source object for each key in *keys*, in order. For example:
+
+```js
+permute(["a", "b", "c"], [1, 2, 0]); // returns ["b", "c", "a"]
+```
+
+It is acceptable to have more keys than source elements, and for keys to be duplicated or omitted.
+
+This method can also be used to extract the values from an object into an array with a stable order. Extracting keyed values in order can be useful for generating data arrays in nested selections. For example:
+
+```js
+let object = {yield: 27, variety: "Manchuria", year: 1931, site: "University Farm"};
+let fields = ["site", "variety", "yield"];
+
+d3.permute(object, fields); // returns ["University Farm", "Manchuria", 27]
+```
+
+# d3.shuffle(array[, start[, stop]]) · [Source](https://github.com/d3/d3-array/blob/main/src/shuffle.js), [Examples](https://observablehq.com/@d3/d3-shuffle)
+
+Randomizes the order of the specified *array* in-place using the [Fisher–Yates shuffle](https://bost.ocks.org/mike/shuffle/) and returns the *array*. If *start* is specified, it is the starting index (inclusive) of the *array* to shuffle; if *start* is not specified, it defaults to zero. If *stop* is specified, it is the ending index (exclusive) of the *array* to shuffle; if *stop* is not specified, it defaults to *array*.length. For example, to shuffle the first ten elements of the *array*: shuffle(*array*, 0, 10).
+
+# d3.shuffler(random) · [Source](https://github.com/d3/d3-array/blob/main/src/shuffle.js)
+
+Returns a [shuffle function](#shuffle) given the specified random source. For example, using [d3.randomLcg](https://github.com/d3/d3-random/blob/main/README.md#randomLcg):
+
+```js
+const random = d3.randomLcg(0.9051667019185816);
+const shuffle = d3.shuffler(random);
+
+shuffle([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); // returns [7, 4, 5, 3, 9, 0, 6, 1, 2, 8]
+```
+
+# d3.ticks(start, stop, count) · [Source](https://github.com/d3/d3-array/blob/main/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks)
+
+Returns an array of approximately *count* + 1 uniformly-spaced, nicely-rounded values between *start* and *stop* (inclusive). Each value is a power of ten multiplied by 1, 2 or 5. See also [d3.tickIncrement](#tickIncrement), [d3.tickStep](#tickStep) and [*linear*.ticks](https://github.com/d3/d3-scale/blob/main/README.md#linear_ticks).
+
+Ticks are inclusive in the sense that they may include the specified *start* and *stop* values if (and only if) they are exact, nicely-rounded values consistent with the inferred [step](#tickStep). More formally, each returned tick *t* satisfies *start* ≤ *t* and *t* ≤ *stop*.
+
+# d3.tickIncrement(start, stop, count) · [Source](https://github.com/d3/d3-array/blob/main/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks)
+
+Like [d3.tickStep](#tickStep), except requires that *start* is always less than or equal to *stop*, and if the tick step for the given *start*, *stop* and *count* would be less than one, returns the negative inverse tick step instead. This method is always guaranteed to return an integer, and is used by [d3.ticks](#ticks) to guarantee that the returned tick values are represented as precisely as possible in IEEE 754 floating point.
+
+# d3.tickStep(start, stop, count) · [Source](https://github.com/d3/d3-array/blob/main/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks)
+
+Returns the difference between adjacent tick values if the same arguments were passed to [d3.ticks](#ticks): a nicely-rounded value that is a power of ten multiplied by 1, 2 or 5. Note that due to the limited precision of IEEE 754 floating point, the returned value may not be exact decimals; use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption.
+
+# d3.nice(start, stop, count) · [Source](https://github.com/d3/d3-array/blob/main/src/nice.js)
+
+Returns a new interval [*niceStart*, *niceStop*] covering the given interval [*start*, *stop*] and where *niceStart* and *niceStop* are guaranteed to align with the corresponding [tick step](#tickStep). Like [d3.tickIncrement](#tickIncrement), this requires that *start* is less than or equal to *stop*.
+
+# d3.range([start, ]stop[, step]) · [Source](https://github.com/d3/d3-array/blob/main/src/range.js), [Examples](https://observablehq.com/@d3/d3-range)
+
+Returns an array containing an arithmetic progression, similar to the Python built-in [range](http://docs.python.org/library/functions.html#range). This method is often used to iterate over a sequence of uniformly-spaced numeric values, such as the indexes of an array or the ticks of a linear scale. (See also [d3.ticks](#ticks) for nicely-rounded values.)
+
+If *step* is omitted, it defaults to 1. If *start* is omitted, it defaults to 0. The *stop* value is exclusive; it is not included in the result. If *step* is positive, the last element is the largest *start* + *i* \* *step* less than *stop*; if *step* is negative, the last element is the smallest *start* + *i* \* *step* greater than *stop*. If the returned array would contain an infinite number of values, an empty range is returned.
+
+The arguments are not required to be integers; however, the results are more predictable if they are. The values in the returned array are defined as *start* + *i* \* *step*, where *i* is an integer from zero to one minus the total number of elements in the returned array. For example:
+
+```js
+d3.range(0, 1, 0.2) // [0, 0.2, 0.4, 0.6000000000000001, 0.8]
+```
+
+This unexpected behavior is due to IEEE 754 double-precision floating point, which defines 0.2 * 3 = 0.6000000000000001. Use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption with appropriate rounding; see also [linear.tickFormat](https://github.com/d3/d3-scale/blob/main/README.md#linear_tickFormat) in [d3-scale](https://github.com/d3/d3-scale).
+
+Likewise, if the returned array should have a specific length, consider using [array.map](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on an integer range. For example:
+
+```js
+d3.range(0, 1, 1 / 49); // BAD: returns 50 elements!
+d3.range(49).map(function(d) { return d / 49; }); // GOOD: returns 49 elements.
+```
+
+# d3.transpose(matrix) · [Source](https://github.com/d3/d3-array/blob/main/src/transpose.js), [Examples](https://observablehq.com/@d3/d3-transpose)
+
+Uses the [zip](#zip) operator as a two-dimensional [matrix transpose](http://en.wikipedia.org/wiki/Transpose).
+
+# d3.zip(arrays…) · [Source](https://github.com/d3/d3-array/blob/main/src/zip.js), [Examples](https://observablehq.com/@d3/d3-transpose)
+
+Returns an array of arrays, where the *i*th array contains the *i*th element from each of the argument *arrays*. The returned array is truncated in length to the shortest array in *arrays*. If *arrays* contains only a single array, the returned array contains one-element arrays. With no arguments, the returned array is empty.
+
+```js
+d3.zip([1, 2], [3, 4]); // returns [[1, 3], [2, 4]]
+```
+
+#### Blur
+
+# d3.blur(*data*, *radius*) · [Source](https://github.com/d3/d3-array/blob/main/src/blur.js), [Examples](https://observablehq.com/@d3/d3-blur)
+
+Blurs an array of *data* in-place by applying three iterations of a moving average transform, for a fast approximation of a gaussian kernel of the given *radius*, a non-negative number, and returns the array.
+
+```js
+const randomWalk = d3.cumsum({length: 1000}, () => Math.random() - 0.5);
+blur(randomWalk, 5);
+```
+
+Copy the data if you don’t want to smooth it in-place:
+```js
+const smoothed = blur(randomWalk.slice(), 5);
+```
+
+# d3.blur2({*data*, *width*[, *height*]}, *rx*[, *ry*]) · [Source](https://github.com/d3/d3-array/blob/main/src/blur.js), [Examples](https://observablehq.com/@d3/d3-blur)
+
+Blurs a matrix of the given *width* and *height* in-place, by applying an horizontal blur of radius *rx* and a vertical blur or radius *ry* (which defaults to *rx*). The matrix *data* is stored in a flat array, used to determine the *height* if it is not specified. Returns the blurred {data, width, height}.
+
+```js
+data = [
+ 1, 0, 0,
+ 0, 0, 0,
+ 0, 0, 1
+];
+blur2({data, width: 3}, 1);
+```
+
+# d3.blurImage(*imageData*, *rx*[, *ry*]) · [Source](https://github.com/d3/d3-array/blob/main/src/blur.js), [Examples](https://observablehq.com/@d3/d3-blurimage)
+
+Blurs an [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) structure in-place, blurring each of the RGBA layers independently by applying an horizontal blur of radius *rx* and a vertical blur or radius *ry* (which defaults to *rx*). Returns the blurred ImageData.
+
+```js
+const imData = context.getImageData(0, 0, width, height);
+blurImage(imData, 5);
+```
+
+### Iterables
+
+These are equivalent to built-in array methods, but work with any iterable including Map, Set, and Generator.
+
+# d3.every(iterable, test) · [Source](https://github.com/d3/d3-array/blob/main/src/every.js)
+
+Returns true if the given *test* function returns true for every value in the given *iterable*. This method returns as soon as *test* returns a non-truthy value or all values are iterated over. Equivalent to [*array*.every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every):
+
+```js
+d3.every(new Set([1, 3, 5, 7]), x => x & 1) // true
+```
+
+# d3.some(iterable, test) · [Source](https://github.com/d3/d3-array/blob/main/src/some.js)
+
+Returns true if the given *test* function returns true for any value in the given *iterable*. This method returns as soon as *test* returns a truthy value or all values are iterated over. Equivalent to [*array*.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some):
+
+```js
+d3.some(new Set([0, 2, 3, 4]), x => x & 1) // true
+```
+
+# d3.filter(iterable, test) · [Source](https://github.com/d3/d3-array/blob/main/src/filter.js)
+
+Returns a new array containing the values from *iterable*, in order, for which the given *test* function returns true. Equivalent to [*array*.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter):
+
+```js
+d3.filter(new Set([0, 2, 3, 4]), x => x & 1) // [3]
+```
+
+# d3.map(iterable, mapper) · [Source](https://github.com/d3/d3-array/blob/main/src/map.js)
+
+Returns a new array containing the mapped values from *iterable*, in order, as defined by given *mapper* function. Equivalent to [*array*.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from):
+
+```js
+d3.map(new Set([0, 2, 3, 4]), x => x & 1) // [0, 0, 1, 0]
+```
+
+# d3.reduce(iterable, reducer[, initialValue]) · [Source](https://github.com/d3/d3-array/blob/main/src/reduce.js)
+
+Returns the reduced value defined by given *reducer* function, which is repeatedly invoked for each value in *iterable*, being passed the current reduced value and the next value. Equivalent to [*array*.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce):
+
+```js
+d3.reduce(new Set([0, 2, 3, 4]), (p, v) => p + v, 0) // 9
+```
+
+# d3.reverse(iterable) · [Source](https://github.com/d3/d3-array/blob/main/src/reverse.js)
+
+Returns an array containing the values in the given *iterable* in reverse order. Equivalent to [*array*.reverse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse), except that it does not mutate the given *iterable*:
+
+```js
+d3.reverse(new Set([0, 2, 3, 1])) // [1, 3, 2, 0]
+```
+
+# d3.sort(iterable, comparator = d3.ascending) · [Source](https://github.com/d3/d3-array/blob/main/src/sort.js)
+ # d3.sort(iterable, ...accessors)
+
+Returns an array containing the values in the given *iterable* in the sorted order defined by the given *comparator* or *accessor* function. If *comparator* is not specified, it defaults to [d3.ascending](#ascending). Equivalent to [*array*.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), except that it does not mutate the given *iterable*, and the comparator defaults to natural order instead of lexicographic order:
+
+```js
+d3.sort(new Set([0, 2, 3, 1])) // [0, 1, 2, 3]
+```
+
+If an *accessor* (a function that does not take exactly two arguments) is specified,
+
+```js
+d3.sort(data, d => d.value)
+```
+
+it is equivalent to a *comparator* using [natural order](#ascending):
+
+```js
+d3.sort(data, (a, b) => d3.ascending(a.value, b.value))
+```
+
+The *accessor* is only invoked once per element, and thus the returned sorted order is consistent even if the accessor is nondeterministic.
+
+Multiple accessors may be specified to break ties:
+
+```js
+d3.sort(points, ({x}) => x, ({y}) => y)
+```
+
+This is equivalent to:
+
+```js
+d3.sort(data, (a, b) => d3.ascending(a.x, b.x) || d3.ascending(a.y, b.y))
+```
+
+### Sets
+
+This methods implement basic set operations for any iterable.
+
+# d3.difference(iterable, ...others) · [Source](https://github.com/d3/d3-array/blob/main/src/difference.js)
+
+Returns a new InternSet containing every value in *iterable* that is not in any of the *others* iterables.
+
+```js
+d3.difference([0, 1, 2, 0], [1]) // Set {0, 2}
+```
+
+# d3.union(...iterables) · [Source](https://github.com/d3/d3-array/blob/main/src/union.js)
+
+Returns a new InternSet containing every (distinct) value that appears in any of the given *iterables*. The order of values in the returned set is based on their first occurrence in the given *iterables*.
+
+```js
+d3.union([0, 2, 1, 0], [1, 3]) // Set {0, 2, 1, 3}
+```
+
+# d3.intersection(...iterables) · [Source](https://github.com/d3/d3-array/blob/main/src/intersection.js)
+
+Returns a new InternSet containing every (distinct) value that appears in all of the given *iterables*. The order of values in the returned set is based on their first occurrence in the given *iterables*.
+
+```js
+d3.intersection([0, 2, 1, 0], [1, 3]) // Set {1}
+```
+
+# d3.superset(a, b) · [Source](https://github.com/d3/d3-array/blob/main/src/superset.js)
+
+Returns true if *a* is a superset of *b*: if every value in the given iterable *b* is also in the given iterable *a*.
+
+```js
+d3.superset([0, 2, 1, 3, 0], [1, 3]) // true
+```
+
+# d3.subset(a, b) · [Source](https://github.com/d3/d3-array/blob/main/src/subset.js)
+
+Returns true if *a* is a subset of *b*: if every value in the given iterable *a* is also in the given iterable *b*.
+
+```js
+d3.subset([1, 3], [0, 2, 1, 3, 0]) // true
+```
+
+# d3.disjoint(a, b) · [Source](https://github.com/d3/d3-array/blob/main/src/disjoint.js)
+
+Returns true if *a* and *b* are disjoint: if *a* and *b* contain no shared value.
+
+```js
+d3.disjoint([1, 3], [2, 4]) // true
+```
+
+### Bins
+
+[](http://bl.ocks.org/mbostock/3048450)
+
+Binning groups discrete samples into a smaller number of consecutive, non-overlapping intervals. They are often used to visualize the distribution of numerical data as histograms.
+
+# d3.bin() · [Source](https://github.com/d3/d3-array/blob/main/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+Constructs a new bin generator with the default settings.
+
+#bin(data) · [Source](https://github.com/d3/d3-array/blob/main/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+Bins the given iterable of *data* samples. Returns an array of bins, where each bin is an array containing the associated elements from the input *data*. Thus, the `length` of the bin is the number of elements in that bin. Each bin has two additional attributes:
+
+* `x0` - the lower bound of the bin (inclusive).
+* `x1` - the upper bound of the bin (exclusive, except for the last bin).
+
+Any null or non-comparable values in the given *data*, or those outside the [domain](#bin_domain), are ignored.
+
+#bin.value([value]) · [Source](https://github.com/d3/d3-array/blob/main/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+If *value* is specified, sets the value accessor to the specified function or constant and returns this bin generator. If *value* is not specified, returns the current value accessor, which defaults to the identity function.
+
+When bins are [generated](#_bin), the value accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default value accessor assumes that the input data are orderable (comparable), such as numbers or dates. If your data are not, then you should specify an accessor that returns the corresponding orderable value for a given datum.
+
+This is similar to mapping your data to values before invoking the bin generator, but has the benefit that the input data remains associated with the returned bins, thereby making it easier to access other fields of the data.
+
+#bin.domain([domain]) · [Source](https://github.com/d3/d3-array/blob/main/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+If *domain* is specified, sets the domain accessor to the specified function or array and returns this bin generator. If *domain* is not specified, returns the current domain accessor, which defaults to [extent](#extent). The bin domain is defined as an array [*min*, *max*], where *min* is the minimum observable value and *max* is the maximum observable value; both values are inclusive. Any value outside of this domain will be ignored when the bins are [generated](#_bin).
+
+For example, if you are using the bin generator in conjunction with a [linear scale](https://github.com/d3/d3-scale/blob/main/README.md#linear-scales) `x`, you might say:
+
+```js
+var bin = d3.bin()
+ .domain(x.domain())
+ .thresholds(x.ticks(20));
+```
+
+You can then compute the bins from an array of numbers like so:
+
+```js
+var bins = bin(numbers);
+```
+
+If the default [extent](#extent) domain is used and the [thresholds](#bin_thresholds) are specified as a count (rather than explicit values), then the computed domain will be [niced](#nice) such that all bins are uniform width.
+
+Note that the domain accessor is invoked on the materialized array of [values](#bin_value), not on the input data array.
+
+#bin.thresholds([count]) · [Source](https://github.com/d3/d3-array/blob/main/src/bin.js), [Examples](https://observablehq.com/@d3/d3-bin)
+ #bin.thresholds([thresholds])
+
+If *thresholds* is specified, sets the [threshold generator](#bin-thresholds) to the specified function or array and returns this bin generator. If *thresholds* is not specified, returns the current threshold generator, which by default implements [Sturges’ formula](#thresholdSturges). (Thus by default, the values to be binned must be numbers!) Thresholds are defined as an array of values [*x0*, *x1*, …]. Any value less than *x0* will be placed in the first bin; any value greater than or equal to *x0* but less than *x1* will be placed in the second bin; and so on. Thus, the [generated bins](#_bin) will have *thresholds*.length + 1 bins. See [bin thresholds](#bin-thresholds) for more information.
+
+Any threshold values outside the [domain](#bin_domain) are ignored. The first *bin*.x0 is always equal to the minimum domain value, and the last *bin*.x1 is always equal to the maximum domain value.
+
+If a *count* is specified instead of an array of *thresholds*, then the [domain](#bin_domain) will be uniformly divided into approximately *count* bins; see [ticks](#ticks).
+
+#### Bin Thresholds
+
+These functions are typically not used directly; instead, pass them to [*bin*.thresholds](#bin_thresholds).
+
+# d3.thresholdFreedmanDiaconis(values, min, max) · [Source](https://github.com/d3/d3-array/blob/main/src/threshold/freedmanDiaconis.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+Returns the number of bins according to the [Freedman–Diaconis rule](https://en.wikipedia.org/wiki/Histogram#Mathematical_definition); the input *values* must be numbers.
+
+# d3.thresholdScott(values, min, max) · [Source](https://github.com/d3/d3-array/blob/main/src/threshold/scott.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+Returns the number of bins according to [Scott’s normal reference rule](https://en.wikipedia.org/wiki/Histogram#Mathematical_definition); the input *values* must be numbers.
+
+# d3.thresholdSturges(values) · [Source](https://github.com/d3/d3-array/blob/main/src/threshold/sturges.js), [Examples](https://observablehq.com/@d3/d3-bin)
+
+Returns the number of bins according to [Sturges’ formula](https://en.wikipedia.org/wiki/Histogram#Mathematical_definition); the input *values* must be numbers.
+
+You may also implement your own threshold generator taking three arguments: the array of input [*values*](#bin_value) derived from the data, and the [observable domain](#bin_domain) represented as *min* and *max*. The generator may then return either the array of numeric thresholds or the *count* of bins; in the latter case the domain is divided uniformly into approximately *count* bins; see [ticks](#ticks).
+
+For instance, when binning date values, you might want to use the ticks from a time scale ([Example](https://observablehq.com/@d3/d3-bin-time-thresholds)).
+
+### Interning
+
+# new d3.InternMap([iterable][, key]) · [Source](https://github.com/mbostock/internmap/blob/main/src/index.js), [Examples](https://observablehq.com/d/d4c5f6ad343866b9)
+ # new d3.InternSet([iterable][, key]) · [Source](https://github.com/mbostock/internmap/blob/main/src/index.js), [Examples](https://observablehq.com/d/d4c5f6ad343866b9)
+
+The [InternMap and InternSet](https://github.com/mbostock/internmap) classes extend the native JavaScript Map and Set classes, respectively, allowing Dates and other non-primitive keys by bypassing the [SameValueZero algorithm](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness) when determining key equality. d3.group, d3.rollup and d3.index use an InternMap rather than a native Map. These two classes are exported for convenience.
diff --git a/node_modules/d3-array/dist/d3-array.js b/node_modules/d3-array/dist/d3-array.js
new file mode 100644
index 000000000..0644ded59
--- /dev/null
+++ b/node_modules/d3-array/dist/d3-array.js
@@ -0,0 +1,1455 @@
+// https://d3js.org/d3-array/ v3.2.4 Copyright 2010-2023 Mike Bostock
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+typeof define === 'function' && define.amd ? define(['exports'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}));
+})(this, (function (exports) { 'use strict';
+
+function ascending(a, b) {
+ return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+}
+
+function descending(a, b) {
+ return a == null || b == null ? NaN
+ : b < a ? -1
+ : b > a ? 1
+ : b >= a ? 0
+ : NaN;
+}
+
+function bisector(f) {
+ let compare1, compare2, delta;
+
+ // If an accessor is specified, promote it to a comparator. In this case we
+ // can test whether the search value is (self-) comparable. We can’t do this
+ // for a comparator (except for specific, known comparators) because we can’t
+ // tell if the comparator is symmetric, and an asymmetric comparator can’t be
+ // used to test whether a single value is comparable.
+ if (f.length !== 2) {
+ compare1 = ascending;
+ compare2 = (d, x) => ascending(f(d), x);
+ delta = (d, x) => f(d) - x;
+ } else {
+ compare1 = f === ascending || f === descending ? f : zero;
+ compare2 = f;
+ delta = f;
+ }
+
+ function left(a, x, lo = 0, hi = a.length) {
+ if (lo < hi) {
+ if (compare1(x, x) !== 0) return hi;
+ do {
+ const mid = (lo + hi) >>> 1;
+ if (compare2(a[mid], x) < 0) lo = mid + 1;
+ else hi = mid;
+ } while (lo < hi);
+ }
+ return lo;
+ }
+
+ function right(a, x, lo = 0, hi = a.length) {
+ if (lo < hi) {
+ if (compare1(x, x) !== 0) return hi;
+ do {
+ const mid = (lo + hi) >>> 1;
+ if (compare2(a[mid], x) <= 0) lo = mid + 1;
+ else hi = mid;
+ } while (lo < hi);
+ }
+ return lo;
+ }
+
+ function center(a, x, lo = 0, hi = a.length) {
+ const i = left(a, x, lo, hi - 1);
+ return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
+ }
+
+ return {left, center, right};
+}
+
+function zero() {
+ return 0;
+}
+
+function number(x) {
+ return x === null ? NaN : +x;
+}
+
+function* numbers(values, valueof) {
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && (value = +value) >= value) {
+ yield value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+ yield value;
+ }
+ }
+ }
+}
+
+const ascendingBisect = bisector(ascending);
+const bisectRight = ascendingBisect.right;
+const bisectLeft = ascendingBisect.left;
+const bisectCenter = bisector(number).center;
+var bisect = bisectRight;
+
+function blur(values, r) {
+ if (!((r = +r) >= 0)) throw new RangeError("invalid r");
+ let length = values.length;
+ if (!((length = Math.floor(length)) >= 0)) throw new RangeError("invalid length");
+ if (!length || !r) return values;
+ const blur = blurf(r);
+ const temp = values.slice();
+ blur(values, temp, 0, length, 1);
+ blur(temp, values, 0, length, 1);
+ blur(values, temp, 0, length, 1);
+ return values;
+}
+
+const blur2 = Blur2(blurf);
+
+const blurImage = Blur2(blurfImage);
+
+function Blur2(blur) {
+ return function(data, rx, ry = rx) {
+ if (!((rx = +rx) >= 0)) throw new RangeError("invalid rx");
+ if (!((ry = +ry) >= 0)) throw new RangeError("invalid ry");
+ let {data: values, width, height} = data;
+ if (!((width = Math.floor(width)) >= 0)) throw new RangeError("invalid width");
+ if (!((height = Math.floor(height !== undefined ? height : values.length / width)) >= 0)) throw new RangeError("invalid height");
+ if (!width || !height || (!rx && !ry)) return data;
+ const blurx = rx && blur(rx);
+ const blury = ry && blur(ry);
+ const temp = values.slice();
+ if (blurx && blury) {
+ blurh(blurx, temp, values, width, height);
+ blurh(blurx, values, temp, width, height);
+ blurh(blurx, temp, values, width, height);
+ blurv(blury, values, temp, width, height);
+ blurv(blury, temp, values, width, height);
+ blurv(blury, values, temp, width, height);
+ } else if (blurx) {
+ blurh(blurx, values, temp, width, height);
+ blurh(blurx, temp, values, width, height);
+ blurh(blurx, values, temp, width, height);
+ } else if (blury) {
+ blurv(blury, values, temp, width, height);
+ blurv(blury, temp, values, width, height);
+ blurv(blury, values, temp, width, height);
+ }
+ return data;
+ };
+}
+
+function blurh(blur, T, S, w, h) {
+ for (let y = 0, n = w * h; y < n;) {
+ blur(T, S, y, y += w, 1);
+ }
+}
+
+function blurv(blur, T, S, w, h) {
+ for (let x = 0, n = w * h; x < w; ++x) {
+ blur(T, S, x, x + n, w);
+ }
+}
+
+function blurfImage(radius) {
+ const blur = blurf(radius);
+ return (T, S, start, stop, step) => {
+ start <<= 2, stop <<= 2, step <<= 2;
+ blur(T, S, start + 0, stop + 0, step);
+ blur(T, S, start + 1, stop + 1, step);
+ blur(T, S, start + 2, stop + 2, step);
+ blur(T, S, start + 3, stop + 3, step);
+ };
+}
+
+// Given a target array T, a source array S, sets each value T[i] to the average
+// of {S[i - r], …, S[i], …, S[i + r]}, where r = ⌊radius⌋, start <= i < stop,
+// for each i, i + step, i + 2 * step, etc., and where S[j] is clamped between
+// S[start] (inclusive) and S[stop] (exclusive). If the given radius is not an
+// integer, S[i - r - 1] and S[i + r + 1] are added to the sum, each weighted
+// according to r - ⌊radius⌋.
+function blurf(radius) {
+ const radius0 = Math.floor(radius);
+ if (radius0 === radius) return bluri(radius);
+ const t = radius - radius0;
+ const w = 2 * radius + 1;
+ return (T, S, start, stop, step) => { // stop must be aligned!
+ if (!((stop -= step) >= start)) return; // inclusive stop
+ let sum = radius0 * S[start];
+ const s0 = step * radius0;
+ const s1 = s0 + step;
+ for (let i = start, j = start + s0; i < j; i += step) {
+ sum += S[Math.min(stop, i)];
+ }
+ for (let i = start, j = stop; i <= j; i += step) {
+ sum += S[Math.min(stop, i + s0)];
+ T[i] = (sum + t * (S[Math.max(start, i - s1)] + S[Math.min(stop, i + s1)])) / w;
+ sum -= S[Math.max(start, i - s0)];
+ }
+ };
+}
+
+// Like blurf, but optimized for integer radius.
+function bluri(radius) {
+ const w = 2 * radius + 1;
+ return (T, S, start, stop, step) => { // stop must be aligned!
+ if (!((stop -= step) >= start)) return; // inclusive stop
+ let sum = radius * S[start];
+ const s = step * radius;
+ for (let i = start, j = start + s; i < j; i += step) {
+ sum += S[Math.min(stop, i)];
+ }
+ for (let i = start, j = stop; i <= j; i += step) {
+ sum += S[Math.min(stop, i + s)];
+ T[i] = sum / w;
+ sum -= S[Math.max(start, i - s)];
+ }
+ };
+}
+
+function count(values, valueof) {
+ let count = 0;
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && (value = +value) >= value) {
+ ++count;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+ ++count;
+ }
+ }
+ }
+ return count;
+}
+
+function length$1(array) {
+ return array.length | 0;
+}
+
+function empty(length) {
+ return !(length > 0);
+}
+
+function arrayify(values) {
+ return typeof values !== "object" || "length" in values ? values : Array.from(values);
+}
+
+function reducer(reduce) {
+ return values => reduce(...values);
+}
+
+function cross(...values) {
+ const reduce = typeof values[values.length - 1] === "function" && reducer(values.pop());
+ values = values.map(arrayify);
+ const lengths = values.map(length$1);
+ const j = values.length - 1;
+ const index = new Array(j + 1).fill(0);
+ const product = [];
+ if (j < 0 || lengths.some(empty)) return product;
+ while (true) {
+ product.push(index.map((j, i) => values[i][j]));
+ let i = j;
+ while (++index[i] === lengths[i]) {
+ if (i === 0) return reduce ? product.map(reduce) : product;
+ index[i--] = 0;
+ }
+ }
+}
+
+function cumsum(values, valueof) {
+ var sum = 0, index = 0;
+ return Float64Array.from(values, valueof === undefined
+ ? v => (sum += +v || 0)
+ : v => (sum += +valueof(v, index++, values) || 0));
+}
+
+function variance(values, valueof) {
+ let count = 0;
+ let delta;
+ let mean = 0;
+ let sum = 0;
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && (value = +value) >= value) {
+ delta = value - mean;
+ mean += delta / ++count;
+ sum += delta * (value - mean);
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+ delta = value - mean;
+ mean += delta / ++count;
+ sum += delta * (value - mean);
+ }
+ }
+ }
+ if (count > 1) return sum / (count - 1);
+}
+
+function deviation(values, valueof) {
+ const v = variance(values, valueof);
+ return v ? Math.sqrt(v) : v;
+}
+
+function extent(values, valueof) {
+ let min;
+ let max;
+ if (valueof === undefined) {
+ for (const value of values) {
+ if (value != null) {
+ if (min === undefined) {
+ if (value >= value) min = max = value;
+ } else {
+ if (min > value) min = value;
+ if (max < value) max = value;
+ }
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null) {
+ if (min === undefined) {
+ if (value >= value) min = max = value;
+ } else {
+ if (min > value) min = value;
+ if (max < value) max = value;
+ }
+ }
+ }
+ }
+ return [min, max];
+}
+
+// https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
+class Adder {
+ constructor() {
+ this._partials = new Float64Array(32);
+ this._n = 0;
+ }
+ add(x) {
+ const p = this._partials;
+ let i = 0;
+ for (let j = 0; j < this._n && j < 32; j++) {
+ const y = p[j],
+ hi = x + y,
+ lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
+ if (lo) p[i++] = lo;
+ x = hi;
+ }
+ p[i] = x;
+ this._n = i + 1;
+ return this;
+ }
+ valueOf() {
+ const p = this._partials;
+ let n = this._n, x, y, lo, hi = 0;
+ if (n > 0) {
+ hi = p[--n];
+ while (n > 0) {
+ x = hi;
+ y = p[--n];
+ hi = x + y;
+ lo = y - (hi - x);
+ if (lo) break;
+ }
+ if (n > 0 && ((lo < 0 && p[n - 1] < 0) || (lo > 0 && p[n - 1] > 0))) {
+ y = lo * 2;
+ x = hi + y;
+ if (y == x - hi) hi = x;
+ }
+ }
+ return hi;
+ }
+}
+
+function fsum(values, valueof) {
+ const adder = new Adder();
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value = +value) {
+ adder.add(value);
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if (value = +valueof(value, ++index, values)) {
+ adder.add(value);
+ }
+ }
+ }
+ return +adder;
+}
+
+function fcumsum(values, valueof) {
+ const adder = new Adder();
+ let index = -1;
+ return Float64Array.from(values, valueof === undefined
+ ? v => adder.add(+v || 0)
+ : v => adder.add(+valueof(v, ++index, values) || 0)
+ );
+}
+
+class InternMap extends Map {
+ constructor(entries, key = keyof) {
+ super();
+ Object.defineProperties(this, {_intern: {value: new Map()}, _key: {value: key}});
+ if (entries != null) for (const [key, value] of entries) this.set(key, value);
+ }
+ get(key) {
+ return super.get(intern_get(this, key));
+ }
+ has(key) {
+ return super.has(intern_get(this, key));
+ }
+ set(key, value) {
+ return super.set(intern_set(this, key), value);
+ }
+ delete(key) {
+ return super.delete(intern_delete(this, key));
+ }
+}
+
+class InternSet extends Set {
+ constructor(values, key = keyof) {
+ super();
+ Object.defineProperties(this, {_intern: {value: new Map()}, _key: {value: key}});
+ if (values != null) for (const value of values) this.add(value);
+ }
+ has(value) {
+ return super.has(intern_get(this, value));
+ }
+ add(value) {
+ return super.add(intern_set(this, value));
+ }
+ delete(value) {
+ return super.delete(intern_delete(this, value));
+ }
+}
+
+function intern_get({_intern, _key}, value) {
+ const key = _key(value);
+ return _intern.has(key) ? _intern.get(key) : value;
+}
+
+function intern_set({_intern, _key}, value) {
+ const key = _key(value);
+ if (_intern.has(key)) return _intern.get(key);
+ _intern.set(key, value);
+ return value;
+}
+
+function intern_delete({_intern, _key}, value) {
+ const key = _key(value);
+ if (_intern.has(key)) {
+ value = _intern.get(key);
+ _intern.delete(key);
+ }
+ return value;
+}
+
+function keyof(value) {
+ return value !== null && typeof value === "object" ? value.valueOf() : value;
+}
+
+function identity(x) {
+ return x;
+}
+
+function group(values, ...keys) {
+ return nest(values, identity, identity, keys);
+}
+
+function groups(values, ...keys) {
+ return nest(values, Array.from, identity, keys);
+}
+
+function flatten$1(groups, keys) {
+ for (let i = 1, n = keys.length; i < n; ++i) {
+ groups = groups.flatMap(g => g.pop().map(([key, value]) => [...g, key, value]));
+ }
+ return groups;
+}
+
+function flatGroup(values, ...keys) {
+ return flatten$1(groups(values, ...keys), keys);
+}
+
+function flatRollup(values, reduce, ...keys) {
+ return flatten$1(rollups(values, reduce, ...keys), keys);
+}
+
+function rollup(values, reduce, ...keys) {
+ return nest(values, identity, reduce, keys);
+}
+
+function rollups(values, reduce, ...keys) {
+ return nest(values, Array.from, reduce, keys);
+}
+
+function index(values, ...keys) {
+ return nest(values, identity, unique, keys);
+}
+
+function indexes(values, ...keys) {
+ return nest(values, Array.from, unique, keys);
+}
+
+function unique(values) {
+ if (values.length !== 1) throw new Error("duplicate key");
+ return values[0];
+}
+
+function nest(values, map, reduce, keys) {
+ return (function regroup(values, i) {
+ if (i >= keys.length) return reduce(values);
+ const groups = new InternMap();
+ const keyof = keys[i++];
+ let index = -1;
+ for (const value of values) {
+ const key = keyof(value, ++index, values);
+ const group = groups.get(key);
+ if (group) group.push(value);
+ else groups.set(key, [value]);
+ }
+ for (const [key, values] of groups) {
+ groups.set(key, regroup(values, i));
+ }
+ return map(groups);
+ })(values, 0);
+}
+
+function permute(source, keys) {
+ return Array.from(keys, key => source[key]);
+}
+
+function sort(values, ...F) {
+ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+ values = Array.from(values);
+ let [f] = F;
+ if ((f && f.length !== 2) || F.length > 1) {
+ const index = Uint32Array.from(values, (d, i) => i);
+ if (F.length > 1) {
+ F = F.map(f => values.map(f));
+ index.sort((i, j) => {
+ for (const f of F) {
+ const c = ascendingDefined(f[i], f[j]);
+ if (c) return c;
+ }
+ });
+ } else {
+ f = values.map(f);
+ index.sort((i, j) => ascendingDefined(f[i], f[j]));
+ }
+ return permute(values, index);
+ }
+ return values.sort(compareDefined(f));
+}
+
+function compareDefined(compare = ascending) {
+ if (compare === ascending) return ascendingDefined;
+ if (typeof compare !== "function") throw new TypeError("compare is not a function");
+ return (a, b) => {
+ const x = compare(a, b);
+ if (x || x === 0) return x;
+ return (compare(b, b) === 0) - (compare(a, a) === 0);
+ };
+}
+
+function ascendingDefined(a, b) {
+ return (a == null || !(a >= a)) - (b == null || !(b >= b)) || (a < b ? -1 : a > b ? 1 : 0);
+}
+
+function groupSort(values, reduce, key) {
+ return (reduce.length !== 2
+ ? sort(rollup(values, reduce, key), (([ak, av], [bk, bv]) => ascending(av, bv) || ascending(ak, bk)))
+ : sort(group(values, key), (([ak, av], [bk, bv]) => reduce(av, bv) || ascending(ak, bk))))
+ .map(([key]) => key);
+}
+
+var array = Array.prototype;
+
+var slice = array.slice;
+
+function constant(x) {
+ return () => x;
+}
+
+const e10 = Math.sqrt(50),
+ e5 = Math.sqrt(10),
+ e2 = Math.sqrt(2);
+
+function tickSpec(start, stop, count) {
+ const step = (stop - start) / Math.max(0, count),
+ power = Math.floor(Math.log10(step)),
+ error = step / Math.pow(10, power),
+ factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;
+ let i1, i2, inc;
+ if (power < 0) {
+ inc = Math.pow(10, -power) / factor;
+ i1 = Math.round(start * inc);
+ i2 = Math.round(stop * inc);
+ if (i1 / inc < start) ++i1;
+ if (i2 / inc > stop) --i2;
+ inc = -inc;
+ } else {
+ inc = Math.pow(10, power) * factor;
+ i1 = Math.round(start / inc);
+ i2 = Math.round(stop / inc);
+ if (i1 * inc < start) ++i1;
+ if (i2 * inc > stop) --i2;
+ }
+ if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2);
+ return [i1, i2, inc];
+}
+
+function ticks(start, stop, count) {
+ stop = +stop, start = +start, count = +count;
+ if (!(count > 0)) return [];
+ if (start === stop) return [start];
+ const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count) : tickSpec(start, stop, count);
+ if (!(i2 >= i1)) return [];
+ const n = i2 - i1 + 1, ticks = new Array(n);
+ if (reverse) {
+ if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) / -inc;
+ else for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) * inc;
+ } else {
+ if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) / -inc;
+ else for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) * inc;
+ }
+ return ticks;
+}
+
+function tickIncrement(start, stop, count) {
+ stop = +stop, start = +start, count = +count;
+ return tickSpec(start, stop, count)[2];
+}
+
+function tickStep(start, stop, count) {
+ stop = +stop, start = +start, count = +count;
+ const reverse = stop < start, inc = reverse ? tickIncrement(stop, start, count) : tickIncrement(start, stop, count);
+ return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc);
+}
+
+function nice(start, stop, count) {
+ let prestep;
+ while (true) {
+ const step = tickIncrement(start, stop, count);
+ if (step === prestep || step === 0 || !isFinite(step)) {
+ return [start, stop];
+ } else if (step > 0) {
+ start = Math.floor(start / step) * step;
+ stop = Math.ceil(stop / step) * step;
+ } else if (step < 0) {
+ start = Math.ceil(start * step) / step;
+ stop = Math.floor(stop * step) / step;
+ }
+ prestep = step;
+ }
+}
+
+function thresholdSturges(values) {
+ return Math.max(1, Math.ceil(Math.log(count(values)) / Math.LN2) + 1);
+}
+
+function bin() {
+ var value = identity,
+ domain = extent,
+ threshold = thresholdSturges;
+
+ function histogram(data) {
+ if (!Array.isArray(data)) data = Array.from(data);
+
+ var i,
+ n = data.length,
+ x,
+ step,
+ values = new Array(n);
+
+ for (i = 0; i < n; ++i) {
+ values[i] = value(data[i], i, data);
+ }
+
+ var xz = domain(values),
+ x0 = xz[0],
+ x1 = xz[1],
+ tz = threshold(values, x0, x1);
+
+ // Convert number of thresholds into uniform thresholds, and nice the
+ // default domain accordingly.
+ if (!Array.isArray(tz)) {
+ const max = x1, tn = +tz;
+ if (domain === extent) [x0, x1] = nice(x0, x1, tn);
+ tz = ticks(x0, x1, tn);
+
+ // If the domain is aligned with the first tick (which it will by
+ // default), then we can use quantization rather than bisection to bin
+ // values, which is substantially faster.
+ if (tz[0] <= x0) step = tickIncrement(x0, x1, tn);
+
+ // If the last threshold is coincident with the domain’s upper bound, the
+ // last bin will be zero-width. If the default domain is used, and this
+ // last threshold is coincident with the maximum input value, we can
+ // extend the niced upper bound by one tick to ensure uniform bin widths;
+ // otherwise, we simply remove the last threshold. Note that we don’t
+ // coerce values or the domain to numbers, and thus must be careful to
+ // compare order (>=) rather than strict equality (===)!
+ if (tz[tz.length - 1] >= x1) {
+ if (max >= x1 && domain === extent) {
+ const step = tickIncrement(x0, x1, tn);
+ if (isFinite(step)) {
+ if (step > 0) {
+ x1 = (Math.floor(x1 / step) + 1) * step;
+ } else if (step < 0) {
+ x1 = (Math.ceil(x1 * -step) + 1) / -step;
+ }
+ }
+ } else {
+ tz.pop();
+ }
+ }
+ }
+
+ // Remove any thresholds outside the domain.
+ // Be careful not to mutate an array owned by the user!
+ var m = tz.length, a = 0, b = m;
+ while (tz[a] <= x0) ++a;
+ while (tz[b - 1] > x1) --b;
+ if (a || b < m) tz = tz.slice(a, b), m = b - a;
+
+ var bins = new Array(m + 1),
+ bin;
+
+ // Initialize bins.
+ for (i = 0; i <= m; ++i) {
+ bin = bins[i] = [];
+ bin.x0 = i > 0 ? tz[i - 1] : x0;
+ bin.x1 = i < m ? tz[i] : x1;
+ }
+
+ // Assign data to bins by value, ignoring any outside the domain.
+ if (isFinite(step)) {
+ if (step > 0) {
+ for (i = 0; i < n; ++i) {
+ if ((x = values[i]) != null && x0 <= x && x <= x1) {
+ bins[Math.min(m, Math.floor((x - x0) / step))].push(data[i]);
+ }
+ }
+ } else if (step < 0) {
+ for (i = 0; i < n; ++i) {
+ if ((x = values[i]) != null && x0 <= x && x <= x1) {
+ const j = Math.floor((x0 - x) * step);
+ bins[Math.min(m, j + (tz[j] <= x))].push(data[i]); // handle off-by-one due to rounding
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ if ((x = values[i]) != null && x0 <= x && x <= x1) {
+ bins[bisect(tz, x, 0, m)].push(data[i]);
+ }
+ }
+ }
+
+ return bins;
+ }
+
+ histogram.value = function(_) {
+ return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
+ };
+
+ histogram.domain = function(_) {
+ return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
+ };
+
+ histogram.thresholds = function(_) {
+ return arguments.length ? (threshold = typeof _ === "function" ? _ : constant(Array.isArray(_) ? slice.call(_) : _), histogram) : threshold;
+ };
+
+ return histogram;
+}
+
+function max(values, valueof) {
+ let max;
+ if (valueof === undefined) {
+ for (const value of values) {
+ if (value != null
+ && (max < value || (max === undefined && value >= value))) {
+ max = value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null
+ && (max < value || (max === undefined && value >= value))) {
+ max = value;
+ }
+ }
+ }
+ return max;
+}
+
+function maxIndex(values, valueof) {
+ let max;
+ let maxIndex = -1;
+ let index = -1;
+ if (valueof === undefined) {
+ for (const value of values) {
+ ++index;
+ if (value != null
+ && (max < value || (max === undefined && value >= value))) {
+ max = value, maxIndex = index;
+ }
+ }
+ } else {
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null
+ && (max < value || (max === undefined && value >= value))) {
+ max = value, maxIndex = index;
+ }
+ }
+ }
+ return maxIndex;
+}
+
+function min(values, valueof) {
+ let min;
+ if (valueof === undefined) {
+ for (const value of values) {
+ if (value != null
+ && (min > value || (min === undefined && value >= value))) {
+ min = value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null
+ && (min > value || (min === undefined && value >= value))) {
+ min = value;
+ }
+ }
+ }
+ return min;
+}
+
+function minIndex(values, valueof) {
+ let min;
+ let minIndex = -1;
+ let index = -1;
+ if (valueof === undefined) {
+ for (const value of values) {
+ ++index;
+ if (value != null
+ && (min > value || (min === undefined && value >= value))) {
+ min = value, minIndex = index;
+ }
+ }
+ } else {
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null
+ && (min > value || (min === undefined && value >= value))) {
+ min = value, minIndex = index;
+ }
+ }
+ }
+ return minIndex;
+}
+
+// Based on https://github.com/mourner/quickselect
+// ISC license, Copyright 2018 Vladimir Agafonkin.
+function quickselect(array, k, left = 0, right = Infinity, compare) {
+ k = Math.floor(k);
+ left = Math.floor(Math.max(0, left));
+ right = Math.floor(Math.min(array.length - 1, right));
+
+ if (!(left <= k && k <= right)) return array;
+
+ compare = compare === undefined ? ascendingDefined : compareDefined(compare);
+
+ while (right > left) {
+ if (right - left > 600) {
+ const n = right - left + 1;
+ const m = k - left + 1;
+ const z = Math.log(n);
+ const s = 0.5 * Math.exp(2 * z / 3);
+ const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
+ const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
+ const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
+ quickselect(array, k, newLeft, newRight, compare);
+ }
+
+ const t = array[k];
+ let i = left;
+ let j = right;
+
+ swap(array, left, k);
+ if (compare(array[right], t) > 0) swap(array, left, right);
+
+ while (i < j) {
+ swap(array, i, j), ++i, --j;
+ while (compare(array[i], t) < 0) ++i;
+ while (compare(array[j], t) > 0) --j;
+ }
+
+ if (compare(array[left], t) === 0) swap(array, left, j);
+ else ++j, swap(array, j, right);
+
+ if (j <= k) left = j + 1;
+ if (k <= j) right = j - 1;
+ }
+
+ return array;
+}
+
+function swap(array, i, j) {
+ const t = array[i];
+ array[i] = array[j];
+ array[j] = t;
+}
+
+function greatest(values, compare = ascending) {
+ let max;
+ let defined = false;
+ if (compare.length === 1) {
+ let maxValue;
+ for (const element of values) {
+ const value = compare(element);
+ if (defined
+ ? ascending(value, maxValue) > 0
+ : ascending(value, value) === 0) {
+ max = element;
+ maxValue = value;
+ defined = true;
+ }
+ }
+ } else {
+ for (const value of values) {
+ if (defined
+ ? compare(value, max) > 0
+ : compare(value, value) === 0) {
+ max = value;
+ defined = true;
+ }
+ }
+ }
+ return max;
+}
+
+function quantile(values, p, valueof) {
+ values = Float64Array.from(numbers(values, valueof));
+ if (!(n = values.length) || isNaN(p = +p)) return;
+ if (p <= 0 || n < 2) return min(values);
+ if (p >= 1) return max(values);
+ var n,
+ i = (n - 1) * p,
+ i0 = Math.floor(i),
+ value0 = max(quickselect(values, i0).subarray(0, i0 + 1)),
+ value1 = min(values.subarray(i0 + 1));
+ return value0 + (value1 - value0) * (i - i0);
+}
+
+function quantileSorted(values, p, valueof = number) {
+ if (!(n = values.length) || isNaN(p = +p)) return;
+ if (p <= 0 || n < 2) return +valueof(values[0], 0, values);
+ if (p >= 1) return +valueof(values[n - 1], n - 1, values);
+ var n,
+ i = (n - 1) * p,
+ i0 = Math.floor(i),
+ value0 = +valueof(values[i0], i0, values),
+ value1 = +valueof(values[i0 + 1], i0 + 1, values);
+ return value0 + (value1 - value0) * (i - i0);
+}
+
+function quantileIndex(values, p, valueof = number) {
+ if (isNaN(p = +p)) return;
+ numbers = Float64Array.from(values, (_, i) => number(valueof(values[i], i, values)));
+ if (p <= 0) return minIndex(numbers);
+ if (p >= 1) return maxIndex(numbers);
+ var numbers,
+ index = Uint32Array.from(values, (_, i) => i),
+ j = numbers.length - 1,
+ i = Math.floor(j * p);
+ quickselect(index, i, 0, j, (i, j) => ascendingDefined(numbers[i], numbers[j]));
+ i = greatest(index.subarray(0, i + 1), (i) => numbers[i]);
+ return i >= 0 ? i : -1;
+}
+
+function thresholdFreedmanDiaconis(values, min, max) {
+ const c = count(values), d = quantile(values, 0.75) - quantile(values, 0.25);
+ return c && d ? Math.ceil((max - min) / (2 * d * Math.pow(c, -1 / 3))) : 1;
+}
+
+function thresholdScott(values, min, max) {
+ const c = count(values), d = deviation(values);
+ return c && d ? Math.ceil((max - min) * Math.cbrt(c) / (3.49 * d)) : 1;
+}
+
+function mean(values, valueof) {
+ let count = 0;
+ let sum = 0;
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && (value = +value) >= value) {
+ ++count, sum += value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+ ++count, sum += value;
+ }
+ }
+ }
+ if (count) return sum / count;
+}
+
+function median(values, valueof) {
+ return quantile(values, 0.5, valueof);
+}
+
+function medianIndex(values, valueof) {
+ return quantileIndex(values, 0.5, valueof);
+}
+
+function* flatten(arrays) {
+ for (const array of arrays) {
+ yield* array;
+ }
+}
+
+function merge(arrays) {
+ return Array.from(flatten(arrays));
+}
+
+function mode(values, valueof) {
+ const counts = new InternMap();
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && value >= value) {
+ counts.set(value, (counts.get(value) || 0) + 1);
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && value >= value) {
+ counts.set(value, (counts.get(value) || 0) + 1);
+ }
+ }
+ }
+ let modeValue;
+ let modeCount = 0;
+ for (const [value, count] of counts) {
+ if (count > modeCount) {
+ modeCount = count;
+ modeValue = value;
+ }
+ }
+ return modeValue;
+}
+
+function pairs(values, pairof = pair) {
+ const pairs = [];
+ let previous;
+ let first = false;
+ for (const value of values) {
+ if (first) pairs.push(pairof(previous, value));
+ previous = value;
+ first = true;
+ }
+ return pairs;
+}
+
+function pair(a, b) {
+ return [a, b];
+}
+
+function range(start, stop, step) {
+ start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
+
+ var i = -1,
+ n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
+ range = new Array(n);
+
+ while (++i < n) {
+ range[i] = start + i * step;
+ }
+
+ return range;
+}
+
+function rank(values, valueof = ascending) {
+ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+ let V = Array.from(values);
+ const R = new Float64Array(V.length);
+ if (valueof.length !== 2) V = V.map(valueof), valueof = ascending;
+ const compareIndex = (i, j) => valueof(V[i], V[j]);
+ let k, r;
+ values = Uint32Array.from(V, (_, i) => i);
+ // Risky chaining due to Safari 14 https://github.com/d3/d3-array/issues/123
+ values.sort(valueof === ascending ? (i, j) => ascendingDefined(V[i], V[j]) : compareDefined(compareIndex));
+ values.forEach((j, i) => {
+ const c = compareIndex(j, k === undefined ? j : k);
+ if (c >= 0) {
+ if (k === undefined || c > 0) k = j, r = i;
+ R[j] = r;
+ } else {
+ R[j] = NaN;
+ }
+ });
+ return R;
+}
+
+function least(values, compare = ascending) {
+ let min;
+ let defined = false;
+ if (compare.length === 1) {
+ let minValue;
+ for (const element of values) {
+ const value = compare(element);
+ if (defined
+ ? ascending(value, minValue) < 0
+ : ascending(value, value) === 0) {
+ min = element;
+ minValue = value;
+ defined = true;
+ }
+ }
+ } else {
+ for (const value of values) {
+ if (defined
+ ? compare(value, min) < 0
+ : compare(value, value) === 0) {
+ min = value;
+ defined = true;
+ }
+ }
+ }
+ return min;
+}
+
+function leastIndex(values, compare = ascending) {
+ if (compare.length === 1) return minIndex(values, compare);
+ let minValue;
+ let min = -1;
+ let index = -1;
+ for (const value of values) {
+ ++index;
+ if (min < 0
+ ? compare(value, value) === 0
+ : compare(value, minValue) < 0) {
+ minValue = value;
+ min = index;
+ }
+ }
+ return min;
+}
+
+function greatestIndex(values, compare = ascending) {
+ if (compare.length === 1) return maxIndex(values, compare);
+ let maxValue;
+ let max = -1;
+ let index = -1;
+ for (const value of values) {
+ ++index;
+ if (max < 0
+ ? compare(value, value) === 0
+ : compare(value, maxValue) > 0) {
+ maxValue = value;
+ max = index;
+ }
+ }
+ return max;
+}
+
+function scan(values, compare) {
+ const index = leastIndex(values, compare);
+ return index < 0 ? undefined : index;
+}
+
+var shuffle = shuffler(Math.random);
+
+function shuffler(random) {
+ return function shuffle(array, i0 = 0, i1 = array.length) {
+ let m = i1 - (i0 = +i0);
+ while (m) {
+ const i = random() * m-- | 0, t = array[m + i0];
+ array[m + i0] = array[i + i0];
+ array[i + i0] = t;
+ }
+ return array;
+ };
+}
+
+function sum(values, valueof) {
+ let sum = 0;
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value = +value) {
+ sum += value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if (value = +valueof(value, ++index, values)) {
+ sum += value;
+ }
+ }
+ }
+ return sum;
+}
+
+function transpose(matrix) {
+ if (!(n = matrix.length)) return [];
+ for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
+ for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
+ row[j] = matrix[j][i];
+ }
+ }
+ return transpose;
+}
+
+function length(d) {
+ return d.length;
+}
+
+function zip() {
+ return transpose(arguments);
+}
+
+function every(values, test) {
+ if (typeof test !== "function") throw new TypeError("test is not a function");
+ let index = -1;
+ for (const value of values) {
+ if (!test(value, ++index, values)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function some(values, test) {
+ if (typeof test !== "function") throw new TypeError("test is not a function");
+ let index = -1;
+ for (const value of values) {
+ if (test(value, ++index, values)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function filter(values, test) {
+ if (typeof test !== "function") throw new TypeError("test is not a function");
+ const array = [];
+ let index = -1;
+ for (const value of values) {
+ if (test(value, ++index, values)) {
+ array.push(value);
+ }
+ }
+ return array;
+}
+
+function map(values, mapper) {
+ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+ if (typeof mapper !== "function") throw new TypeError("mapper is not a function");
+ return Array.from(values, (value, index) => mapper(value, index, values));
+}
+
+function reduce(values, reducer, value) {
+ if (typeof reducer !== "function") throw new TypeError("reducer is not a function");
+ const iterator = values[Symbol.iterator]();
+ let done, next, index = -1;
+ if (arguments.length < 3) {
+ ({done, value} = iterator.next());
+ if (done) return;
+ ++index;
+ }
+ while (({done, value: next} = iterator.next()), !done) {
+ value = reducer(value, next, ++index, values);
+ }
+ return value;
+}
+
+function reverse(values) {
+ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+ return Array.from(values).reverse();
+}
+
+function difference(values, ...others) {
+ values = new InternSet(values);
+ for (const other of others) {
+ for (const value of other) {
+ values.delete(value);
+ }
+ }
+ return values;
+}
+
+function disjoint(values, other) {
+ const iterator = other[Symbol.iterator](), set = new InternSet();
+ for (const v of values) {
+ if (set.has(v)) return false;
+ let value, done;
+ while (({value, done} = iterator.next())) {
+ if (done) break;
+ if (Object.is(v, value)) return false;
+ set.add(value);
+ }
+ }
+ return true;
+}
+
+function intersection(values, ...others) {
+ values = new InternSet(values);
+ others = others.map(set);
+ out: for (const value of values) {
+ for (const other of others) {
+ if (!other.has(value)) {
+ values.delete(value);
+ continue out;
+ }
+ }
+ }
+ return values;
+}
+
+function set(values) {
+ return values instanceof InternSet ? values : new InternSet(values);
+}
+
+function superset(values, other) {
+ const iterator = values[Symbol.iterator](), set = new Set();
+ for (const o of other) {
+ const io = intern(o);
+ if (set.has(io)) continue;
+ let value, done;
+ while (({value, done} = iterator.next())) {
+ if (done) return false;
+ const ivalue = intern(value);
+ set.add(ivalue);
+ if (Object.is(io, ivalue)) break;
+ }
+ }
+ return true;
+}
+
+function intern(value) {
+ return value !== null && typeof value === "object" ? value.valueOf() : value;
+}
+
+function subset(values, other) {
+ return superset(other, values);
+}
+
+function union(...others) {
+ const set = new InternSet();
+ for (const other of others) {
+ for (const o of other) {
+ set.add(o);
+ }
+ }
+ return set;
+}
+
+exports.Adder = Adder;
+exports.InternMap = InternMap;
+exports.InternSet = InternSet;
+exports.ascending = ascending;
+exports.bin = bin;
+exports.bisect = bisect;
+exports.bisectCenter = bisectCenter;
+exports.bisectLeft = bisectLeft;
+exports.bisectRight = bisectRight;
+exports.bisector = bisector;
+exports.blur = blur;
+exports.blur2 = blur2;
+exports.blurImage = blurImage;
+exports.count = count;
+exports.cross = cross;
+exports.cumsum = cumsum;
+exports.descending = descending;
+exports.deviation = deviation;
+exports.difference = difference;
+exports.disjoint = disjoint;
+exports.every = every;
+exports.extent = extent;
+exports.fcumsum = fcumsum;
+exports.filter = filter;
+exports.flatGroup = flatGroup;
+exports.flatRollup = flatRollup;
+exports.fsum = fsum;
+exports.greatest = greatest;
+exports.greatestIndex = greatestIndex;
+exports.group = group;
+exports.groupSort = groupSort;
+exports.groups = groups;
+exports.histogram = bin;
+exports.index = index;
+exports.indexes = indexes;
+exports.intersection = intersection;
+exports.least = least;
+exports.leastIndex = leastIndex;
+exports.map = map;
+exports.max = max;
+exports.maxIndex = maxIndex;
+exports.mean = mean;
+exports.median = median;
+exports.medianIndex = medianIndex;
+exports.merge = merge;
+exports.min = min;
+exports.minIndex = minIndex;
+exports.mode = mode;
+exports.nice = nice;
+exports.pairs = pairs;
+exports.permute = permute;
+exports.quantile = quantile;
+exports.quantileIndex = quantileIndex;
+exports.quantileSorted = quantileSorted;
+exports.quickselect = quickselect;
+exports.range = range;
+exports.rank = rank;
+exports.reduce = reduce;
+exports.reverse = reverse;
+exports.rollup = rollup;
+exports.rollups = rollups;
+exports.scan = scan;
+exports.shuffle = shuffle;
+exports.shuffler = shuffler;
+exports.some = some;
+exports.sort = sort;
+exports.subset = subset;
+exports.sum = sum;
+exports.superset = superset;
+exports.thresholdFreedmanDiaconis = thresholdFreedmanDiaconis;
+exports.thresholdScott = thresholdScott;
+exports.thresholdSturges = thresholdSturges;
+exports.tickIncrement = tickIncrement;
+exports.tickStep = tickStep;
+exports.ticks = ticks;
+exports.transpose = transpose;
+exports.union = union;
+exports.variance = variance;
+exports.zip = zip;
+
+}));
diff --git a/node_modules/d3-array/dist/d3-array.min.js b/node_modules/d3-array/dist/d3-array.min.js
new file mode 100644
index 000000000..8ac3c0984
--- /dev/null
+++ b/node_modules/d3-array/dist/d3-array.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-array/ v3.2.4 Copyright 2010-2023 Mike Bostock
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function n(t,n){return null==t||null==n?NaN:tn?1:t>=n?0:NaN}function r(t,n){return null==t||null==n?NaN:nt?1:n>=t?0:NaN}function e(t){let e,f,i;function u(t,n,r=0,o=t.length){if(r>>1;f(t[e],n)<0?r=e+1:o=e}while(rn(t(r),e),i=(n,r)=>t(n)-r):(e=t===n||t===r?t:o,f=t,i=t),{left:u,center:function(t,n,r=0,e=t.length){const o=u(t,n,r,e-1);return o>r&&i(t[o-1],n)>-i(t[o],n)?o-1:o},right:function(t,n,r=0,o=t.length){if(r>>1;f(t[e],n)<=0?r=e+1:o=e}while(r{n(t,r,(e<<=2)+0,(o<<=2)+0,f<<=2),n(t,r,e+1,o+1,f),n(t,r,e+2,o+2,f),n(t,r,e+3,o+3,f)}}));function d(t){return function(n,r,e=r){if(!((r=+r)>=0))throw new RangeError("invalid rx");if(!((e=+e)>=0))throw new RangeError("invalid ry");let{data:o,width:f,height:i}=n;if(!((f=Math.floor(f))>=0))throw new RangeError("invalid width");if(!((i=Math.floor(void 0!==i?i:o.length/f))>=0))throw new RangeError("invalid height");if(!f||!i||!r&&!e)return n;const u=r&&t(r),l=e&&t(e),c=o.slice();return u&&l?(p(u,c,o,f,i),p(u,o,c,f,i),p(u,c,o,f,i),y(l,o,c,f,i),y(l,c,o,f,i),y(l,o,c,f,i)):u?(p(u,o,c,f,i),p(u,c,o,f,i),p(u,o,c,f,i)):l&&(y(l,o,c,f,i),y(l,c,o,f,i),y(l,o,c,f,i)),n}}function p(t,n,r,e,o){for(let f=0,i=e*o;f{if(!((f-=i)>=o))return;let u=t*e[o];const l=i*t;for(let t=o,n=o+l;t{if(!((i-=u)>=f))return;let l=n*o[f];const c=u*n,s=c+u;for(let t=f,n=f+c;t=n&&++r;else{let e=-1;for(let o of t)null!=(o=n(o,++e,t))&&(o=+o)>=o&&++r}return r}function v(t){return 0|t.length}function M(t){return!(t>0)}function w(t){return"object"!=typeof t||"length"in t?t:Array.from(t)}function b(t,n){let r,e=0,o=0,f=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(r=n-o,o+=r/++e,f+=r*(n-o));else{let i=-1;for(let u of t)null!=(u=n(u,++i,t))&&(u=+u)>=u&&(r=u-o,o+=r/++e,f+=r*(u-o))}if(e>1)return f/(e-1)}function A(t,n){const r=b(t,n);return r?Math.sqrt(r):r}function x(t,n){let r,e;if(void 0===n)for(const n of t)null!=n&&(void 0===r?n>=n&&(r=e=n):(r>n&&(r=n),e=f&&(r=e=f):(r>f&&(r=f),e0){for(f=t[--o];o>0&&(n=f,r=t[--o],f=n+r,e=r-(f-n),!e););o>0&&(e<0&&t[o-1]<0||e>0&&t[o-1]>0)&&(r=2*e,n=f+r,r==n-f&&(f=n))}return f}}class InternMap extends Map{constructor(t,n=k){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const[n,r]of t)this.set(n,r)}get(t){return super.get(E(this,t))}has(t){return super.has(E(this,t))}set(t,n){return super.set(_(this,t),n)}delete(t){return super.delete(S(this,t))}}class InternSet extends Set{constructor(t,n=k){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const n of t)this.add(n)}has(t){return super.has(E(this,t))}add(t){return super.add(_(this,t))}delete(t){return super.delete(S(this,t))}}function E({_intern:t,_key:n},r){const e=n(r);return t.has(e)?t.get(e):r}function _({_intern:t,_key:n},r){const e=n(r);return t.has(e)?t.get(e):(t.set(e,r),r)}function S({_intern:t,_key:n},r){const e=n(r);return t.has(e)&&(r=t.get(e),t.delete(e)),r}function k(t){return null!==t&&"object"==typeof t?t.valueOf():t}function T(t){return t}function F(t,...n){return U(t,T,T,n)}function I(t,...n){return U(t,Array.from,T,n)}function j(t,n){for(let r=1,e=n.length;rt.pop().map((([n,r])=>[...t,n,r]))));return t}function q(t,n,...r){return U(t,T,n,r)}function R(t,n,...r){return U(t,Array.from,n,r)}function O(t){if(1!==t.length)throw new Error("duplicate key");return t[0]}function U(t,n,r,e){return function t(o,f){if(f>=e.length)return r(o);const i=new InternMap,u=e[f++];let l=-1;for(const t of o){const n=u(t,++l,o),r=i.get(n);r?r.push(t):i.set(n,[t])}for(const[n,r]of i)i.set(n,t(r,f));return n(i)}(t,0)}function L(t,n){return Array.from(n,(n=>t[n]))}function P(t,...n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");t=Array.from(t);let[r]=n;if(r&&2!==r.length||n.length>1){const e=Uint32Array.from(t,((t,n)=>n));return n.length>1?(n=n.map((n=>t.map(n))),e.sort(((t,r)=>{for(const e of n){const n=C(e[t],e[r]);if(n)return n}}))):(r=t.map(r),e.sort(((t,n)=>C(r[t],r[n])))),L(t,e)}return t.sort(z(r))}function z(t=n){if(t===n)return C;if("function"!=typeof t)throw new TypeError("compare is not a function");return(n,r)=>{const e=t(n,r);return e||0===e?e:(0===t(r,r))-(0===t(n,n))}}function C(t,n){return(null==t||!(t>=t))-(null==n||!(n>=n))||(tn?1:0)}var D=Array.prototype.slice;function G(t){return()=>t}const B=Math.sqrt(50),H=Math.sqrt(10),J=Math.sqrt(2);function K(t,n,r){const e=(n-t)/Math.max(0,r),o=Math.floor(Math.log10(e)),f=e/Math.pow(10,o),i=f>=B?10:f>=H?5:f>=J?2:1;let u,l,c;return o<0?(c=Math.pow(10,-o)/i,u=Math.round(t*c),l=Math.round(n*c),u/cn&&--l,c=-c):(c=Math.pow(10,o)*i,u=Math.round(t/c),l=Math.round(n/c),u*cn&&--l),l0))return[];if((t=+t)===(n=+n))return[t];const e=n=o))return[];const u=f-o+1,l=new Array(u);if(e)if(i<0)for(let t=0;t0?(t=Math.floor(t/o)*o,n=Math.ceil(n/o)*o):o<0&&(t=Math.ceil(t*o)/o,n=Math.floor(n*o)/o),e=o}}function X(t){return Math.max(1,Math.ceil(Math.log(g(t))/Math.LN2)+1)}function Y(){var t=T,n=x,r=X;function e(e){Array.isArray(e)||(e=Array.from(e));var o,f,i,u=e.length,l=new Array(u);for(o=0;o=h)if(t>=h&&n===x){const t=V(a,h,r);isFinite(t)&&(t>0?h=(Math.floor(h/t)+1)*t:t<0&&(h=(Math.ceil(h*-t)+1)/-t))}else d.pop()}for(var p=d.length,y=0,m=p;d[y]<=a;)++y;for(;d[m-1]>h;)--m;(y||m
0?d[o-1]:a,g.x1=o
0)for(o=0;o=n)&&(r=n);else{let e=-1;for(let o of t)null!=(o=n(o,++e,t))&&(r=o)&&(r=o)}return r}function $(t,n){let r,e=-1,o=-1;if(void 0===n)for(const n of t)++o,null!=n&&(r=n)&&(r=n,e=o);else for(let f of t)null!=(f=n(f,++o,t))&&(r=f)&&(r=f,e=o);return e}function tt(t,n){let r;if(void 0===n)for(const n of t)null!=n&&(r>n||void 0===r&&n>=n)&&(r=n);else{let e=-1;for(let o of t)null!=(o=n(o,++e,t))&&(r>o||void 0===r&&o>=o)&&(r=o)}return r}function nt(t,n){let r,e=-1,o=-1;if(void 0===n)for(const n of t)++o,null!=n&&(r>n||void 0===r&&n>=n)&&(r=n,e=o);else for(let f of t)null!=(f=n(f,++o,t))&&(r>f||void 0===r&&f>=f)&&(r=f,e=o);return e}function rt(t,n,r=0,e=1/0,o){if(n=Math.floor(n),r=Math.floor(Math.max(0,r)),e=Math.floor(Math.min(t.length-1,e)),!(r<=n&&n<=e))return t;for(o=void 0===o?C:z(o);e>r;){if(e-r>600){const f=e-r+1,i=n-r+1,u=Math.log(f),l=.5*Math.exp(2*u/3),c=.5*Math.sqrt(u*l*(f-l)/f)*(i-f/2<0?-1:1);rt(t,n,Math.max(r,Math.floor(n-i*l/f+c)),Math.min(e,Math.floor(n+(f-i)*l/f+c)),o)}const f=t[n];let i=r,u=e;for(et(t,r,n),o(t[e],f)>0&&et(t,r,e);i0;)--u}0===o(t[r],f)?et(t,r,u):(++u,et(t,u,e)),u<=n&&(r=u+1),n<=u&&(e=u-1)}return t}function et(t,n,r){const e=t[n];t[n]=t[r],t[r]=e}function ot(t,r=n){let e,o=!1;if(1===r.length){let f;for(const i of t){const t=r(i);(o?n(t,f)>0:0===n(t,t))&&(e=i,f=t,o=!0)}}else for(const n of t)(o?r(n,e)>0:0===r(n,n))&&(e=n,o=!0);return e}function ft(t,n,r){if(t=Float64Array.from(function*(t,n){if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(yield n);else{let r=-1;for(let e of t)null!=(e=n(e,++r,t))&&(e=+e)>=e&&(yield e)}}(t,r)),(e=t.length)&&!isNaN(n=+n)){if(n<=0||e<2)return tt(t);if(n>=1)return Z(t);var e,o=(e-1)*n,f=Math.floor(o),i=Z(rt(t,f).subarray(0,f+1));return i+(tt(t.subarray(f+1))-i)*(o-f)}}function it(t,n,r=f){if(!isNaN(n=+n)){if(e=Float64Array.from(t,((n,e)=>f(r(t[e],e,t)))),n<=0)return nt(e);if(n>=1)return $(e);var e,o=Uint32Array.from(t,((t,n)=>n)),i=e.length-1,u=Math.floor(i*n);return rt(o,u,0,i,((t,n)=>C(e[t],e[n]))),(u=ot(o.subarray(0,u+1),(t=>e[t])))>=0?u:-1}}function ut(t,n){return[t,n]}function lt(t,r=n){if(1===r.length)return nt(t,r);let e,o=-1,f=-1;for(const n of t)++f,(o<0?0===r(n,n):r(n,e)<0)&&(e=n,o=f);return o}var ct=st(Math.random);function st(t){return function(n,r=0,e=n.length){let o=e-(r=+r);for(;o;){const e=t()*o--|0,f=n[o+r];n[o+r]=n[e+r],n[e+r]=f}return n}}function at(t){if(!(o=t.length))return[];for(var n=-1,r=tt(t,ht),e=new Array(r);++n=0))throw new RangeError("invalid r");let r=t.length;if(!((r=Math.floor(r))>=0))throw new RangeError("invalid length");if(!r||!n)return t;const e=m(n),o=t.slice();return e(t,o,0,r,1),e(o,t,0,r,1),e(t,o,0,r,1),t},t.blur2=a,t.blurImage=h,t.count=g,t.cross=function(...t){const n="function"==typeof t[t.length-1]&&function(t){return n=>t(...n)}(t.pop()),r=(t=t.map(w)).map(v),e=t.length-1,o=new Array(e+1).fill(0),f=[];if(e<0||r.some(M))return f;for(;;){f.push(o.map(((n,r)=>t[r][n])));let i=e;for(;++o[i]===r[i];){if(0===i)return n?f.map(n):f;o[i--]=0}}},t.cumsum=function(t,n){var r=0,e=0;return Float64Array.from(t,void 0===n?t=>r+=+t||0:o=>r+=+n(o,e++,t)||0)},t.descending=r,t.deviation=A,t.difference=function(t,...n){t=new InternSet(t);for(const r of n)for(const n of r)t.delete(n);return t},t.disjoint=function(t,n){const r=n[Symbol.iterator](),e=new InternSet;for(const n of t){if(e.has(n))return!1;let t,o;for(;({value:t,done:o}=r.next())&&!o;){if(Object.is(n,t))return!1;e.add(t)}}return!0},t.every=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let r=-1;for(const e of t)if(!n(e,++r,t))return!1;return!0},t.extent=x,t.fcumsum=function(t,n){const r=new N;let e=-1;return Float64Array.from(t,void 0===n?t=>r.add(+t||0):o=>r.add(+n(o,++e,t)||0))},t.filter=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");const r=[];let e=-1;for(const o of t)n(o,++e,t)&&r.push(o);return r},t.flatGroup=function(t,...n){return j(I(t,...n),n)},t.flatRollup=function(t,n,...r){return j(R(t,n,...r),r)},t.fsum=function(t,n){const r=new N;if(void 0===n)for(let n of t)(n=+n)&&r.add(n);else{let e=-1;for(let o of t)(o=+n(o,++e,t))&&r.add(o)}return+r},t.greatest=ot,t.greatestIndex=function(t,r=n){if(1===r.length)return $(t,r);let e,o=-1,f=-1;for(const n of t)++f,(o<0?0===r(n,n):r(n,e)>0)&&(e=n,o=f);return o},t.group=F,t.groupSort=function(t,r,e){return(2!==r.length?P(q(t,r,e),(([t,r],[e,o])=>n(r,o)||n(t,e))):P(F(t,e),(([t,e],[o,f])=>r(e,f)||n(t,o)))).map((([t])=>t))},t.groups=I,t.histogram=Y,t.index=function(t,...n){return U(t,T,O,n)},t.indexes=function(t,...n){return U(t,Array.from,O,n)},t.intersection=function(t,...n){t=new InternSet(t),n=n.map(dt);t:for(const r of t)for(const e of n)if(!e.has(r)){t.delete(r);continue t}return t},t.least=function(t,r=n){let e,o=!1;if(1===r.length){let f;for(const i of t){const t=r(i);(o?n(t,f)<0:0===n(t,t))&&(e=i,f=t,o=!0)}}else for(const n of t)(o?r(n,e)<0:0===r(n,n))&&(e=n,o=!0);return e},t.leastIndex=lt,t.map=function(t,n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");if("function"!=typeof n)throw new TypeError("mapper is not a function");return Array.from(t,((r,e)=>n(r,e,t)))},t.max=Z,t.maxIndex=$,t.mean=function(t,n){let r=0,e=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(++r,e+=n);else{let o=-1;for(let f of t)null!=(f=n(f,++o,t))&&(f=+f)>=f&&(++r,e+=f)}if(r)return e/r},t.median=function(t,n){return ft(t,.5,n)},t.medianIndex=function(t,n){return it(t,.5,n)},t.merge=function(t){return Array.from(function*(t){for(const n of t)yield*n}(t))},t.min=tt,t.minIndex=nt,t.mode=function(t,n){const r=new InternMap;if(void 0===n)for(let n of t)null!=n&&n>=n&&r.set(n,(r.get(n)||0)+1);else{let e=-1;for(let o of t)null!=(o=n(o,++e,t))&&o>=o&&r.set(o,(r.get(o)||0)+1)}let e,o=0;for(const[t,n]of r)n>o&&(o=n,e=t);return e},t.nice=W,t.pairs=function(t,n=ut){const r=[];let e,o=!1;for(const f of t)o&&r.push(n(e,f)),e=f,o=!0;return r},t.permute=L,t.quantile=ft,t.quantileIndex=it,t.quantileSorted=function(t,n,r=f){if((e=t.length)&&!isNaN(n=+n)){if(n<=0||e<2)return+r(t[0],0,t);if(n>=1)return+r(t[e-1],e-1,t);var e,o=(e-1)*n,i=Math.floor(o),u=+r(t[i],i,t);return u+(+r(t[i+1],i+1,t)-u)*(o-i)}},t.quickselect=rt,t.range=function(t,n,r){t=+t,n=+n,r=(o=arguments.length)<2?(n=t,t=0,1):o<3?1:+r;for(var e=-1,o=0|Math.max(0,Math.ceil((n-t)/r)),f=new Array(o);++er(e[t],e[n]);let i,u;return(t=Uint32Array.from(e,((t,n)=>n))).sort(r===n?(t,n)=>C(e[t],e[n]):z(f)),t.forEach(((t,n)=>{const r=f(t,void 0===i?t:i);r>=0?((void 0===i||r>0)&&(i=t,u=n),o[t]=u):o[t]=NaN})),o},t.reduce=function(t,n,r){if("function"!=typeof n)throw new TypeError("reducer is not a function");const e=t[Symbol.iterator]();let o,f,i=-1;if(arguments.length<3){if(({done:o,value:r}=e.next()),o)return;++i}for(;({done:o,value:f}=e.next()),!o;)r=n(r,f,++i,t);return r},t.reverse=function(t){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");return Array.from(t).reverse()},t.rollup=q,t.rollups=R,t.scan=function(t,n){const r=lt(t,n);return r<0?void 0:r},t.shuffle=ct,t.shuffler=st,t.some=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let r=-1;for(const e of t)if(n(e,++r,t))return!0;return!1},t.sort=P,t.subset=function(t,n){return pt(n,t)},t.sum=function(t,n){let r=0;if(void 0===n)for(let n of t)(n=+n)&&(r+=n);else{let e=-1;for(let o of t)(o=+n(o,++e,t))&&(r+=o)}return r},t.superset=pt,t.thresholdFreedmanDiaconis=function(t,n,r){const e=g(t),o=ft(t,.75)-ft(t,.25);return e&&o?Math.ceil((r-n)/(2*o*Math.pow(e,-1/3))):1},t.thresholdScott=function(t,n,r){const e=g(t),o=A(t);return e&&o?Math.ceil((r-n)*Math.cbrt(e)/(3.49*o)):1},t.thresholdSturges=X,t.tickIncrement=V,t.tickStep=function(t,n,r){r=+r;const e=(n=+n)<(t=+t),o=e?V(n,t,r):V(t,n,r);return(e?-1:1)*(o<0?1/-o:o)},t.ticks=Q,t.transpose=at,t.union=function(...t){const n=new InternSet;for(const r of t)for(const t of r)n.add(t);return n},t.variance=b,t.zip=function(){return at(arguments)}}));
diff --git a/node_modules/d3-array/package.json b/node_modules/d3-array/package.json
new file mode 100644
index 000000000..d0c54eea5
--- /dev/null
+++ b/node_modules/d3-array/package.json
@@ -0,0 +1,61 @@
+{
+ "name": "d3-array",
+ "version": "3.2.4",
+ "description": "Array manipulation, ordering, searching, summarizing, etc.",
+ "homepage": "https://d3js.org/d3-array/",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/d3/d3-array.git"
+ },
+ "keywords": [
+ "d3",
+ "d3-module",
+ "histogram",
+ "bisect",
+ "shuffle",
+ "statistics",
+ "search",
+ "sort",
+ "array"
+ ],
+ "license": "ISC",
+ "author": {
+ "name": "Mike Bostock",
+ "url": "http://bost.ocks.org/mike"
+ },
+ "type": "module",
+ "files": [
+ "dist/**/*.js",
+ "src/**/*.js"
+ ],
+ "module": "src/index.js",
+ "main": "src/index.js",
+ "jsdelivr": "dist/d3-array.min.js",
+ "unpkg": "dist/d3-array.min.js",
+ "exports": {
+ "umd": "./dist/d3-array.min.js",
+ "default": "./src/index.js"
+ },
+ "sideEffects": false,
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "devDependencies": {
+ "@rollup/plugin-node-resolve": "15",
+ "d3-dsv": "3",
+ "d3-random": "2 - 3",
+ "eslint": "8",
+ "jsdom": "21",
+ "mocha": "10",
+ "rollup": "3",
+ "rollup-plugin-terser": "7"
+ },
+ "scripts": {
+ "test": "mocha 'test/**/*-test.js' && eslint src test",
+ "prepublishOnly": "rm -rf dist && rollup -c",
+ "postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../${npm_package_name}/dist/${npm_package_name}.js ${npm_package_name}.v${npm_package_version%%.*}.js && cp ../${npm_package_name}/dist/${npm_package_name}.min.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git add ${npm_package_name}.v${npm_package_version%%.*}.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git commit -m \"${npm_package_name} ${npm_package_version}\" && git push && cd -"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+}
diff --git a/node_modules/d3-array/src/array.js b/node_modules/d3-array/src/array.js
new file mode 100644
index 000000000..80084030e
--- /dev/null
+++ b/node_modules/d3-array/src/array.js
@@ -0,0 +1,4 @@
+var array = Array.prototype;
+
+export var slice = array.slice;
+export var map = array.map;
diff --git a/node_modules/d3-array/src/ascending.js b/node_modules/d3-array/src/ascending.js
new file mode 100644
index 000000000..7527ea797
--- /dev/null
+++ b/node_modules/d3-array/src/ascending.js
@@ -0,0 +1,3 @@
+export default function ascending(a, b) {
+ return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+}
diff --git a/node_modules/d3-array/src/bin.js b/node_modules/d3-array/src/bin.js
new file mode 100644
index 000000000..4557e104b
--- /dev/null
+++ b/node_modules/d3-array/src/bin.js
@@ -0,0 +1,125 @@
+import {slice} from "./array.js";
+import bisect from "./bisect.js";
+import constant from "./constant.js";
+import extent from "./extent.js";
+import identity from "./identity.js";
+import nice from "./nice.js";
+import ticks, {tickIncrement} from "./ticks.js";
+import sturges from "./threshold/sturges.js";
+
+export default function bin() {
+ var value = identity,
+ domain = extent,
+ threshold = sturges;
+
+ function histogram(data) {
+ if (!Array.isArray(data)) data = Array.from(data);
+
+ var i,
+ n = data.length,
+ x,
+ step,
+ values = new Array(n);
+
+ for (i = 0; i < n; ++i) {
+ values[i] = value(data[i], i, data);
+ }
+
+ var xz = domain(values),
+ x0 = xz[0],
+ x1 = xz[1],
+ tz = threshold(values, x0, x1);
+
+ // Convert number of thresholds into uniform thresholds, and nice the
+ // default domain accordingly.
+ if (!Array.isArray(tz)) {
+ const max = x1, tn = +tz;
+ if (domain === extent) [x0, x1] = nice(x0, x1, tn);
+ tz = ticks(x0, x1, tn);
+
+ // If the domain is aligned with the first tick (which it will by
+ // default), then we can use quantization rather than bisection to bin
+ // values, which is substantially faster.
+ if (tz[0] <= x0) step = tickIncrement(x0, x1, tn);
+
+ // If the last threshold is coincident with the domain’s upper bound, the
+ // last bin will be zero-width. If the default domain is used, and this
+ // last threshold is coincident with the maximum input value, we can
+ // extend the niced upper bound by one tick to ensure uniform bin widths;
+ // otherwise, we simply remove the last threshold. Note that we don’t
+ // coerce values or the domain to numbers, and thus must be careful to
+ // compare order (>=) rather than strict equality (===)!
+ if (tz[tz.length - 1] >= x1) {
+ if (max >= x1 && domain === extent) {
+ const step = tickIncrement(x0, x1, tn);
+ if (isFinite(step)) {
+ if (step > 0) {
+ x1 = (Math.floor(x1 / step) + 1) * step;
+ } else if (step < 0) {
+ x1 = (Math.ceil(x1 * -step) + 1) / -step;
+ }
+ }
+ } else {
+ tz.pop();
+ }
+ }
+ }
+
+ // Remove any thresholds outside the domain.
+ // Be careful not to mutate an array owned by the user!
+ var m = tz.length, a = 0, b = m;
+ while (tz[a] <= x0) ++a;
+ while (tz[b - 1] > x1) --b;
+ if (a || b < m) tz = tz.slice(a, b), m = b - a;
+
+ var bins = new Array(m + 1),
+ bin;
+
+ // Initialize bins.
+ for (i = 0; i <= m; ++i) {
+ bin = bins[i] = [];
+ bin.x0 = i > 0 ? tz[i - 1] : x0;
+ bin.x1 = i < m ? tz[i] : x1;
+ }
+
+ // Assign data to bins by value, ignoring any outside the domain.
+ if (isFinite(step)) {
+ if (step > 0) {
+ for (i = 0; i < n; ++i) {
+ if ((x = values[i]) != null && x0 <= x && x <= x1) {
+ bins[Math.min(m, Math.floor((x - x0) / step))].push(data[i]);
+ }
+ }
+ } else if (step < 0) {
+ for (i = 0; i < n; ++i) {
+ if ((x = values[i]) != null && x0 <= x && x <= x1) {
+ const j = Math.floor((x0 - x) * step);
+ bins[Math.min(m, j + (tz[j] <= x))].push(data[i]); // handle off-by-one due to rounding
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ if ((x = values[i]) != null && x0 <= x && x <= x1) {
+ bins[bisect(tz, x, 0, m)].push(data[i]);
+ }
+ }
+ }
+
+ return bins;
+ }
+
+ histogram.value = function(_) {
+ return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
+ };
+
+ histogram.domain = function(_) {
+ return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
+ };
+
+ histogram.thresholds = function(_) {
+ return arguments.length ? (threshold = typeof _ === "function" ? _ : constant(Array.isArray(_) ? slice.call(_) : _), histogram) : threshold;
+ };
+
+ return histogram;
+}
diff --git a/node_modules/d3-array/src/bisect.js b/node_modules/d3-array/src/bisect.js
new file mode 100644
index 000000000..333a7e431
--- /dev/null
+++ b/node_modules/d3-array/src/bisect.js
@@ -0,0 +1,9 @@
+import ascending from "./ascending.js";
+import bisector from "./bisector.js";
+import number from "./number.js";
+
+const ascendingBisect = bisector(ascending);
+export const bisectRight = ascendingBisect.right;
+export const bisectLeft = ascendingBisect.left;
+export const bisectCenter = bisector(number).center;
+export default bisectRight;
diff --git a/node_modules/d3-array/src/bisector.js b/node_modules/d3-array/src/bisector.js
new file mode 100644
index 000000000..07e4c342b
--- /dev/null
+++ b/node_modules/d3-array/src/bisector.js
@@ -0,0 +1,56 @@
+import ascending from "./ascending.js";
+import descending from "./descending.js";
+
+export default function bisector(f) {
+ let compare1, compare2, delta;
+
+ // If an accessor is specified, promote it to a comparator. In this case we
+ // can test whether the search value is (self-) comparable. We can’t do this
+ // for a comparator (except for specific, known comparators) because we can’t
+ // tell if the comparator is symmetric, and an asymmetric comparator can’t be
+ // used to test whether a single value is comparable.
+ if (f.length !== 2) {
+ compare1 = ascending;
+ compare2 = (d, x) => ascending(f(d), x);
+ delta = (d, x) => f(d) - x;
+ } else {
+ compare1 = f === ascending || f === descending ? f : zero;
+ compare2 = f;
+ delta = f;
+ }
+
+ function left(a, x, lo = 0, hi = a.length) {
+ if (lo < hi) {
+ if (compare1(x, x) !== 0) return hi;
+ do {
+ const mid = (lo + hi) >>> 1;
+ if (compare2(a[mid], x) < 0) lo = mid + 1;
+ else hi = mid;
+ } while (lo < hi);
+ }
+ return lo;
+ }
+
+ function right(a, x, lo = 0, hi = a.length) {
+ if (lo < hi) {
+ if (compare1(x, x) !== 0) return hi;
+ do {
+ const mid = (lo + hi) >>> 1;
+ if (compare2(a[mid], x) <= 0) lo = mid + 1;
+ else hi = mid;
+ } while (lo < hi);
+ }
+ return lo;
+ }
+
+ function center(a, x, lo = 0, hi = a.length) {
+ const i = left(a, x, lo, hi - 1);
+ return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
+ }
+
+ return {left, center, right};
+}
+
+function zero() {
+ return 0;
+}
diff --git a/node_modules/d3-array/src/blur.js b/node_modules/d3-array/src/blur.js
new file mode 100644
index 000000000..7021cbf3d
--- /dev/null
+++ b/node_modules/d3-array/src/blur.js
@@ -0,0 +1,115 @@
+export function blur(values, r) {
+ if (!((r = +r) >= 0)) throw new RangeError("invalid r");
+ let length = values.length;
+ if (!((length = Math.floor(length)) >= 0)) throw new RangeError("invalid length");
+ if (!length || !r) return values;
+ const blur = blurf(r);
+ const temp = values.slice();
+ blur(values, temp, 0, length, 1);
+ blur(temp, values, 0, length, 1);
+ blur(values, temp, 0, length, 1);
+ return values;
+}
+
+export const blur2 = Blur2(blurf);
+
+export const blurImage = Blur2(blurfImage);
+
+function Blur2(blur) {
+ return function(data, rx, ry = rx) {
+ if (!((rx = +rx) >= 0)) throw new RangeError("invalid rx");
+ if (!((ry = +ry) >= 0)) throw new RangeError("invalid ry");
+ let {data: values, width, height} = data;
+ if (!((width = Math.floor(width)) >= 0)) throw new RangeError("invalid width");
+ if (!((height = Math.floor(height !== undefined ? height : values.length / width)) >= 0)) throw new RangeError("invalid height");
+ if (!width || !height || (!rx && !ry)) return data;
+ const blurx = rx && blur(rx);
+ const blury = ry && blur(ry);
+ const temp = values.slice();
+ if (blurx && blury) {
+ blurh(blurx, temp, values, width, height);
+ blurh(blurx, values, temp, width, height);
+ blurh(blurx, temp, values, width, height);
+ blurv(blury, values, temp, width, height);
+ blurv(blury, temp, values, width, height);
+ blurv(blury, values, temp, width, height);
+ } else if (blurx) {
+ blurh(blurx, values, temp, width, height);
+ blurh(blurx, temp, values, width, height);
+ blurh(blurx, values, temp, width, height);
+ } else if (blury) {
+ blurv(blury, values, temp, width, height);
+ blurv(blury, temp, values, width, height);
+ blurv(blury, values, temp, width, height);
+ }
+ return data;
+ };
+}
+
+function blurh(blur, T, S, w, h) {
+ for (let y = 0, n = w * h; y < n;) {
+ blur(T, S, y, y += w, 1);
+ }
+}
+
+function blurv(blur, T, S, w, h) {
+ for (let x = 0, n = w * h; x < w; ++x) {
+ blur(T, S, x, x + n, w);
+ }
+}
+
+function blurfImage(radius) {
+ const blur = blurf(radius);
+ return (T, S, start, stop, step) => {
+ start <<= 2, stop <<= 2, step <<= 2;
+ blur(T, S, start + 0, stop + 0, step);
+ blur(T, S, start + 1, stop + 1, step);
+ blur(T, S, start + 2, stop + 2, step);
+ blur(T, S, start + 3, stop + 3, step);
+ };
+}
+
+// Given a target array T, a source array S, sets each value T[i] to the average
+// of {S[i - r], …, S[i], …, S[i + r]}, where r = ⌊radius⌋, start <= i < stop,
+// for each i, i + step, i + 2 * step, etc., and where S[j] is clamped between
+// S[start] (inclusive) and S[stop] (exclusive). If the given radius is not an
+// integer, S[i - r - 1] and S[i + r + 1] are added to the sum, each weighted
+// according to r - ⌊radius⌋.
+function blurf(radius) {
+ const radius0 = Math.floor(radius);
+ if (radius0 === radius) return bluri(radius);
+ const t = radius - radius0;
+ const w = 2 * radius + 1;
+ return (T, S, start, stop, step) => { // stop must be aligned!
+ if (!((stop -= step) >= start)) return; // inclusive stop
+ let sum = radius0 * S[start];
+ const s0 = step * radius0;
+ const s1 = s0 + step;
+ for (let i = start, j = start + s0; i < j; i += step) {
+ sum += S[Math.min(stop, i)];
+ }
+ for (let i = start, j = stop; i <= j; i += step) {
+ sum += S[Math.min(stop, i + s0)];
+ T[i] = (sum + t * (S[Math.max(start, i - s1)] + S[Math.min(stop, i + s1)])) / w;
+ sum -= S[Math.max(start, i - s0)];
+ }
+ };
+}
+
+// Like blurf, but optimized for integer radius.
+function bluri(radius) {
+ const w = 2 * radius + 1;
+ return (T, S, start, stop, step) => { // stop must be aligned!
+ if (!((stop -= step) >= start)) return; // inclusive stop
+ let sum = radius * S[start];
+ const s = step * radius;
+ for (let i = start, j = start + s; i < j; i += step) {
+ sum += S[Math.min(stop, i)];
+ }
+ for (let i = start, j = stop; i <= j; i += step) {
+ sum += S[Math.min(stop, i + s)];
+ T[i] = sum / w;
+ sum -= S[Math.max(start, i - s)];
+ }
+ };
+}
diff --git a/node_modules/d3-array/src/constant.js b/node_modules/d3-array/src/constant.js
new file mode 100644
index 000000000..bb0ec8605
--- /dev/null
+++ b/node_modules/d3-array/src/constant.js
@@ -0,0 +1,3 @@
+export default function constant(x) {
+ return () => x;
+}
diff --git a/node_modules/d3-array/src/count.js b/node_modules/d3-array/src/count.js
new file mode 100644
index 000000000..b8783f08b
--- /dev/null
+++ b/node_modules/d3-array/src/count.js
@@ -0,0 +1,18 @@
+export default function count(values, valueof) {
+ let count = 0;
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && (value = +value) >= value) {
+ ++count;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+ ++count;
+ }
+ }
+ }
+ return count;
+}
diff --git a/node_modules/d3-array/src/cross.js b/node_modules/d3-array/src/cross.js
new file mode 100644
index 000000000..7efdbe3cd
--- /dev/null
+++ b/node_modules/d3-array/src/cross.js
@@ -0,0 +1,33 @@
+function length(array) {
+ return array.length | 0;
+}
+
+function empty(length) {
+ return !(length > 0);
+}
+
+function arrayify(values) {
+ return typeof values !== "object" || "length" in values ? values : Array.from(values);
+}
+
+function reducer(reduce) {
+ return values => reduce(...values);
+}
+
+export default function cross(...values) {
+ const reduce = typeof values[values.length - 1] === "function" && reducer(values.pop());
+ values = values.map(arrayify);
+ const lengths = values.map(length);
+ const j = values.length - 1;
+ const index = new Array(j + 1).fill(0);
+ const product = [];
+ if (j < 0 || lengths.some(empty)) return product;
+ while (true) {
+ product.push(index.map((j, i) => values[i][j]));
+ let i = j;
+ while (++index[i] === lengths[i]) {
+ if (i === 0) return reduce ? product.map(reduce) : product;
+ index[i--] = 0;
+ }
+ }
+}
diff --git a/node_modules/d3-array/src/cumsum.js b/node_modules/d3-array/src/cumsum.js
new file mode 100644
index 000000000..86fb0522c
--- /dev/null
+++ b/node_modules/d3-array/src/cumsum.js
@@ -0,0 +1,6 @@
+export default function cumsum(values, valueof) {
+ var sum = 0, index = 0;
+ return Float64Array.from(values, valueof === undefined
+ ? v => (sum += +v || 0)
+ : v => (sum += +valueof(v, index++, values) || 0));
+}
\ No newline at end of file
diff --git a/node_modules/d3-array/src/descending.js b/node_modules/d3-array/src/descending.js
new file mode 100644
index 000000000..215f81ea2
--- /dev/null
+++ b/node_modules/d3-array/src/descending.js
@@ -0,0 +1,7 @@
+export default function descending(a, b) {
+ return a == null || b == null ? NaN
+ : b < a ? -1
+ : b > a ? 1
+ : b >= a ? 0
+ : NaN;
+}
diff --git a/node_modules/d3-array/src/deviation.js b/node_modules/d3-array/src/deviation.js
new file mode 100644
index 000000000..d5dbe7a98
--- /dev/null
+++ b/node_modules/d3-array/src/deviation.js
@@ -0,0 +1,6 @@
+import variance from "./variance.js";
+
+export default function deviation(values, valueof) {
+ const v = variance(values, valueof);
+ return v ? Math.sqrt(v) : v;
+}
diff --git a/node_modules/d3-array/src/difference.js b/node_modules/d3-array/src/difference.js
new file mode 100644
index 000000000..c19ba7882
--- /dev/null
+++ b/node_modules/d3-array/src/difference.js
@@ -0,0 +1,11 @@
+import {InternSet} from "internmap";
+
+export default function difference(values, ...others) {
+ values = new InternSet(values);
+ for (const other of others) {
+ for (const value of other) {
+ values.delete(value);
+ }
+ }
+ return values;
+}
diff --git a/node_modules/d3-array/src/disjoint.js b/node_modules/d3-array/src/disjoint.js
new file mode 100644
index 000000000..d62a67010
--- /dev/null
+++ b/node_modules/d3-array/src/disjoint.js
@@ -0,0 +1,15 @@
+import {InternSet} from "internmap";
+
+export default function disjoint(values, other) {
+ const iterator = other[Symbol.iterator](), set = new InternSet();
+ for (const v of values) {
+ if (set.has(v)) return false;
+ let value, done;
+ while (({value, done} = iterator.next())) {
+ if (done) break;
+ if (Object.is(v, value)) return false;
+ set.add(value);
+ }
+ }
+ return true;
+}
diff --git a/node_modules/d3-array/src/every.js b/node_modules/d3-array/src/every.js
new file mode 100644
index 000000000..484cac23e
--- /dev/null
+++ b/node_modules/d3-array/src/every.js
@@ -0,0 +1,10 @@
+export default function every(values, test) {
+ if (typeof test !== "function") throw new TypeError("test is not a function");
+ let index = -1;
+ for (const value of values) {
+ if (!test(value, ++index, values)) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/node_modules/d3-array/src/extent.js b/node_modules/d3-array/src/extent.js
new file mode 100644
index 000000000..580171fd3
--- /dev/null
+++ b/node_modules/d3-array/src/extent.js
@@ -0,0 +1,29 @@
+export default function extent(values, valueof) {
+ let min;
+ let max;
+ if (valueof === undefined) {
+ for (const value of values) {
+ if (value != null) {
+ if (min === undefined) {
+ if (value >= value) min = max = value;
+ } else {
+ if (min > value) min = value;
+ if (max < value) max = value;
+ }
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null) {
+ if (min === undefined) {
+ if (value >= value) min = max = value;
+ } else {
+ if (min > value) min = value;
+ if (max < value) max = value;
+ }
+ }
+ }
+ }
+ return [min, max];
+}
diff --git a/node_modules/d3-array/src/filter.js b/node_modules/d3-array/src/filter.js
new file mode 100644
index 000000000..d653392f2
--- /dev/null
+++ b/node_modules/d3-array/src/filter.js
@@ -0,0 +1,11 @@
+export default function filter(values, test) {
+ if (typeof test !== "function") throw new TypeError("test is not a function");
+ const array = [];
+ let index = -1;
+ for (const value of values) {
+ if (test(value, ++index, values)) {
+ array.push(value);
+ }
+ }
+ return array;
+}
diff --git a/node_modules/d3-array/src/fsum.js b/node_modules/d3-array/src/fsum.js
new file mode 100644
index 000000000..4a8e1cfc1
--- /dev/null
+++ b/node_modules/d3-array/src/fsum.js
@@ -0,0 +1,69 @@
+// https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
+export class Adder {
+ constructor() {
+ this._partials = new Float64Array(32);
+ this._n = 0;
+ }
+ add(x) {
+ const p = this._partials;
+ let i = 0;
+ for (let j = 0; j < this._n && j < 32; j++) {
+ const y = p[j],
+ hi = x + y,
+ lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
+ if (lo) p[i++] = lo;
+ x = hi;
+ }
+ p[i] = x;
+ this._n = i + 1;
+ return this;
+ }
+ valueOf() {
+ const p = this._partials;
+ let n = this._n, x, y, lo, hi = 0;
+ if (n > 0) {
+ hi = p[--n];
+ while (n > 0) {
+ x = hi;
+ y = p[--n];
+ hi = x + y;
+ lo = y - (hi - x);
+ if (lo) break;
+ }
+ if (n > 0 && ((lo < 0 && p[n - 1] < 0) || (lo > 0 && p[n - 1] > 0))) {
+ y = lo * 2;
+ x = hi + y;
+ if (y == x - hi) hi = x;
+ }
+ }
+ return hi;
+ }
+}
+
+export function fsum(values, valueof) {
+ const adder = new Adder();
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value = +value) {
+ adder.add(value);
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if (value = +valueof(value, ++index, values)) {
+ adder.add(value);
+ }
+ }
+ }
+ return +adder;
+}
+
+export function fcumsum(values, valueof) {
+ const adder = new Adder();
+ let index = -1;
+ return Float64Array.from(values, valueof === undefined
+ ? v => adder.add(+v || 0)
+ : v => adder.add(+valueof(v, ++index, values) || 0)
+ );
+}
diff --git a/node_modules/d3-array/src/greatest.js b/node_modules/d3-array/src/greatest.js
new file mode 100644
index 000000000..521f4f5c0
--- /dev/null
+++ b/node_modules/d3-array/src/greatest.js
@@ -0,0 +1,29 @@
+import ascending from "./ascending.js";
+
+export default function greatest(values, compare = ascending) {
+ let max;
+ let defined = false;
+ if (compare.length === 1) {
+ let maxValue;
+ for (const element of values) {
+ const value = compare(element);
+ if (defined
+ ? ascending(value, maxValue) > 0
+ : ascending(value, value) === 0) {
+ max = element;
+ maxValue = value;
+ defined = true;
+ }
+ }
+ } else {
+ for (const value of values) {
+ if (defined
+ ? compare(value, max) > 0
+ : compare(value, value) === 0) {
+ max = value;
+ defined = true;
+ }
+ }
+ }
+ return max;
+}
diff --git a/node_modules/d3-array/src/greatestIndex.js b/node_modules/d3-array/src/greatestIndex.js
new file mode 100644
index 000000000..2f390e5b4
--- /dev/null
+++ b/node_modules/d3-array/src/greatestIndex.js
@@ -0,0 +1,19 @@
+import ascending from "./ascending.js";
+import maxIndex from "./maxIndex.js";
+
+export default function greatestIndex(values, compare = ascending) {
+ if (compare.length === 1) return maxIndex(values, compare);
+ let maxValue;
+ let max = -1;
+ let index = -1;
+ for (const value of values) {
+ ++index;
+ if (max < 0
+ ? compare(value, value) === 0
+ : compare(value, maxValue) > 0) {
+ maxValue = value;
+ max = index;
+ }
+ }
+ return max;
+}
diff --git a/node_modules/d3-array/src/group.js b/node_modules/d3-array/src/group.js
new file mode 100644
index 000000000..0c30d7e96
--- /dev/null
+++ b/node_modules/d3-array/src/group.js
@@ -0,0 +1,65 @@
+import {InternMap} from "internmap";
+import identity from "./identity.js";
+
+export default function group(values, ...keys) {
+ return nest(values, identity, identity, keys);
+}
+
+export function groups(values, ...keys) {
+ return nest(values, Array.from, identity, keys);
+}
+
+function flatten(groups, keys) {
+ for (let i = 1, n = keys.length; i < n; ++i) {
+ groups = groups.flatMap(g => g.pop().map(([key, value]) => [...g, key, value]));
+ }
+ return groups;
+}
+
+export function flatGroup(values, ...keys) {
+ return flatten(groups(values, ...keys), keys);
+}
+
+export function flatRollup(values, reduce, ...keys) {
+ return flatten(rollups(values, reduce, ...keys), keys);
+}
+
+export function rollup(values, reduce, ...keys) {
+ return nest(values, identity, reduce, keys);
+}
+
+export function rollups(values, reduce, ...keys) {
+ return nest(values, Array.from, reduce, keys);
+}
+
+export function index(values, ...keys) {
+ return nest(values, identity, unique, keys);
+}
+
+export function indexes(values, ...keys) {
+ return nest(values, Array.from, unique, keys);
+}
+
+function unique(values) {
+ if (values.length !== 1) throw new Error("duplicate key");
+ return values[0];
+}
+
+function nest(values, map, reduce, keys) {
+ return (function regroup(values, i) {
+ if (i >= keys.length) return reduce(values);
+ const groups = new InternMap();
+ const keyof = keys[i++];
+ let index = -1;
+ for (const value of values) {
+ const key = keyof(value, ++index, values);
+ const group = groups.get(key);
+ if (group) group.push(value);
+ else groups.set(key, [value]);
+ }
+ for (const [key, values] of groups) {
+ groups.set(key, regroup(values, i));
+ }
+ return map(groups);
+ })(values, 0);
+}
diff --git a/node_modules/d3-array/src/groupSort.js b/node_modules/d3-array/src/groupSort.js
new file mode 100644
index 000000000..2d56ccf0d
--- /dev/null
+++ b/node_modules/d3-array/src/groupSort.js
@@ -0,0 +1,10 @@
+import ascending from "./ascending.js";
+import group, {rollup} from "./group.js";
+import sort from "./sort.js";
+
+export default function groupSort(values, reduce, key) {
+ return (reduce.length !== 2
+ ? sort(rollup(values, reduce, key), (([ak, av], [bk, bv]) => ascending(av, bv) || ascending(ak, bk)))
+ : sort(group(values, key), (([ak, av], [bk, bv]) => reduce(av, bv) || ascending(ak, bk))))
+ .map(([key]) => key);
+}
diff --git a/node_modules/d3-array/src/identity.js b/node_modules/d3-array/src/identity.js
new file mode 100644
index 000000000..0c86fdf01
--- /dev/null
+++ b/node_modules/d3-array/src/identity.js
@@ -0,0 +1,3 @@
+export default function identity(x) {
+ return x;
+}
diff --git a/node_modules/d3-array/src/index.js b/node_modules/d3-array/src/index.js
new file mode 100644
index 000000000..7759f6dbb
--- /dev/null
+++ b/node_modules/d3-array/src/index.js
@@ -0,0 +1,57 @@
+export {default as bisect, bisectRight, bisectLeft, bisectCenter} from "./bisect.js";
+export {default as ascending} from "./ascending.js";
+export {default as bisector} from "./bisector.js";
+export {blur, blur2, blurImage} from "./blur.js";
+export {default as count} from "./count.js";
+export {default as cross} from "./cross.js";
+export {default as cumsum} from "./cumsum.js";
+export {default as descending} from "./descending.js";
+export {default as deviation} from "./deviation.js";
+export {default as extent} from "./extent.js";
+export {Adder, fsum, fcumsum} from "./fsum.js";
+export {default as group, flatGroup, flatRollup, groups, index, indexes, rollup, rollups} from "./group.js";
+export {default as groupSort} from "./groupSort.js";
+export {default as bin, default as histogram} from "./bin.js"; // Deprecated; use bin.
+export {default as thresholdFreedmanDiaconis} from "./threshold/freedmanDiaconis.js";
+export {default as thresholdScott} from "./threshold/scott.js";
+export {default as thresholdSturges} from "./threshold/sturges.js";
+export {default as max} from "./max.js";
+export {default as maxIndex} from "./maxIndex.js";
+export {default as mean} from "./mean.js";
+export {default as median, medianIndex} from "./median.js";
+export {default as merge} from "./merge.js";
+export {default as min} from "./min.js";
+export {default as minIndex} from "./minIndex.js";
+export {default as mode} from "./mode.js";
+export {default as nice} from "./nice.js";
+export {default as pairs} from "./pairs.js";
+export {default as permute} from "./permute.js";
+export {default as quantile, quantileIndex, quantileSorted} from "./quantile.js";
+export {default as quickselect} from "./quickselect.js";
+export {default as range} from "./range.js";
+export {default as rank} from "./rank.js";
+export {default as least} from "./least.js";
+export {default as leastIndex} from "./leastIndex.js";
+export {default as greatest} from "./greatest.js";
+export {default as greatestIndex} from "./greatestIndex.js";
+export {default as scan} from "./scan.js"; // Deprecated; use leastIndex.
+export {default as shuffle, shuffler} from "./shuffle.js";
+export {default as sum} from "./sum.js";
+export {default as ticks, tickIncrement, tickStep} from "./ticks.js";
+export {default as transpose} from "./transpose.js";
+export {default as variance} from "./variance.js";
+export {default as zip} from "./zip.js";
+export {default as every} from "./every.js";
+export {default as some} from "./some.js";
+export {default as filter} from "./filter.js";
+export {default as map} from "./map.js";
+export {default as reduce} from "./reduce.js";
+export {default as reverse} from "./reverse.js";
+export {default as sort} from "./sort.js";
+export {default as difference} from "./difference.js";
+export {default as disjoint} from "./disjoint.js";
+export {default as intersection} from "./intersection.js";
+export {default as subset} from "./subset.js";
+export {default as superset} from "./superset.js";
+export {default as union} from "./union.js";
+export {InternMap, InternSet} from "internmap";
diff --git a/node_modules/d3-array/src/intersection.js b/node_modules/d3-array/src/intersection.js
new file mode 100644
index 000000000..43aff3994
--- /dev/null
+++ b/node_modules/d3-array/src/intersection.js
@@ -0,0 +1,19 @@
+import {InternSet} from "internmap";
+
+export default function intersection(values, ...others) {
+ values = new InternSet(values);
+ others = others.map(set);
+ out: for (const value of values) {
+ for (const other of others) {
+ if (!other.has(value)) {
+ values.delete(value);
+ continue out;
+ }
+ }
+ }
+ return values;
+}
+
+function set(values) {
+ return values instanceof InternSet ? values : new InternSet(values);
+}
diff --git a/node_modules/d3-array/src/least.js b/node_modules/d3-array/src/least.js
new file mode 100644
index 000000000..a756abf4c
--- /dev/null
+++ b/node_modules/d3-array/src/least.js
@@ -0,0 +1,29 @@
+import ascending from "./ascending.js";
+
+export default function least(values, compare = ascending) {
+ let min;
+ let defined = false;
+ if (compare.length === 1) {
+ let minValue;
+ for (const element of values) {
+ const value = compare(element);
+ if (defined
+ ? ascending(value, minValue) < 0
+ : ascending(value, value) === 0) {
+ min = element;
+ minValue = value;
+ defined = true;
+ }
+ }
+ } else {
+ for (const value of values) {
+ if (defined
+ ? compare(value, min) < 0
+ : compare(value, value) === 0) {
+ min = value;
+ defined = true;
+ }
+ }
+ }
+ return min;
+}
diff --git a/node_modules/d3-array/src/leastIndex.js b/node_modules/d3-array/src/leastIndex.js
new file mode 100644
index 000000000..ee3542be8
--- /dev/null
+++ b/node_modules/d3-array/src/leastIndex.js
@@ -0,0 +1,19 @@
+import ascending from "./ascending.js";
+import minIndex from "./minIndex.js";
+
+export default function leastIndex(values, compare = ascending) {
+ if (compare.length === 1) return minIndex(values, compare);
+ let minValue;
+ let min = -1;
+ let index = -1;
+ for (const value of values) {
+ ++index;
+ if (min < 0
+ ? compare(value, value) === 0
+ : compare(value, minValue) < 0) {
+ minValue = value;
+ min = index;
+ }
+ }
+ return min;
+}
diff --git a/node_modules/d3-array/src/map.js b/node_modules/d3-array/src/map.js
new file mode 100644
index 000000000..4e5681907
--- /dev/null
+++ b/node_modules/d3-array/src/map.js
@@ -0,0 +1,5 @@
+export default function map(values, mapper) {
+ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+ if (typeof mapper !== "function") throw new TypeError("mapper is not a function");
+ return Array.from(values, (value, index) => mapper(value, index, values));
+}
diff --git a/node_modules/d3-array/src/max.js b/node_modules/d3-array/src/max.js
new file mode 100644
index 000000000..ce287368e
--- /dev/null
+++ b/node_modules/d3-array/src/max.js
@@ -0,0 +1,20 @@
+export default function max(values, valueof) {
+ let max;
+ if (valueof === undefined) {
+ for (const value of values) {
+ if (value != null
+ && (max < value || (max === undefined && value >= value))) {
+ max = value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null
+ && (max < value || (max === undefined && value >= value))) {
+ max = value;
+ }
+ }
+ }
+ return max;
+}
diff --git a/node_modules/d3-array/src/maxIndex.js b/node_modules/d3-array/src/maxIndex.js
new file mode 100644
index 000000000..87da1a2c4
--- /dev/null
+++ b/node_modules/d3-array/src/maxIndex.js
@@ -0,0 +1,22 @@
+export default function maxIndex(values, valueof) {
+ let max;
+ let maxIndex = -1;
+ let index = -1;
+ if (valueof === undefined) {
+ for (const value of values) {
+ ++index;
+ if (value != null
+ && (max < value || (max === undefined && value >= value))) {
+ max = value, maxIndex = index;
+ }
+ }
+ } else {
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null
+ && (max < value || (max === undefined && value >= value))) {
+ max = value, maxIndex = index;
+ }
+ }
+ }
+ return maxIndex;
+}
diff --git a/node_modules/d3-array/src/mean.js b/node_modules/d3-array/src/mean.js
new file mode 100644
index 000000000..ff6fc461f
--- /dev/null
+++ b/node_modules/d3-array/src/mean.js
@@ -0,0 +1,19 @@
+export default function mean(values, valueof) {
+ let count = 0;
+ let sum = 0;
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && (value = +value) >= value) {
+ ++count, sum += value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+ ++count, sum += value;
+ }
+ }
+ }
+ if (count) return sum / count;
+}
diff --git a/node_modules/d3-array/src/median.js b/node_modules/d3-array/src/median.js
new file mode 100644
index 000000000..2604df878
--- /dev/null
+++ b/node_modules/d3-array/src/median.js
@@ -0,0 +1,9 @@
+import quantile, {quantileIndex} from "./quantile.js";
+
+export default function median(values, valueof) {
+ return quantile(values, 0.5, valueof);
+}
+
+export function medianIndex(values, valueof) {
+ return quantileIndex(values, 0.5, valueof);
+}
diff --git a/node_modules/d3-array/src/merge.js b/node_modules/d3-array/src/merge.js
new file mode 100644
index 000000000..a36800287
--- /dev/null
+++ b/node_modules/d3-array/src/merge.js
@@ -0,0 +1,9 @@
+function* flatten(arrays) {
+ for (const array of arrays) {
+ yield* array;
+ }
+}
+
+export default function merge(arrays) {
+ return Array.from(flatten(arrays));
+}
diff --git a/node_modules/d3-array/src/min.js b/node_modules/d3-array/src/min.js
new file mode 100644
index 000000000..df88bfb26
--- /dev/null
+++ b/node_modules/d3-array/src/min.js
@@ -0,0 +1,20 @@
+export default function min(values, valueof) {
+ let min;
+ if (valueof === undefined) {
+ for (const value of values) {
+ if (value != null
+ && (min > value || (min === undefined && value >= value))) {
+ min = value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null
+ && (min > value || (min === undefined && value >= value))) {
+ min = value;
+ }
+ }
+ }
+ return min;
+}
diff --git a/node_modules/d3-array/src/minIndex.js b/node_modules/d3-array/src/minIndex.js
new file mode 100644
index 000000000..5c07d1ead
--- /dev/null
+++ b/node_modules/d3-array/src/minIndex.js
@@ -0,0 +1,22 @@
+export default function minIndex(values, valueof) {
+ let min;
+ let minIndex = -1;
+ let index = -1;
+ if (valueof === undefined) {
+ for (const value of values) {
+ ++index;
+ if (value != null
+ && (min > value || (min === undefined && value >= value))) {
+ min = value, minIndex = index;
+ }
+ }
+ } else {
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null
+ && (min > value || (min === undefined && value >= value))) {
+ min = value, minIndex = index;
+ }
+ }
+ }
+ return minIndex;
+}
diff --git a/node_modules/d3-array/src/mode.js b/node_modules/d3-array/src/mode.js
new file mode 100644
index 000000000..386be5798
--- /dev/null
+++ b/node_modules/d3-array/src/mode.js
@@ -0,0 +1,28 @@
+import {InternMap} from "internmap";
+
+export default function mode(values, valueof) {
+ const counts = new InternMap();
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && value >= value) {
+ counts.set(value, (counts.get(value) || 0) + 1);
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && value >= value) {
+ counts.set(value, (counts.get(value) || 0) + 1);
+ }
+ }
+ }
+ let modeValue;
+ let modeCount = 0;
+ for (const [value, count] of counts) {
+ if (count > modeCount) {
+ modeCount = count;
+ modeValue = value;
+ }
+ }
+ return modeValue;
+}
diff --git a/node_modules/d3-array/src/nice.js b/node_modules/d3-array/src/nice.js
new file mode 100644
index 000000000..579b418c7
--- /dev/null
+++ b/node_modules/d3-array/src/nice.js
@@ -0,0 +1,18 @@
+import {tickIncrement} from "./ticks.js";
+
+export default function nice(start, stop, count) {
+ let prestep;
+ while (true) {
+ const step = tickIncrement(start, stop, count);
+ if (step === prestep || step === 0 || !isFinite(step)) {
+ return [start, stop];
+ } else if (step > 0) {
+ start = Math.floor(start / step) * step;
+ stop = Math.ceil(stop / step) * step;
+ } else if (step < 0) {
+ start = Math.ceil(start * step) / step;
+ stop = Math.floor(stop * step) / step;
+ }
+ prestep = step;
+ }
+}
diff --git a/node_modules/d3-array/src/number.js b/node_modules/d3-array/src/number.js
new file mode 100644
index 000000000..f282cdfb7
--- /dev/null
+++ b/node_modules/d3-array/src/number.js
@@ -0,0 +1,20 @@
+export default function number(x) {
+ return x === null ? NaN : +x;
+}
+
+export function* numbers(values, valueof) {
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && (value = +value) >= value) {
+ yield value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+ yield value;
+ }
+ }
+ }
+}
diff --git a/node_modules/d3-array/src/pairs.js b/node_modules/d3-array/src/pairs.js
new file mode 100644
index 000000000..bfaafece5
--- /dev/null
+++ b/node_modules/d3-array/src/pairs.js
@@ -0,0 +1,15 @@
+export default function pairs(values, pairof = pair) {
+ const pairs = [];
+ let previous;
+ let first = false;
+ for (const value of values) {
+ if (first) pairs.push(pairof(previous, value));
+ previous = value;
+ first = true;
+ }
+ return pairs;
+}
+
+export function pair(a, b) {
+ return [a, b];
+}
diff --git a/node_modules/d3-array/src/permute.js b/node_modules/d3-array/src/permute.js
new file mode 100644
index 000000000..f050865cb
--- /dev/null
+++ b/node_modules/d3-array/src/permute.js
@@ -0,0 +1,3 @@
+export default function permute(source, keys) {
+ return Array.from(keys, key => source[key]);
+}
diff --git a/node_modules/d3-array/src/quantile.js b/node_modules/d3-array/src/quantile.js
new file mode 100644
index 000000000..75d97268e
--- /dev/null
+++ b/node_modules/d3-array/src/quantile.js
@@ -0,0 +1,47 @@
+import max from "./max.js";
+import maxIndex from "./maxIndex.js";
+import min from "./min.js";
+import minIndex from "./minIndex.js";
+import quickselect from "./quickselect.js";
+import number, {numbers} from "./number.js";
+import {ascendingDefined} from "./sort.js";
+import greatest from "./greatest.js";
+
+export default function quantile(values, p, valueof) {
+ values = Float64Array.from(numbers(values, valueof));
+ if (!(n = values.length) || isNaN(p = +p)) return;
+ if (p <= 0 || n < 2) return min(values);
+ if (p >= 1) return max(values);
+ var n,
+ i = (n - 1) * p,
+ i0 = Math.floor(i),
+ value0 = max(quickselect(values, i0).subarray(0, i0 + 1)),
+ value1 = min(values.subarray(i0 + 1));
+ return value0 + (value1 - value0) * (i - i0);
+}
+
+export function quantileSorted(values, p, valueof = number) {
+ if (!(n = values.length) || isNaN(p = +p)) return;
+ if (p <= 0 || n < 2) return +valueof(values[0], 0, values);
+ if (p >= 1) return +valueof(values[n - 1], n - 1, values);
+ var n,
+ i = (n - 1) * p,
+ i0 = Math.floor(i),
+ value0 = +valueof(values[i0], i0, values),
+ value1 = +valueof(values[i0 + 1], i0 + 1, values);
+ return value0 + (value1 - value0) * (i - i0);
+}
+
+export function quantileIndex(values, p, valueof = number) {
+ if (isNaN(p = +p)) return;
+ numbers = Float64Array.from(values, (_, i) => number(valueof(values[i], i, values)));
+ if (p <= 0) return minIndex(numbers);
+ if (p >= 1) return maxIndex(numbers);
+ var numbers,
+ index = Uint32Array.from(values, (_, i) => i),
+ j = numbers.length - 1,
+ i = Math.floor(j * p);
+ quickselect(index, i, 0, j, (i, j) => ascendingDefined(numbers[i], numbers[j]));
+ i = greatest(index.subarray(0, i + 1), (i) => numbers[i]);
+ return i >= 0 ? i : -1;
+}
diff --git a/node_modules/d3-array/src/quickselect.js b/node_modules/d3-array/src/quickselect.js
new file mode 100644
index 000000000..19dbb4670
--- /dev/null
+++ b/node_modules/d3-array/src/quickselect.js
@@ -0,0 +1,53 @@
+import {ascendingDefined, compareDefined} from "./sort.js";
+
+// Based on https://github.com/mourner/quickselect
+// ISC license, Copyright 2018 Vladimir Agafonkin.
+export default function quickselect(array, k, left = 0, right = Infinity, compare) {
+ k = Math.floor(k);
+ left = Math.floor(Math.max(0, left));
+ right = Math.floor(Math.min(array.length - 1, right));
+
+ if (!(left <= k && k <= right)) return array;
+
+ compare = compare === undefined ? ascendingDefined : compareDefined(compare);
+
+ while (right > left) {
+ if (right - left > 600) {
+ const n = right - left + 1;
+ const m = k - left + 1;
+ const z = Math.log(n);
+ const s = 0.5 * Math.exp(2 * z / 3);
+ const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
+ const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
+ const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
+ quickselect(array, k, newLeft, newRight, compare);
+ }
+
+ const t = array[k];
+ let i = left;
+ let j = right;
+
+ swap(array, left, k);
+ if (compare(array[right], t) > 0) swap(array, left, right);
+
+ while (i < j) {
+ swap(array, i, j), ++i, --j;
+ while (compare(array[i], t) < 0) ++i;
+ while (compare(array[j], t) > 0) --j;
+ }
+
+ if (compare(array[left], t) === 0) swap(array, left, j);
+ else ++j, swap(array, j, right);
+
+ if (j <= k) left = j + 1;
+ if (k <= j) right = j - 1;
+ }
+
+ return array;
+}
+
+function swap(array, i, j) {
+ const t = array[i];
+ array[i] = array[j];
+ array[j] = t;
+}
diff --git a/node_modules/d3-array/src/range.js b/node_modules/d3-array/src/range.js
new file mode 100644
index 000000000..5b86b561d
--- /dev/null
+++ b/node_modules/d3-array/src/range.js
@@ -0,0 +1,13 @@
+export default function range(start, stop, step) {
+ start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
+
+ var i = -1,
+ n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
+ range = new Array(n);
+
+ while (++i < n) {
+ range[i] = start + i * step;
+ }
+
+ return range;
+}
diff --git a/node_modules/d3-array/src/rank.js b/node_modules/d3-array/src/rank.js
new file mode 100644
index 000000000..44fb675ba
--- /dev/null
+++ b/node_modules/d3-array/src/rank.js
@@ -0,0 +1,24 @@
+import ascending from "./ascending.js";
+import {ascendingDefined, compareDefined} from "./sort.js";
+
+export default function rank(values, valueof = ascending) {
+ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+ let V = Array.from(values);
+ const R = new Float64Array(V.length);
+ if (valueof.length !== 2) V = V.map(valueof), valueof = ascending;
+ const compareIndex = (i, j) => valueof(V[i], V[j]);
+ let k, r;
+ values = Uint32Array.from(V, (_, i) => i);
+ // Risky chaining due to Safari 14 https://github.com/d3/d3-array/issues/123
+ values.sort(valueof === ascending ? (i, j) => ascendingDefined(V[i], V[j]) : compareDefined(compareIndex));
+ values.forEach((j, i) => {
+ const c = compareIndex(j, k === undefined ? j : k);
+ if (c >= 0) {
+ if (k === undefined || c > 0) k = j, r = i;
+ R[j] = r;
+ } else {
+ R[j] = NaN;
+ }
+ });
+ return R;
+}
diff --git a/node_modules/d3-array/src/reduce.js b/node_modules/d3-array/src/reduce.js
new file mode 100644
index 000000000..3b49cf56b
--- /dev/null
+++ b/node_modules/d3-array/src/reduce.js
@@ -0,0 +1,14 @@
+export default function reduce(values, reducer, value) {
+ if (typeof reducer !== "function") throw new TypeError("reducer is not a function");
+ const iterator = values[Symbol.iterator]();
+ let done, next, index = -1;
+ if (arguments.length < 3) {
+ ({done, value} = iterator.next());
+ if (done) return;
+ ++index;
+ }
+ while (({done, value: next} = iterator.next()), !done) {
+ value = reducer(value, next, ++index, values);
+ }
+ return value;
+}
diff --git a/node_modules/d3-array/src/reverse.js b/node_modules/d3-array/src/reverse.js
new file mode 100644
index 000000000..da6742cf2
--- /dev/null
+++ b/node_modules/d3-array/src/reverse.js
@@ -0,0 +1,4 @@
+export default function reverse(values) {
+ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+ return Array.from(values).reverse();
+}
diff --git a/node_modules/d3-array/src/scan.js b/node_modules/d3-array/src/scan.js
new file mode 100644
index 000000000..9c538f8a1
--- /dev/null
+++ b/node_modules/d3-array/src/scan.js
@@ -0,0 +1,6 @@
+import leastIndex from "./leastIndex.js";
+
+export default function scan(values, compare) {
+ const index = leastIndex(values, compare);
+ return index < 0 ? undefined : index;
+}
diff --git a/node_modules/d3-array/src/shuffle.js b/node_modules/d3-array/src/shuffle.js
new file mode 100644
index 000000000..426cdac06
--- /dev/null
+++ b/node_modules/d3-array/src/shuffle.js
@@ -0,0 +1,13 @@
+export default shuffler(Math.random);
+
+export function shuffler(random) {
+ return function shuffle(array, i0 = 0, i1 = array.length) {
+ let m = i1 - (i0 = +i0);
+ while (m) {
+ const i = random() * m-- | 0, t = array[m + i0];
+ array[m + i0] = array[i + i0];
+ array[i + i0] = t;
+ }
+ return array;
+ };
+}
diff --git a/node_modules/d3-array/src/some.js b/node_modules/d3-array/src/some.js
new file mode 100644
index 000000000..0b8f98b91
--- /dev/null
+++ b/node_modules/d3-array/src/some.js
@@ -0,0 +1,10 @@
+export default function some(values, test) {
+ if (typeof test !== "function") throw new TypeError("test is not a function");
+ let index = -1;
+ for (const value of values) {
+ if (test(value, ++index, values)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/node_modules/d3-array/src/sort.js b/node_modules/d3-array/src/sort.js
new file mode 100644
index 000000000..14541beb7
--- /dev/null
+++ b/node_modules/d3-array/src/sort.js
@@ -0,0 +1,39 @@
+import ascending from "./ascending.js";
+import permute from "./permute.js";
+
+export default function sort(values, ...F) {
+ if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+ values = Array.from(values);
+ let [f] = F;
+ if ((f && f.length !== 2) || F.length > 1) {
+ const index = Uint32Array.from(values, (d, i) => i);
+ if (F.length > 1) {
+ F = F.map(f => values.map(f));
+ index.sort((i, j) => {
+ for (const f of F) {
+ const c = ascendingDefined(f[i], f[j]);
+ if (c) return c;
+ }
+ });
+ } else {
+ f = values.map(f);
+ index.sort((i, j) => ascendingDefined(f[i], f[j]));
+ }
+ return permute(values, index);
+ }
+ return values.sort(compareDefined(f));
+}
+
+export function compareDefined(compare = ascending) {
+ if (compare === ascending) return ascendingDefined;
+ if (typeof compare !== "function") throw new TypeError("compare is not a function");
+ return (a, b) => {
+ const x = compare(a, b);
+ if (x || x === 0) return x;
+ return (compare(b, b) === 0) - (compare(a, a) === 0);
+ };
+}
+
+export function ascendingDefined(a, b) {
+ return (a == null || !(a >= a)) - (b == null || !(b >= b)) || (a < b ? -1 : a > b ? 1 : 0);
+}
diff --git a/node_modules/d3-array/src/subset.js b/node_modules/d3-array/src/subset.js
new file mode 100644
index 000000000..8a1c56407
--- /dev/null
+++ b/node_modules/d3-array/src/subset.js
@@ -0,0 +1,5 @@
+import superset from "./superset.js";
+
+export default function subset(values, other) {
+ return superset(other, values);
+}
diff --git a/node_modules/d3-array/src/sum.js b/node_modules/d3-array/src/sum.js
new file mode 100644
index 000000000..0720e2a1f
--- /dev/null
+++ b/node_modules/d3-array/src/sum.js
@@ -0,0 +1,18 @@
+export default function sum(values, valueof) {
+ let sum = 0;
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value = +value) {
+ sum += value;
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if (value = +valueof(value, ++index, values)) {
+ sum += value;
+ }
+ }
+ }
+ return sum;
+}
diff --git a/node_modules/d3-array/src/superset.js b/node_modules/d3-array/src/superset.js
new file mode 100644
index 000000000..d178e9c24
--- /dev/null
+++ b/node_modules/d3-array/src/superset.js
@@ -0,0 +1,19 @@
+export default function superset(values, other) {
+ const iterator = values[Symbol.iterator](), set = new Set();
+ for (const o of other) {
+ const io = intern(o);
+ if (set.has(io)) continue;
+ let value, done;
+ while (({value, done} = iterator.next())) {
+ if (done) return false;
+ const ivalue = intern(value);
+ set.add(ivalue);
+ if (Object.is(io, ivalue)) break;
+ }
+ }
+ return true;
+}
+
+function intern(value) {
+ return value !== null && typeof value === "object" ? value.valueOf() : value;
+}
diff --git a/node_modules/d3-array/src/threshold/freedmanDiaconis.js b/node_modules/d3-array/src/threshold/freedmanDiaconis.js
new file mode 100644
index 000000000..c78cff407
--- /dev/null
+++ b/node_modules/d3-array/src/threshold/freedmanDiaconis.js
@@ -0,0 +1,7 @@
+import count from "../count.js";
+import quantile from "../quantile.js";
+
+export default function thresholdFreedmanDiaconis(values, min, max) {
+ const c = count(values), d = quantile(values, 0.75) - quantile(values, 0.25);
+ return c && d ? Math.ceil((max - min) / (2 * d * Math.pow(c, -1 / 3))) : 1;
+}
diff --git a/node_modules/d3-array/src/threshold/scott.js b/node_modules/d3-array/src/threshold/scott.js
new file mode 100644
index 000000000..2541d2dc6
--- /dev/null
+++ b/node_modules/d3-array/src/threshold/scott.js
@@ -0,0 +1,7 @@
+import count from "../count.js";
+import deviation from "../deviation.js";
+
+export default function thresholdScott(values, min, max) {
+ const c = count(values), d = deviation(values);
+ return c && d ? Math.ceil((max - min) * Math.cbrt(c) / (3.49 * d)) : 1;
+}
diff --git a/node_modules/d3-array/src/threshold/sturges.js b/node_modules/d3-array/src/threshold/sturges.js
new file mode 100644
index 000000000..3370968e9
--- /dev/null
+++ b/node_modules/d3-array/src/threshold/sturges.js
@@ -0,0 +1,5 @@
+import count from "../count.js";
+
+export default function thresholdSturges(values) {
+ return Math.max(1, Math.ceil(Math.log(count(values)) / Math.LN2) + 1);
+}
diff --git a/node_modules/d3-array/src/ticks.js b/node_modules/d3-array/src/ticks.js
new file mode 100644
index 000000000..5868d8d20
--- /dev/null
+++ b/node_modules/d3-array/src/ticks.js
@@ -0,0 +1,55 @@
+const e10 = Math.sqrt(50),
+ e5 = Math.sqrt(10),
+ e2 = Math.sqrt(2);
+
+function tickSpec(start, stop, count) {
+ const step = (stop - start) / Math.max(0, count),
+ power = Math.floor(Math.log10(step)),
+ error = step / Math.pow(10, power),
+ factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;
+ let i1, i2, inc;
+ if (power < 0) {
+ inc = Math.pow(10, -power) / factor;
+ i1 = Math.round(start * inc);
+ i2 = Math.round(stop * inc);
+ if (i1 / inc < start) ++i1;
+ if (i2 / inc > stop) --i2;
+ inc = -inc;
+ } else {
+ inc = Math.pow(10, power) * factor;
+ i1 = Math.round(start / inc);
+ i2 = Math.round(stop / inc);
+ if (i1 * inc < start) ++i1;
+ if (i2 * inc > stop) --i2;
+ }
+ if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2);
+ return [i1, i2, inc];
+}
+
+export default function ticks(start, stop, count) {
+ stop = +stop, start = +start, count = +count;
+ if (!(count > 0)) return [];
+ if (start === stop) return [start];
+ const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count) : tickSpec(start, stop, count);
+ if (!(i2 >= i1)) return [];
+ const n = i2 - i1 + 1, ticks = new Array(n);
+ if (reverse) {
+ if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) / -inc;
+ else for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) * inc;
+ } else {
+ if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) / -inc;
+ else for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) * inc;
+ }
+ return ticks;
+}
+
+export function tickIncrement(start, stop, count) {
+ stop = +stop, start = +start, count = +count;
+ return tickSpec(start, stop, count)[2];
+}
+
+export function tickStep(start, stop, count) {
+ stop = +stop, start = +start, count = +count;
+ const reverse = stop < start, inc = reverse ? tickIncrement(stop, start, count) : tickIncrement(start, stop, count);
+ return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc);
+}
diff --git a/node_modules/d3-array/src/transpose.js b/node_modules/d3-array/src/transpose.js
new file mode 100644
index 000000000..de6caebde
--- /dev/null
+++ b/node_modules/d3-array/src/transpose.js
@@ -0,0 +1,15 @@
+import min from "./min.js";
+
+export default function transpose(matrix) {
+ if (!(n = matrix.length)) return [];
+ for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
+ for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
+ row[j] = matrix[j][i];
+ }
+ }
+ return transpose;
+}
+
+function length(d) {
+ return d.length;
+}
diff --git a/node_modules/d3-array/src/union.js b/node_modules/d3-array/src/union.js
new file mode 100644
index 000000000..57c20b108
--- /dev/null
+++ b/node_modules/d3-array/src/union.js
@@ -0,0 +1,11 @@
+import {InternSet} from "internmap";
+
+export default function union(...others) {
+ const set = new InternSet();
+ for (const other of others) {
+ for (const o of other) {
+ set.add(o);
+ }
+ }
+ return set;
+}
diff --git a/node_modules/d3-array/src/variance.js b/node_modules/d3-array/src/variance.js
new file mode 100644
index 000000000..2428bf85f
--- /dev/null
+++ b/node_modules/d3-array/src/variance.js
@@ -0,0 +1,25 @@
+export default function variance(values, valueof) {
+ let count = 0;
+ let delta;
+ let mean = 0;
+ let sum = 0;
+ if (valueof === undefined) {
+ for (let value of values) {
+ if (value != null && (value = +value) >= value) {
+ delta = value - mean;
+ mean += delta / ++count;
+ sum += delta * (value - mean);
+ }
+ }
+ } else {
+ let index = -1;
+ for (let value of values) {
+ if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+ delta = value - mean;
+ mean += delta / ++count;
+ sum += delta * (value - mean);
+ }
+ }
+ }
+ if (count > 1) return sum / (count - 1);
+}
diff --git a/node_modules/d3-array/src/zip.js b/node_modules/d3-array/src/zip.js
new file mode 100644
index 000000000..48cfb425a
--- /dev/null
+++ b/node_modules/d3-array/src/zip.js
@@ -0,0 +1,5 @@
+import transpose from "./transpose.js";
+
+export default function zip() {
+ return transpose(arguments);
+}
diff --git a/node_modules/d3-geo-projection/LICENSE b/node_modules/d3-geo-projection/LICENSE
new file mode 100644
index 000000000..79356d12c
--- /dev/null
+++ b/node_modules/d3-geo-projection/LICENSE
@@ -0,0 +1,37 @@
+Copyright 2013-2021 Mike Bostock
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+MIT License for https://github.com/scijs/integrate-adaptive-simpson
+
+The MIT License (MIT)
+
+Copyright 2015 Ricky Reusser
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/node_modules/d3-geo-projection/README.md b/node_modules/d3-geo-projection/README.md
new file mode 100644
index 000000000..273d47bb5
--- /dev/null
+++ b/node_modules/d3-geo-projection/README.md
@@ -0,0 +1,1181 @@
+# d3-geo-projection
+
+Extended geographic projections for [d3-geo](https://github.com/d3/d3-geo). See [Command-Line Cartography](https://medium.com/@mbostock/command-line-cartography-part-1-897aa8f8ca2c) for an introduction.
+
+## Installing
+
+If you use npm, `npm install d3-geo-projection`. You can also download the [latest release on GitHub](https://github.com/d3/d3-geo-projection/releases/latest). For vanilla HTML in modern browsers, import d3-geo-projection from Skypack:
+
+```html
+
+```
+
+For legacy environments, you can load d3-geo-projection’s UMD bundle from an npm-based CDN such as jsDelivr; a `d3` global is exported:
+
+```html
+
+
+
+
+```
+
+## API Reference
+
+* [Projections](#projections)
+* [Interrupted Projections](#interrupted-projections)
+* [Polyhedral Projections](#polyhedral-projections)
+* [Quincuncial Projections](#quincuncial-projections)
+* [Transformations](#transformations)
+
+### Projections
+
+Note: projections tagged \[d3-geo\] are exported by [d3-geo](https://github.com/d3/d3-geo), not d3-geo-projection. These commonly-used projections are also included in the [d3](https://github.com/d3/d3) default bundle.
+
+# d3.geoAiry() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/airy.js), [Examples](https://observablehq.com/@d3/airys-minimum-error)
+ # d3.geoAiryRaw(beta)
+
+[](https://observablehq.com/@d3/airys-minimum-error)
+
+Airy’s minimum-error azimuthal projection.
+
+#airy.radius([radius])
+
+Defaults to 90°.
+
+# d3.geoAitoff() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/aitoff.js), [Examples](https://observablehq.com/@d3/aitoff)
+ # d3.geoAitoffRaw
+
+[](https://observablehq.com/@d3/aitoff)
+
+The Aitoff projection.
+
+# d3.geoAlbers() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/albers.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoAlbers)
+
+[](https://observablehq.com/@d3/conic-equal-area)
+
+Albers’ [equal-area conic projection](#geoConicEqualArea).
+
+# d3.geoArmadillo() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/armadillo.js), [Examples](https://observablehq.com/@d3/armadillo)
+ # d3.geoArmadilloRaw(phi0)
+
+[](https://observablehq.com/@d3/armadillo)
+
+The armadillo projection. The default center assumes the default [parallel](#armadillo_parallel) of 20° and should be changed if a different parallel is used. Note: requires clipping to the sphere.
+
+#armadillo.parallel([parallel])
+
+Defaults to 20°.
+
+# d3.geoAugust() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/august.js), [Examples](https://observablehq.com/@d3/august)
+ # d3.geoAugustRaw
+
+[](https://observablehq.com/@d3/august)
+
+August’s epicycloidal conformal projection.
+
+# d3.geoAzimuthalEqualArea() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/azimuthalEqualArea.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoAzimuthalEqualArea), [Examples](https://observablehq.com/@d3/azimuthal-equal-area)
+ # d3.geoAzimuthalEqualAreaRaw
+
+[](https://observablehq.com/@d3/azimuthal-equal-area)
+
+The Lambert azimuthal equal-area projection.
+
+# d3.geoAzimuthalEquidistant() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/azimuthalEquidistant.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoAzimuthalEquidistant), [Examples](https://observablehq.com/@d3/azimuthal-equidistant)
+ # d3.geoAzimuthalEquidistantRaw
+
+[](https://observablehq.com/@d3/azimuthal-equidistant)
+
+The azimuthal equidistant projection.
+
+# d3.geoBaker() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/baker.js), [Examples](https://observablehq.com/@d3/baker-dinomic)
+ # d3.geoBakerRaw
+
+[](https://observablehq.com/@d3/baker-dinomic)
+
+The Baker Dinomic projection.
+
+# d3.geoBerghaus() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/berghaus.js), [Examples](https://observablehq.com/@d3/berghaus-star)
+ # d3.geoBerghausRaw(lobes)
+
+[](https://observablehq.com/@d3/berghaus-star)
+
+Berghaus’ star projection. The default center assumes the default [lobe number](#berghaus_lobes) of 5 and should be changed if a different number of lobes is used. Note: requires clipping to the sphere.
+
+#berghaus.lobes([lobes]) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/berghaus.js)
+
+If *lobes* is specified, sets the number of lobes in the resulting star, and returns this projection. If *lobes* is not specified, returns the current lobe number, which defaults to 5.
+
+# d3.geoBertin1953() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/bertin.js)
+ # d3.geoBertin1953Raw
+
+[](https://visionscarto.net/bertin-projection-1953)
+
+Jacques Bertin’s 1953 projection.
+
+# d3.geoBoggs() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/boggs.js), [Examples](https://observablehq.com/@d3/boggs-eumorphic)
+ # d3.geoBoggsRaw
+
+[](https://observablehq.com/@d3/boggs-eumorphic)
+
+The Boggs eumorphic projection. More commonly used in [interrupted form](#geoInterruptedBoggs).
+
+# d3.geoBonne() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/bonne.js), [Examples](https://observablehq.com/@d3/bonne)
+ # d3.geoBonneRaw(phi0)
+
+[](https://observablehq.com/@d3/bonne)
+
+The Bonne pseudoconical equal-area projection. The [Werner projection](https://observablehq.com/@d3/werner) is a limiting form of the Bonne projection with a standard parallel at ±90°. The default center assumes the default [parallel](#bonne_parallel) of 45° and should be changed if a different parallel is used.
+
+#bonne.parallel([parallel])
+
+Defaults to 45°.
+
+# d3.geoBottomley() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/bottomley.js), [Examples](https://observablehq.com/@d3/bottomley)
+ # d3.geoBottomleyRaw(sinPsi)
+
+[](https://observablehq.com/@d3/bottomley)
+
+The [Bottomley projection](https://cybergeo.revues.org/3977) “draws lines of latitude as concentric circular arcs, with arc lengths equal to their lengths on the globe, and placed symmetrically and equally spaced across the vertical central meridian.”
+
+#bottomley.fraction([fraction])
+
+Defaults to 0.5, corresponding to a sin(ψ) where ψ = π/6.
+
+# d3.geoBromley() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/bromley.js), [Examples](https://observablehq.com/@d3/bromley)
+ # d3.geoBromleyRaw
+
+[](https://observablehq.com/@d3/bromley)
+
+The Bromley projection is a rescaled [Mollweide projection](#geoMollweide).
+
+# d3.geoChamberlin(point0, point1, point2) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/chamberlin.js)
+ # d3.geoChamberlinRaw(p0, p1, p2)
+
+The Chamberlin trimetric projection. This method does not support [*projection*.rotate](https://github.com/d3/d3-geo/blob/master/README.md#projection_rotate): the three reference points implicitly determine a fixed rotation.
+
+# d3.geoChamberlinAfrica() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/chamberlin.js)
+
+[](https://bl.ocks.org/mbostock/5625053)
+
+The Chamberlin projection for Africa using points [0°, 22°], [45°, 22°], [22.5°, -22°].
+
+# d3.geoCollignon() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/collignon.js), [Examples](https://observablehq.com/@d3/collignon)
+ # d3.geoCollignonRaw
+
+[](https://observablehq.com/@d3/collignon)
+
+The Collignon equal-area pseudocylindrical projection. This projection is used in the polar areas of the [HEALPix projection](#geoHealpix).
+
+# d3.geoConicConformal() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/conicConformal.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoConicConformal), [Examples](https://observablehq.com/@d3/conic-conformal)
+ # d3.geoConicConformalRaw
+
+[](https://observablehq.com/@d3/conic-conformal)
+
+The Lambert conformal conic projection.
+
+# d3.geoConicEqualArea() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/conicEqualArea.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoConicEqualArea), [Examples](https://observablehq.com/@d3/conic-equal-area)
+ # d3.geoConicEqualAreaRaw
+
+[](https://observablehq.com/@d3/conic-equal-area)
+
+Albers’ conic equal-area projection.
+
+# d3.geoConicEquidistant() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/conicEquidistant.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoConicEquidistant), [Examples](https://observablehq.com/@d3/conic-equidistant)
+ # d3.geoConicEquidistantRaw
+
+[](https://observablehq.com/@d3/conic-equidistant)
+
+The conic equidistant projection.
+
+# d3.geoCraig() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/craig.js), [Examples](https://observablehq.com/@d3/craig)
+ # d3.geoCraigRaw(phi)
+
+[](https://observablehq.com/@d3/craig)
+
+The Craig retroazimuthal projection. Note: this projection tends to [fold over itself](https://bl.ocks.org/mbostock/4459716) if the [standard parallel](#craig_parallel) is non-zero; we have not yet implemented the necessary advanced clipping to avoid overlap.
+
+#craig.parallel([parallel])
+
+Defaults to 0°.
+
+# d3.geoCraster() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/craster.js), [Examples](https://observablehq.com/@d3/craster)
+ # d3.geoCrasterRaw
+
+[](https://observablehq.com/@d3/craster)
+
+The Craster parabolic projection; also known as Putniņš P4.
+
+# d3.geoCylindricalEqualArea() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/cylindricalEqualArea.js), [Examples](https://observablehq.com/@mbostock/cylindrical-equal-area-projections)
+ # d3.geoCylindricalEqualAreaRaw(phi0)
+
+[](https://observablehq.com/@mbostock/cylindrical-equal-area-projections)
+
+The cylindrical equal-area projection. Depending on the chosen [parallel](#cylindricalEqualArea_parallel), this projection is also known as the Lambert cylindrical equal-area (0°), Behrmann (30°), Hobo–Dyer (37.5°), Gall–Peters (45°), Balthasart (50°) and Tobler world-in-a-square (~55.654°).
+
+#cylindricalEqualArea.parallel([parallel])
+
+Defaults to approximately 38.58°, fitting the world in a 960×500 rectangle.
+
+# d3.geoCylindricalStereographic() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/cylindricalStereographic.js), [Examples](https://observablehq.com/@d3/cylindrical-stereographic)
+ # d3.geoCylindricalStereographicRaw(phi0)
+
+[](https://observablehq.com/@d3/cylindrical-stereographic)
+
+The cylindrical stereographic projection. Depending on the chosen [parallel](#cylindricalStereographic_parallel), this projection is also known as Braun’s stereographic (0°) and Gall’s stereographic (45°).
+
+#cylindricalStereographic.parallel([parallel])
+
+Defaults to 0°.
+
+# d3.geoEckert1() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/eckert1.js), [Examples](https://observablehq.com/@d3/eckert-i)
+ # d3.geoEckert1Raw
+
+[](https://observablehq.com/@d3/eckert-i)
+
+The Eckert I projection.
+
+# d3.geoEckert2() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/eckert2.js), [Examples](https://observablehq.com/@d3/eckert-ii)
+ # d3.geoEckert2Raw
+
+[](https://observablehq.com/@d3/eckert-ii)
+
+The Eckert II projection.
+
+# d3.geoEckert3() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/eckert3.js), [Examples](https://observablehq.com/@d3/eckert-iii)
+ # d3.geoEckert3Raw
+
+[](https://observablehq.com/@d3/eckert-iii)
+
+The Eckert III projection.
+
+# d3.geoEckert4() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/eckert4.js), [Examples](https://observablehq.com/@d3/eckert-iv)
+ # d3.geoEckert4Raw
+
+[](https://observablehq.com/@d3/eckert-iv)
+
+The Eckert IV projection.
+
+# d3.geoEckert5() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/eckert5.js), [Examples](https://observablehq.com/@d3/eckert-v)
+ # d3.geoEckert5Raw
+
+[](https://observablehq.com/@d3/eckert-v)
+
+The Eckert V projection.
+
+# d3.geoEckert6() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/eckert6.js), [Examples](https://observablehq.com/@d3/eckert-vi)
+ # d3.geoEckert6Raw
+
+[](https://observablehq.com/@d3/eckert-vi)
+
+The Eckert VI projection.
+
+# d3.geoEisenlohr() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/eisenlohr.js), [Examples](https://observablehq.com/@d3/eisenlohr)
+ # d3.geoEisenlohrRaw(lambda, phi)
+
+[](https://observablehq.com/@d3/eisenlohr)
+
+The Eisenlohr conformal projection.
+
+# d3.geoEquirectangular() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/equirectangular.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoEquirectangular), [Examples](https://observablehq.com/@d3/equirectangular)
+ # d3.geoEquirectangularRaw
+
+[](https://observablehq.com/@d3/equirectangular)
+
+The equirectangular (plate carrée) projection. The [Cassini projection](https://observablehq.com/@d3/cassini) is the transverse aspect of the equirectangular projection.
+
+# d3.geoFahey() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/fahey.js), [Examples](https://observablehq.com/@d3/fahey)
+ # d3.geoFaheyRaw
+
+[](https://observablehq.com/@d3/fahey)
+
+The Fahey pseudocylindrical projection.
+
+# d3.geoFoucaut() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/foucaut.js), [Examples](https://observablehq.com/@d3/foucaut)
+ # d3.geoFoucautRaw
+
+[](https://www.jasondavies.com/maps/foucaut/)
+
+Foucaut’s stereographic equivalent projection.
+
+# d3.geoFoucautSinusoidal() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/foucautSinusoidal.js), [Examples](https://observablehq.com/@d3/foucaut-sinusoidal)
+ # d3.geoFoucautSinusoidalRaw
+
+[](https://observablehq.com/@d3/foucaut-sinusoidal)
+
+Foucaut’s sinusoidal projection, an equal-area average of the sinusoidal and Lambert’s cylindrical projections.
+
+#foucautSinusoidal.alpha([alpha])
+
+Relative weight of the cylindrical projection. Defaults to 0.5.
+
+# d3.geoGilbert([type]) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/gilbert.js), [Examples](https://observablehq.com/@d3/gilbert)
+
+[](https://observablehq.com/@d3/gilbert)
+
+Gilbert’s two-world perspective projection. Wraps an instance of the specified projection *type*; if not specified, defaults to [d3.geoOrthographic](https://github.com/d3/d3-geo/blob/master/README.md#geoOrthographic).
+
+# d3.geoGingery() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/gingery.js), [Examples](https://observablehq.com/@d3/gingery)
+ # d3.geoGingeryRaw(rho, lobes)
+
+[](https://observablehq.com/@d3/gingery)
+
+The U.S.-centric Gingery world projection, as inspired by Cram’s Air Age. Note: requires clipping to the sphere.
+
+#gingery.radius([radius]) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/gingery.js)
+
+Defaults to 30°.
+
+#gingery.lobes([lobes]) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/gingery.js)
+
+Defaults to 6.
+
+# d3.geoGinzburg4() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/ginzburg4.js), [Examples](https://observablehq.com/@d3/ginzburg-iv)
+ # d3.geoGinzburg4Raw
+
+[](https://observablehq.com/@d3/ginzburg-iv)
+
+The Ginzburg IV projection.
+
+# d3.geoGinzburg5() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/ginzburg5.js), [Examples](https://observablehq.com/@d3/ginzburg-v)
+ # d3.geoGinzburg5Raw
+
+[](https://observablehq.com/@d3/ginzburg-v)
+
+The Ginzburg V projection.
+
+# d3.geoGinzburg6() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/ginzburg6.js), [Examples](https://observablehq.com/@d3/ginzburg-vi)
+ # d3.geoGinzburg6Raw
+
+[](https://observablehq.com/@d3/ginzburg-vi)
+
+The Ginzburg VI projection.
+
+# d3.geoGinzburg8() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/ginzburg8.js), [Examples](https://observablehq.com/@d3/ginzburg-viii)
+ # d3.geoGinzburg8Raw
+
+[](https://observablehq.com/@d3/ginzburg-viii)
+
+The Ginzburg VIII projection.
+
+# d3.geoGinzburg9() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/ginzburg9.js), [Examples](https://observablehq.com/@d3/ginzburg-ix)
+ # d3.geoGinzburg9Raw
+
+[](https://observablehq.com/@d3/ginzburg-ix)
+
+The Ginzburg IX projection.
+
+# d3.geoGnomonic() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/gnomonic.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoGnomonic), [Examples](https://observablehq.com/@d3/gnomonic)
+ # d3.geoGnomonicRaw
+
+[](https://observablehq.com/@d3/gnomonic)
+
+The gnomonic projection.
+
+# d3.geoGringorten() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/gringorten.js), [Examples](https://observablehq.com/@d3/gringorten)
+ # d3.geoGringortenRaw
+
+[](https://observablehq.com/@d3/gringorten)
+
+The Gringorten square equal-area projection, rearranged to give each hemisphere an entire square.
+
+# d3.geoGuyou() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/guyou.js), [Examples](https://observablehq.com/@d3/guyou)
+ # d3.geoGuyouRaw
+
+[](https://observablehq.com/@d3/guyou)
+
+The Guyou hemisphere-in-a-square projection. Peirce is credited with its [quincuncial form](#geoPeirceQuincuncial).
+
+# d3.geoHammer() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/hammer.js), [Examples](https://observablehq.com/@d3/hammer)
+ # d3.geoHammerRaw(A, B)
+
+[](https://observablehq.com/@d3/hammer)
+
+The Hammer projection. Depending the chosen coefficient and aspect, also known as [Eckert–Greifendorff](https://observablehq.com/@d3/hammer?b=4), [quartic authalic](https://observablehq.com/@d3/hammer?b=Infinity), and [Briesemeister](https://observablehq.com/@d3/briesemeister-projection).
+
+#hammer.coefficient([coefficient]) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/hammer.js)
+
+Defaults to 2.
+
+# d3.geoHammerRetroazimuthal() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/hammerRetroazimuthal.js), [Examples](https://observablehq.com/@d3/hammer-retroazimuthal)
+ # d3.geoHammerRetroazimuthalRaw(phi0)
+
+[](https://observablehq.com/@d3/hammer-retroazimuthal)
+
+The Hammer retroazimuthal projection. Note: requires clipping to the sphere.
+
+#hammerRetroazimuthal.parallel([parallel])
+
+Defaults to 45°.
+
+# d3.geoHealpix() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/healpix.js), [Examples](https://observablehq.com/@d3/healpix)
+ # d3.geoHealpixRaw(lobes)
+
+[](https://observablehq.com/@d3/healpix)
+
+The HEALPix projection: a Hierarchical Equal Area isoLatitude Pixelisation of a 2-sphere. In this implementation, the parameter *K* is fixed at 3. Note: requires clipping to the sphere.
+
+#healpix.lobes([lobes])
+
+If *lobes* is specified, sets the number of lobes (the parameter *H* in the literature) and returns this projection. If *lobes* is not specified, returns the current lobe number, which defaults to 4.
+
+# d3.geoHill() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/hill.js), [Examples](https://observablehq.com/@d3/hill-eucyclic)
+ # d3.geoHillRaw(K)
+
+[](https://observablehq.com/@d3/hill-eucyclic)
+
+Hill eucyclic projection is pseudoconic and equal-area.
+
+#hill.ratio([ratio])
+
+Defaults to 1. With a ratio of 0, this projection becomes the [Maurer No. 73](https://observablehq.com/@d3/hill-eucyclic?b=0). As it approaches ∞, the projection converges to the [Eckert IV](#geoEckert4).
+
+# d3.geoHomolosine() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/homolosine.js), [Examples](https://observablehq.com/@d3/goode-homolosine)
+ # d3.geoHomolosineRaw
+
+[](https://observablehq.com/@d3/goode-homolosine)
+
+The pseudocylindrical, equal-area Goode homolosine projection is normally presented in [interrupted form](#geoInterruptedHomolosine).
+
+# d3.geoHufnagel() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/hufnagel.js), [Examples](https://observablehq.com/@fil/hufnagel-projection)
+ # d3.geoHufnagelRaw
+
+[](https://observablehq.com/@fil/hufnagel-projection)
+
+A customizable family of pseudocylindrical equal-area projections by Herbert Hufnagel.
+
+#hufnagel.a([a])
+
+#hufnagel.b([b])
+
+#hufnagel.psiMax([psiMax])
+
+#hufnagel.ratio([ratio])
+
+# d3.geoHyperelliptical() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/hyperelliptical.js), [Examples](https://observablehq.com/@fil/toblers-hyperelliptical-projection)
+ # d3.geoHyperellipticalRaw
+
+[](https://observablehq.com/@fil/toblers-hyperelliptical-projection)
+
+Waldo R. Tobler’s hyperelliptical is a family of equal-area pseudocylindrical projections. Parameters include _k_, the exponent of the superellipse (or Lamé curve) that defines the shape of the meridians (default _k_ = 2.5); _alpha_, which governs the weight of the cylindrical projection that is averaged with the superellipse (default _alpha_ = 0); and _gamma_, that shapes the aspect ratio (default: _gamma_ = 1.183136).
+
+# d3.geoKavrayskiy7() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/kavrayskiy7.js), [Examples](https://observablehq.com/@d3/kavrayskiy-vii)
+ # d3.geoKavrayskiy7Raw
+
+[](https://observablehq.com/@d3/kavrayskiy-vii)
+
+The Kavrayskiy VII pseudocylindrical projection.
+
+# d3.geoLagrange() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/lagrange.js), [Examples](https://observablehq.com/@d3/lagrange)
+ # d3.geoLagrangeRaw(n)
+
+[](https://observablehq.com/@d3/lagrange)
+
+The Lagrange conformal projection.
+
+#lagrange.spacing([spacing])
+
+Defaults to 0.5.
+
+# d3.geoLarrivee() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/larrivee.js), [Examples](https://observablehq.com/@d3/larrivee)
+ # d3.geoLarriveeRaw
+
+[](https://observablehq.com/@d3/larrivee)
+
+The Larrivée projection.
+
+# d3.geoLaskowski() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/laskowski.js), [Examples](https://observablehq.com/@d3/laskowski-tri-optimal)
+ # d3.geoLaskowskiRaw
+
+[](https://observablehq.com/@d3/laskowski-tri-optimal)
+
+The Laskowski tri-optimal projection simultaneously minimizes distance, angular, and areal distortion.
+
+# d3.geoLittrow() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/littrow.js), [Examples](https://observablehq.com/@d3/littrow)
+ # d3.geoLittrowRaw
+
+[](https://observablehq.com/@d3/littrow)
+
+The Littrow projection is the only conformal retroazimuthal map projection. Typically clipped to the geographic extent [[-90°, -60°], [90°, 60°]].
+
+# d3.geoLoximuthal() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/loximuthal.js), [Examples](https://observablehq.com/@d3/loximuthal)
+ # d3.geoLoximuthalRaw(phi0)
+
+[](https://observablehq.com/@d3/loximuthal)
+
+The [loximuthal projection](https://en.wikipedia.org/wiki/Loximuthal_projection) is “characterized by the fact that loxodromes (rhumb lines) from one chosen central point (the intersection of the central meridian and central latitude) are shown as straight lines, correct in azimuth from the center, and are ‘true to scale’… It is neither an equal-area projection nor conformal.”
+
+#loximuthal.parallel([parallel])
+
+Defaults to 40°.
+
+# d3.geoMercator() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/mercator.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoMercator), [Examples](https://observablehq.com/@d3/mercator)
+ # d3.geoMercatorRaw
+
+[](https://observablehq.com/@d3/mercator)
+
+The spherical Mercator projection.
+
+# d3.geoMiller() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/miller.js), [Examples](https://observablehq.com/@d3/miller)
+ # d3.geoMillerRaw
+
+[](https://observablehq.com/@d3/miller)
+
+The Miller cylindrical projection is a modified [Mercator](#geoMercator) projection.
+
+# d3.geoModifiedStereographic(coefficients, rotate) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/modifiedStereographic.js)
+ # d3.geoModifiedStereographicRaw(coefficients)
+
+The family of [modified stereographic projections](https://www.jasondavies.com/maps/modified-stereographic/). The default [clip angle](https://github.com/d3/d3-geo/blob/master/README.md#projection_clipAngle) for these projections is 90°. These projections do not support [*projection*.rotate](https://github.com/d3/d3-geo/blob/master/README.md#projection_rotate): a fixed rotation is applied that is specific to the given *coefficients*.
+
+# d3.geoModifiedStereographicAlaska() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/modifiedStereographic.js)
+
+[](https://www.jasondavies.com/maps/modified-stereographic/alaska/)
+
+A [modified stereographic](#geoModifiedStereographic) projection for Alaska.
+
+# d3.geoModifiedStereographicGs48() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/modifiedStereographic.js)
+
+[](https://www.jasondavies.com/maps/modified-stereographic/gs48/)
+
+A [modified stereographic](#geoModifiedStereographic) projection for the conterminous United States.
+
+# d3.geoModifiedStereographicGs50() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/modifiedStereographic.js)
+
+[](https://www.jasondavies.com/maps/modified-stereographic/gs50/)
+
+A [modified stereographic](#geoModifiedStereographic) projection for the United States including Alaska and Hawaii. Typically clipped to the geographic extent [[-180°, 15°], [-50°, 75°]].
+
+# d3.geoModifiedStereographicMiller() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/modifiedStereographic.js), [Examples](https://observablehq.com/@d3/miller-oblated-stereographic)
+
+[](https://www.jasondavies.com/maps/modified-stereographic/miller/)
+
+A [modified stereographic](#geoModifiedStereographic) projection for Europe and Africa. Typically clipped to the geographic extent [[-40°, -40°], [80°, 80°]].
+
+# d3.geoModifiedStereographicLee() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/modifiedStereographic.js), [Examples](https://observablehq.com/@d3/lee-oblated-stereographic)
+
+[](https://www.jasondavies.com/maps/modified-stereographic/lee/)
+
+A [modified stereographic](#geoModifiedStereographic) projection for the Pacific ocean.
+
+# d3.geoMollweide() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/mollweide.js), [Examples](https://observablehq.com/@d3/mollweide)
+ # d3.geoMollweideRaw
+
+[](https://observablehq.com/@d3/mollweide)
+
+The equal-area, pseudocylindrical Mollweide projection. The oblique aspect is known as the [Atlantis projection](https://observablehq.com/@d3/atlantis). [Goode’s interrupted Mollweide](#interruptedMollweide) is also widely known.
+
+# d3.geoMtFlatPolarParabolic() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/mtFlatPolarParabolic.js), [Examples](https://observablehq.com/@d3/flat-polar-parabolic)
+ # d3.geoMtFlatPolarParabolicRaw
+
+[](https://observablehq.com/@d3/flat-polar-parabolic)
+
+The McBryde–Thomas flat-polar parabolic pseudocylindrical equal-area projection.
+
+# d3.geoMtFlatPolarQuartic() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/mtFlatPolarQuartic.js), [Examples](https://observablehq.com/@d3/flat-polar-quartic)
+ # d3.geoMtFlatPolarQuarticRaw
+
+[](https://observablehq.com/@d3/flat-polar-quartic)
+
+The McBryde–Thomas flat-polar quartic pseudocylindrical equal-area projection.
+
+# d3.geoMtFlatPolarSinusoidal() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/mtFlatPolarSinusoidal.js), [Examples](https://observablehq.com/@d3/flat-polar-sinusoidal)
+ # d3.geoMtFlatPolarSinusoidalRaw
+
+[](https://observablehq.com/@d3/flat-polar-sinusoidal)
+
+The McBryde–Thomas flat-polar sinusoidal equal-area projection.
+
+# d3.geoNaturalEarth1() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/naturalEarth1.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoNaturalEarth1), [Examples](https://observablehq.com/@d3/natural-earth)
+ # d3.geoNaturalEarth1Raw
+
+[](https://observablehq.com/@d3/natural-earth)
+
+The Natural Earth projection.
+
+# d3.geoNaturalEarth2() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/naturalEarth2.js), [Examples](https://observablehq.com/@d3/natural-earth-ii)
+ # d3.geoNaturalEarth2Raw
+
+[](https://observablehq.com/@d3/natural-earth-ii)
+
+The [Natural Earth II](http://www.shadedrelief.com/NE2_proj/) projection. Compared to [Natural Earth](#geoNaturalEarth), it is slightly taller and rounder.
+
+# d3.geoNellHammer() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/nellHammer.js), [Examples](https://observablehq.com/@d3/nell-hammer)
+ # d3.geoNellHammerRaw
+
+[](https://observablehq.com/@d3/nell-hammer)
+
+The Nell–Hammer projection.
+
+# d3.geoNicolosi() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/nicolosi.js), [Examples](https://observablehq.com/@toja/nicolosi-globular-projection)
+ # d3.geoNicolosiRaw
+
+[](https://observablehq.com/@toja/nicolosi-globular-projection)
+
+The Nicolosi globular projection.
+
+# d3.geoOrthographic() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/orthographic.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoOrthographic), [Examples](https://observablehq.com/@d3/orthographic)
+ # d3.geoOrthographicRaw
+
+[](https://observablehq.com/@d3/orthographic)
+
+The orthographic projection.
+
+# d3.geoPatterson() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/patterson.js), [Examples](https://observablehq.com/@d3/patterson-cylindrical)
+ # d3.geoPattersonRaw
+
+[](https://observablehq.com/@d3/patterson-cylindrical)
+
+The Patterson cylindrical projection.
+
+# d3.geoPolyconic() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/polyconic.js), [Examples](https://observablehq.com/@d3/polyconic)
+ # d3.geoPolyconicRaw
+
+[](https://observablehq.com/@d3/polyconic)
+
+The American polyconic projection.
+
+# d3.geoRectangularPolyconic() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/rectangularPolyconic.js), [Examples](https://observablehq.com/@d3/rectangular-polyconic)
+ # d3.geoRectangularPolyconicRaw(phi0)
+
+[](https://observablehq.com/@d3/rectangular-polyconic)
+
+The rectangular (War Office) polyconic projection.
+
+#rectangularPolyconic.parallel([parallel])
+
+Defaults to 0°.
+
+# d3.geoRobinson() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/robinson.js), [Examples](https://observablehq.com/@d3/robinson)
+ # d3.geoRobinsonRaw
+
+[](https://observablehq.com/@d3/robinson)
+
+The Robinson projection.
+
+# d3.geoSatellite() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/satellite.js), [Examples](https://observablehq.com/@d3/satellite)
+ # d3.geoSatelliteRaw(P, omega)
+
+[](https://observablehq.com/@d3/satellite)
+
+The satellite (tilted perspective) projection.
+
+#satellite.tilt([tilt])
+
+Defaults to 0°.
+
+#satellite.distance([distance])
+
+Distance from the center of the sphere to the point of view, as a proportion of the sphere’s radius; defaults to 2.0. The recommended maximum [clip angle](https://github.com/d3/d3-geo/blob/master/README.md#projection_clipAngle) for a given *distance* is acos(1 / *distance*) converted to degrees. If [tilt](#satellite_tilt) is also applied, then more conservative clipping may be necessary. For exact clipping, the in-development geographic projection pipeline is needed; see the [satellite explorer](https://observablehq.com/@d3/satellite-explorer).
+
+# d3.geoSinusoidal() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/sinusoidal.js), [Examples](https://observablehq.com/@d3/sinusoidal)
+ # d3.geoSinusoidalRaw
+
+[](https://observablehq.com/@d3/sinusoidal)
+
+The sinusoidal projection.
+
+# d3.geoSinuMollweide() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/sinuMollweide.js), [Examples](https://observablehq.com/@d3/sinu-mollweide)
+ # d3.geoSinuMollweideRaw
+
+[](https://observablehq.com/@d3/sinu-mollweide)
+
+Allen K. Philbrick’s Sinu-Mollweide projection. See also the [interrupted form](#interruptedSinuMollweide).
+
+# d3.geoStereographic() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/stereographic.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoStereographic), [Examples](https://observablehq.com/@d3/stereographic)
+ # d3.geoStereographicRaw
+
+[](https://observablehq.com/@d3/stereographic)
+
+The stereographic projection.
+
+# d3.geoTimes() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/times.js), [Examples](https://observablehq.com/@d3/times)
+ # d3.geoTimesRaw
+
+[](https://observablehq.com/@d3/times)
+
+John Muir’s Times projection.
+
+# d3.geoTransverseMercator() · [Source](https://github.com/d3/d3-geo/blob/master/src/projection/transverseMercator.js) [\[d3-geo\]](https://github.com/d3/d3-geo/blob/master/README.md#geoTransverseMercator), [Examples](https://observablehq.com/@d3/transverse-mercator)
+ # d3.geoTransverseMercatorRaw
+
+[](https://observablehq.com/@d3/transverse-mercator)
+
+The transverse spherical Mercator projection.
+
+# d3.geoTwoPointAzimuthal(point0, point1) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/twoPointAzimuthal.js)
+ # d3.geoTwoPointAzimuthalRaw(d)
+
+The two-point azimuthal projection “shows correct azimuths (but not distances) from either of two points to any other point. [It can] be used to locate a ship at sea, given the exact location of two radio transmitters and the direction of the ship to the transmitters.” This projection does not support [*projection*.rotate](https://github.com/d3/d3-geo/blob/master/README.md#projection_rotate), as the rotation is fixed by the two given points.
+
+# d3.geoTwoPointAzimuthalUsa() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/twoPointAzimuthal.js)
+
+[](https://www.jasondavies.com/maps/two-point-azimuthal/)
+
+The two-point azimuthal projection with points [-158°, 21.5°] and [-77°, 39°], approximately representing Honolulu, HI and Washington, D.C.
+
+# d3.geoTwoPointEquidistant(point0, point1) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/twoPointEquidistant.js)
+ # d3.geoTwoPointEquidistantRaw(z0)
+
+The two-point equidistant projection. This projection does not support [*projection*.rotate](https://github.com/d3/d3-geo/blob/master/README.md#projection_rotate), as the rotation is fixed by the two given points. Note: to show the whole Earth, this projection requires clipping to spherical polygons ([example](https://observablehq.com/@d3/two-point-equidistant)).
+
+# d3.geoTwoPointEquidistantUsa() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/twoPointEquidistant.js)
+
+[](https://www.jasondavies.com/maps/two-point-equidistant/)
+
+The two-point equidistant projection with points [-158°, 21.5°] and [-77°, 39°], approximately representing Honolulu, HI and Washington, D.C.
+
+# d3.geoVanDerGrinten() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/vanDerGrinten.js), [Examples](https://observablehq.com/@d3/van-der-grinten-i)
+ # d3.geoVanDerGrintenRaw
+
+[](https://observablehq.com/@d3/van-der-grinten-i)
+
+The Van der Grinten projection.
+
+# d3.geoVanDerGrinten2() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/vanDerGrinten2.js), [Examples](https://observablehq.com/@d3/van-der-grinten-ii)
+ # d3.geoVanDerGrinten2Raw
+
+[](https://observablehq.com/@d3/van-der-grinten-ii)
+
+The Van der Grinten II projection.
+
+# d3.geoVanDerGrinten3() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/vanDerGrinten3.js), [Examples](https://observablehq.com/@d3/van-der-grinten-iii)
+ # d3.geoVanDerGrinten3Raw
+
+[](https://observablehq.com/@d3/van-der-grinten-iii)
+
+The Van der Grinten III projection.
+
+# d3.geoVanDerGrinten4() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/vanDerGrinten4.js), [Examples](https://observablehq.com/@d3/van-der-grinten-iv)
+ # d3.geoVanDerGrinten4Raw
+
+[](https://observablehq.com/@d3/van-der-grinten-iv)
+
+The Van der Grinten IV projection.
+
+# d3.geoWagner() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/wagner.js), [Examples](https://observablehq.com/@fil/wagner-customizable-projection)
+ # d3.geoWagnerRaw
+
+[](https://map-projections.net/d3-customizable-wagner/)
+
+The Wagner projection is customizable: default values produce the Wagner VIII projection.
+
+#wagner.poleline([poleline])
+
+Defaults to 65°.
+
+#wagner.parallels([parallels])
+
+Defaults to 60°.
+
+#wagner.inflation([inflation])
+
+Defaults to 20.
+
+#wagner.ratio([ratio])
+
+Defaults to 200.
+
+# d3.geoWagner4() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/wagner4.js), [Examples](https://observablehq.com/@d3/wagner-iv)
+ # d3.geoWagner4Raw
+
+[](https://observablehq.com/@d3/wagner-iv)
+
+The Wagner IV projection, also known as Putniṇš P2´.
+
+# d3.geoWagner6() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/wagner6.js), [Examples](https://observablehq.com/@d3/wagner-vi)
+ # d3.geoWagner6Raw
+
+[](https://observablehq.com/@d3/wagner-vi)
+
+The Wagner VI projection.
+
+# d3.geoWagner7() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/wagner7.js), [Examples](ttps://observablehq.com/@d3/wagner-vii)
+
+[](https://observablehq.com/@d3/wagner-vii)
+
+The Wagner VII projection.
+
+# d3.geoWiechel() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/wiechel.js), [Examples](https://observablehq.com/@d3/wiechel)
+ # d3.geoWiechelRaw
+
+[](https://observablehq.com/@d3/wiechel)
+
+The Wiechel projection.
+
+# d3.geoWinkel3() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/winkel3.js), [Examples](https://observablehq.com/@d3/winkel-tripel)
+ # d3.geoWinkel3Raw
+
+[](https://observablehq.com/@d3/winkel-tripel)
+
+The Winkel tripel projection.
+
+### Interrupted Projections
+
+# d3.geoInterrupt(project, lobes) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/interrupted/index.js), [Examples](https://observablehq.com/@d3/interrupted-sinusoidal)
+
+Defines a new interrupted projection for the specified [raw projection](#raw-projections) function *project* and the specified array of *lobes*. The array *lobes* contains two elements representing the hemilobes for the northern hemisphere and the southern hemisphere, respectively. Each hemilobe is an array of triangles, with each triangle represented as three points (in degrees): the start, midpoint, and end. For example, the lobes in [Goode’s interrupted homolosine](#geoInterruptedHomolosine) projection are defined as:
+
+```json
+[
+ [
+ [[-180, 0], [-100, 90], [ -40, 0]],
+ [[ -40, 0], [ 30, 90], [ 180, 0]]
+ ],
+ [
+ [[-180, 0], [-160, -90], [-100, 0]],
+ [[-100, 0], [ -60, -90], [ -20, 0]],
+ [[ -20, 0], [ 20, -90], [ 80, 0]],
+ [[ 80, 0], [ 140, -90], [ 180, 0]]
+ ]
+]
+```
+
+Note: interrupted projections typically require clipping to the sphere.
+
+#interrupted.lobes([lobes]) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/interrupted/index.js)
+
+If *lobes* is specified, sets the new array of hemilobes and returns this projection; see [d3.geoInterrupt](#geoInterrupt) for details on the format of the hemilobes array. If *lobes* is not specified, returns the current array of hemilobes.
+
+# d3.geoInterruptedHomolosine() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/interrupted/homolosine.js), [Examples](https://observablehq.com/@d3/interrupted-goode-homolosine)
+
+[](https://observablehq.com/@d3/interrupted-goode-homolosine)
+
+Goode’s interrupted [homolosine projection](#geoHomolosine). Its [ocean-centric aspect](https://observablehq.com/@d3/interrupted-homolosine-oceans) is also well-known.
+
+# d3.geoInterruptedSinusoidal() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/interrupted/sinusoidal.js), [Examples](https://observablehq.com/@d3/interrupted-sinusoidal)
+
+[](https://observablehq.com/@d3/interrupted-sinusoidal)
+
+An interrupted [sinusoidal projection](#geoSinusoidal) with asymmetrical lobe boundaries that emphasize land masses over oceans, after the Swedish Nordisk Världs Atlas as reproduced by [C.A. Furuti](https://web.archive.org/web/20150928042327/http://www.progonos.com/furuti/MapProj/Normal/ProjInt/projInt.html#InterruptedSansonFlamsteed).
+
+# d3.geoInterruptedBoggs() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/interrupted/boggs.js), [Examples](https://observablehq.com/@d3/interrupted-boggs-eumorphic)
+
+[](https://observablehq.com/@d3/interrupted-boggs-eumorphic)
+
+Bogg’s interrupted [eumorphic projection](#geoBoggs).
+
+# d3.geoInterruptedSinuMollweide() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/interrupted/sinuMollweide.js), [Examples](https://observablehq.com/@d3/interrupted-sinu-mollweide)
+
+[](https://observablehq.com/@d3/interrupted-sinu-mollweide)
+
+Alan K. Philbrick’s interrupted [sinu-Mollweide projection](#geoSinuMollweide).
+
+# d3.geoInterruptedMollweide() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/interrupted/mollweide.js), [Examples](https://observablehq.com/@d3/interrupted-mollweide)
+
+[](https://observablehq.com/@d3/interrupted-mollweide)
+
+Goode’s interrupted [Mollweide projection](#geoMollweide).
+
+# d3.geoInterruptedMollweideHemispheres() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/interrupted/mollweideHemispheres.js), [Examples](https://observablehq.com/@d3/mollweide-hemispheres)
+
+[](https://observablehq.com/@d3/mollweide-hemispheres)
+
+The [Mollweide projection](#geoMollweide) interrupted into two (equal-area) hemispheres.
+
+# d3.geoInterruptedQuarticAuthalic() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/quarticAuthalic.js), [Examples](https://observablehq.com/@piwodlaiwo/interrupted-quartic-authalic-projection)
+
+[](https://observablehq.com/@piwodlaiwo/interrupted-quartic-authalic-projection)
+
+The [quartic authalic projection](https://observablehq.com/@d3/hammer?b=Infinity) interrupted into two hemispheres.
+
+### Polyhedral Projections
+
+# d3.geoPolyhedral(root, face) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/polyhedral/index.js)
+
+Defines a new polyhedral projection. The *root* is a spanning tree of polygon face nodes; each *node* is assigned a *node*.transform matrix. The *face* function returns the appropriate *node* for a given *lambda* and *phi* in radians. Use [*projection*.angle](https://github.com/d3/d3-geo/blob/master/README.md#projection_angle) to set the orientation of the map (the default *angle*, -30°, might change in the next major version).
+
+# d3.geoPolyhedralButterfly() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/polyhedral/butterfly.js), [Examples](https://observablehq.com/@d3/polyhedral-gnomonic)
+
+[](https://observablehq.com/@d3/polyhedral-gnomonic)
+
+The gnomonic butterfly projection.
+
+# d3.geoPolyhedralCollignon() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/polyhedral/collignon.js), [Examples](https://observablehq.com/@d3/polyhedral-collignon)
+
+[](https://www.jasondavies.com/maps/collignon-butterfly/)
+
+The Collignon butterfly projection.
+
+# d3.geoPolyhedralWaterman() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/polyhedral/waterman.js), [Examples](https://observablehq.com/@d3/watermans-butterfly)
+
+[](https://www.jasondavies.com/maps/waterman-butterfly/)
+
+Steve Waterman’s butterfly projection.
+
+### Quincuncial Projections
+
+# d3.geoQuincuncial(project) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/quincuncial/index.js)
+
+Defines a new quincuncial projection for the specified [raw projection](#raw-projections) function *project*. The default rotation is [-90°, -90°, 45°] and the default clip angle is 180° - ε.
+
+# d3.geoGringortenQuincuncial() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/quincuncial/gringorten.js)
+
+
+
+The Gringorten square equal-area projection.
+
+# d3.geoPeirceQuincuncial() · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/quincuncial/peirce.js)
+
+[](https://observablehq.com/@d3/peirce-quincuncial)
+
+The Peirce quincuncial projection is the quincuncial form of the [Guyou projection](#geoGuyou).
+
+### Transformations
+
+# d3.geoProject(object, projection) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/project/index.js)
+
+Projects the specified GeoJSON *object* using the specified *projection*, returning a shallow copy of the specified GeoJSON *object* with projected coordinates. Typically, the input coordinates are spherical and the output coordinates are planar, but the *projection* can also be an [arbitrary geometric transformation](https://github.com/d3/d3-geo/blob/master/README.md#transforms).
+
+See also [geoproject](#geoproject-bin).
+
+# d3.geoStitch(object) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/stitch.js)
+
+Returns a shallow copy of the specified GeoJSON *object*, removing antimeridian and polar cuts, and replacing straight Cartesian line segments with geodesic segments. The input *object* must have coordinates in longitude and latitude in decimal degrees per [RFC 7946](https://tools.ietf.org/html/rfc7946). [Antimeridian cutting](https://bl.ocks.org/mbostock/3788999), if needed, can then be re-applied after rotating to the desired projection aspect.
+
+See also [geostitch](#geostitch-bin).
+
+# d3.geoQuantize(object, digits) · [Source](https://github.com/d3/d3-geo-projection/blob/master/src/quantize.js)
+
+Returns a shallow copy of the specified GeoJSON *object*, rounding *x* and *y* coordinates according to [*number*.toFixed](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed). Typically this is done *after* [projecting](#geoProject).
+
+See also [geoproject --precision](#geoproject_precision) and [geo2svg --precision](#geo2svg_precision).
+
+## Command-Line Reference
+
+### geo2svg
+
+#geo2svg [options…] [file] · [Source](https://github.com/d3/d3-geo-projection/blob/master/bin/geo2svg)
+
+Converts the specified GeoJSON *file* to SVG. With [--newline-delimited](#geo2svg_newline_delimited), each input feature is rendered as a separate [path element](https://www.w3.org/TR/SVG/paths.html); otherwise, a single path element is generated.
+
+By default, the SVG’s [fill](#geo2svg_fill) is set to none and the [stroke](#geo2svg_stroke) is set to black. The default [point radius](https://github.com/d3/d3-geo/blob/master/README.md#path_pointRadius) is 4.5. To override these values on a per-feature basis, the following [GeoJSON feature](http://geojson.org/geojson-spec.html#feature-objects) properties will be propagated to attributes:
+
+* fill
+* fill-rule (or fillRule)
+* fill-opacity (or fillOpacity)
+* stroke
+* stroke-width (or strokeWidth)
+* stroke-linecap (or strokeLinecap)
+* stroke-linejoin (or strokeLinejoin)
+* stroke-miterlimit (or strokeMiterlimit)
+* stroke-dasharray (or strokeDasharray)
+* stroke-dashoffset (or strokeDashoffset)
+* stroke-opacity (or strokeOpacity)
+* point-radius (or pointRadius)
+
+If the feature has an id, the path element will have a corresponding id attribute. If the feature has a *title* property, the path element will have a title element with the corresponding value. For an example of per-feature attributes, see this [California population density map](https://bl.ocks.org/mbostock/fb6c1e5ff700f9713a9dc2f0fd392c35).
+
+Note: per-feature attributes are most useful in conjunction with [newline-delimited](#geo2svg_newline_delimited) input, as otherwise the generated SVG only has a single path element. To set these properties dynamically, pass the input through [ndjson-map](https://github.com/mbostock/ndjson-cli/blob/master/README.md#map).
+
+# geo2svg -h
+ # geo2svg --help
+
+Output usage information.
+
+# geo2svg -V
+ # geo2svg --version
+
+Output the version number.
+
+# geo2svg -ofile
+ # geo2svg --outfile
+
+Specify the output file name. Defaults to “-” for stdout.
+
+# geo2svg -wvalue
+ # geo2svg --widthvalue
+
+Specify the output width. Defaults to 960.
+
+# geo2svg -hvalue
+ # geo2svg --heightvalue
+
+Specify the output height. Defaults to 500.
+
+# geo2svg -pvalue
+ # geo2svg --precisionvalue
+
+Reduce the precision for smaller output files. Defaults to six digits after the decimal point. See also [d3.geoQuantize](#geoQuantize).
+
+# geo2svg --fillvalue
+
+Specify the default output fill color. Defaults to none.
+
+# geo2svg --strokevalue
+
+Specify the default output stroke color. Defaults to black.
+
+# geo2svg --rvalue
+ # geo2svg --radiusvalue
+
+Specify the default output point radius. Defaults to 4.5.
+
+# geo2svg -n
+ # geo2svg --newline-delimited
+
+Accept [newline-delimited JSON](http://ndjson.org/) as input, with one feature per line.
+
+### geograticule
+
+#geograticule [options…] · [Source](https://github.com/d3/d3-geo-projection/blob/master/bin/geograticule)
+
+Generates a GeoJSON graticule. See also [d3.geoGraticule](https://github.com/d3/d3-geo/blob/master/README.md#geoGraticule).
+
+# geograticule -h
+ # geograticule --help
+
+Output usage information.
+
+# geograticule -V
+ # geograticule --version
+
+Output the version number.
+
+# geograticule -ofile
+ # geograticule --outfile
+
+Specify the output file name. Defaults to “-” for stdout.
+
+# geograticule --extentvalue
+
+Sets the graticule’s [extent](https://github.com/d3/d3-geo/blob/master/README.md#graticule_extent).
+
+# geograticule --extent-minorvalue
+
+Sets the graticule’s [minor extent](https://github.com/d3/d3-geo/blob/master/README.md#graticule_extentMinor).
+
+# geograticule --extent-majorvalue
+
+Sets the graticule’s [major extent](https://github.com/d3/d3-geo/blob/master/README.md#graticule_extentMajor).
+
+# geograticule --stepvalue
+
+Sets the graticule’s [step](https://github.com/d3/d3-geo/blob/master/README.md#graticule_step).
+
+# geograticule --step-minorvalue
+
+Sets the graticule’s [minor step](https://github.com/d3/d3-geo/blob/master/README.md#graticule_stepMinor).
+
+# geograticule --step-majorvalue
+
+Sets the graticule’s [major setp](https://github.com/d3/d3-geo/blob/master/README.md#graticule_stepMajor).
+
+# geograticule --precisionvalue
+
+Sets the graticule’s [precision](https://github.com/d3/d3-geo/blob/master/README.md#graticule_precision).
+
+### geoproject
+
+#geoproject [options…] projection [file] · [Source](https://github.com/d3/d3-geo-projection/blob/master/bin/geoproject)
+
+Projects the GeoJSON object in the specified input *file* using the specified *projection*, outputting a new GeoJSON *object* with projected coordinates. For example, to project standard [WGS 84](https://en.wikipedia.org/wiki/World_Geodetic_System#A_new_World_Geodetic_System:_WGS_84) input using [d3.geoAlbersUsa](https://github.com/d3/d3-geo/blob/master/README.md#geoAlbersUsa):
+
+```bash
+geoproject 'd3.geoAlbersUsa()' us.json \
+ > us-albers.json
+```
+
+For geometry that crosses the antimeridian or surrounds a pole, you will want to pass input through [geostitch](#geostitch-bin) first:
+
+```bash
+geostitch world.json \
+ | geoproject 'd3.geoMercator()' \
+ > world-mercator.json
+```
+
+Typically, the input coordinates are spherical and the output coordinates are planar, but the *projection* can also be an [arbitrary geometric transformation](https://github.com/d3/d3-geo/blob/master/README.md#transforms). For example, to invert the *y*-axis of a standard [spatial reference system](https://en.wikipedia.org/wiki/Spatial_reference_system) such as [California Albers (EPSG:3310)](http://spatialreference.org/ref/epsg/nad83-california-albers/) and fit it to a 960×500 viewport:
+
+```bash
+shp2json planar.shp \
+ | geoproject 'd3.geoIdentity().reflectY(true).fitSize([960, 500], d)' \
+ > planar.json
+```
+
+See also [d3.geoProject](#geoProject) and [d3.geoIdentity](https://github.com/d3/d3-geo/blob/master/README.md#geoIdentity).
+
+# geoproject -h
+ # geoproject --help
+
+Output usage information.
+
+# geoproject -V
+ # geoproject --version
+
+Output the version number.
+
+# geoproject -ofile
+ # geoproject --outfile
+
+Specify the output file name. Defaults to “-” for stdout.
+
+# geoproject -pvalue
+ # geoproject --precisionvalue
+
+Reduce the precision for smaller output files. See also [d3.geoQuantize](#geoQuantize).
+
+# geoproject -n
+ # geoproject --newline-delimited
+
+Accept [newline-delimited JSON](http://ndjson.org/) as input, with one feature per line, and generate newline-delimited JSON as output.
+
+# geoproject -r[name=]value
+ # geoproject --require[name=]value
+
+Requires the specified *module*, making it available for use in any expressions used by this command. The loaded module is available as the symbol *name*. If *name* is not specified, it defaults to *module*. (If *module* is not a valid identifier, you must specify a *name*.) For example, to reproject the world on the [Airocean projection](https://github.com/d3/d3-geo-polygon/blob/master/README.md#geoAirocean):
+
+```bash
+geoproject --require d3=d3-geo-polygon 'd3.geoAirocean()' world.geojson
+```
+
+The required *module* is resolved relative to the [current working directory](https://nodejs.org/api/process.html#process_process_cwd). If the *module* is not found during normal resolution, the [global npm root](https://docs.npmjs.com/cli/root) is also searched, allowing you to require globally-installed modules from the command line.
+
+Multiple modules can be required by repeating this option.
+
+### geoquantize
+
+#geoquantize [options…] [file] · [Source](https://github.com/d3/d3-geo-projection/blob/master/bin/geoquantize)
+
+Reads the GeoJSON object from the specified input *file* and outputs a new GeoJSON *object* with coordinates reduced to *precision*. Same options as [geoproject](#geoproject).
+
+```bash
+geoquantize us.json --precision 3 \
+ > us-quantized.json
+```
+
+### geostitch
+
+#geostitch [options…] [file] · [Source](https://github.com/d3/d3-geo-projection/blob/master/bin/geostitch)
+
+Stitches the GeoJSON object in the specified input *file*, removing antimeridian and polar cuts, and replacing straight Cartesian line segments with geodesic segments. The input *object* must have coordinates in longitude and latitude in decimal degrees per [RFC 7946](https://tools.ietf.org/html/rfc7946). [Antimeridian cutting](https://bl.ocks.org/mbostock/3788999), if needed, can then be re-applied after rotating to the desired projection aspect.
+
+See [geoproject](#geoproject) for an example. See also [d3.geoStitch](#geoStitch).
+
+# geostitch -h
+ # geostitch --help
+
+Output usage information.
+
+# geostitch -V
+ # geostitch --version
+
+Output the version number.
+
+# geostitch -ofile
+ # geostitch --outfile
+
+Specify the output file name. Defaults to “-” for stdout.
+
+# geostitch -n
+ # geostitch --newline-delimited
+
+Accept [newline-delimited JSON](http://ndjson.org/) as input, with one feature per line, and generate newline-delimited JSON as output.
diff --git a/node_modules/d3-geo-projection/bin/geo2svg.js b/node_modules/d3-geo-projection/bin/geo2svg.js
new file mode 100644
index 000000000..ae82737f3
--- /dev/null
+++ b/node_modules/d3-geo-projection/bin/geo2svg.js
@@ -0,0 +1,96 @@
+#!/usr/bin/env node
+
+import {EOL} from "os";
+import {program} from "commander";
+import {geoPath} from "d3-geo";
+import {readFileSync} from "fs";
+import {dirname, resolve} from "path";
+import {fileURLToPath} from "url";
+import {geoQuantize} from "../src/index.js";
+import read from "./read.js";
+import write from "./write.js";
+
+const version = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../package.json"))).version;
+
+const options = program
+ .version(version)
+ .usage("[options] [file]")
+ .description("Convert GeoJSON to SVG.")
+ .option("-o, --out ", "output file name; defaults to “-” for stdout", "-")
+ .option("-w, --width ", "output width", 960)
+ .option("-h, --height ", "output height", 500)
+ .option("-p, --precision ", "number of output digits after the decimal point", 6)
+ .option("-n, --newline-delimited", "accept newline-delimited JSON")
+ .option("--fill ", "default fill", "none")
+ .option("--stroke ", "default stroke", "black")
+ .option("-r, --radius ", "default point radius", 4.5)
+ .parse(process.argv)
+ .opts();
+
+if (program.args.length === 0) program.args[0] = "-";
+else if (program.args.length !== 1) {
+ console.error();
+ console.error(" error: multiple input files");
+ console.error();
+ process.exit(1);
+}
+
+var reader = read(program.args[0], options.newlineDelimited, transform).then(end),
+ writer = write(options.out),
+ path = geoPath().pointRadius(function(d) { var p = d.properties, v; return p && (v = p["point-radius"] || p.pointRadius) != null ? v : options.radius; }),
+ render = options.precision == null ? path : function(d) { return path(geoQuantize(d, options.precision)); };
+
+reader.catch(error => {
+ console.error(error.stack);
+});
+
+writer.write("" + EOL
+ + "" + EOL
+ + "" + EOL
+ + "" + EOL);
+}
+
+function text(string) {
+ return string.replace(/[&<>]/g, function(character) {
+ switch (character) {
+ case "&": return "&";
+ case "<": return "<";
+ case ">": return ">";
+ }
+ });
+}
+
+function attr(string) {
+ return string.replace(/"/g, """);
+}
diff --git a/node_modules/d3-geo-projection/bin/geograticule.js b/node_modules/d3-geo-projection/bin/geograticule.js
new file mode 100644
index 000000000..3309d641e
--- /dev/null
+++ b/node_modules/d3-geo-projection/bin/geograticule.js
@@ -0,0 +1,63 @@
+#!/usr/bin/env node
+
+import {program} from "commander";
+import {geoGraticule} from "d3-geo";
+import {readFileSync} from "fs";
+import {dirname, resolve} from "path";
+import {fileURLToPath} from "url";
+import write from "./write.js";
+
+const version = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../package.json"))).version;
+
+const graticule = geoGraticule();
+
+const options = program
+ .version(version)
+ .usage("[options]")
+ .description("Generate a GeoJSON graticule.")
+ .option("-o, --out ", "output file name; defaults to “-” for stdout", "-")
+ .option("--extent ", "the major and minor extent", parseExtent)
+ .option("--extent-minor ", "the minor extent; defaults to " + graticule.extentMajor(), parseExtent)
+ .option("--extent-major ", "the major extent; defaults to " + graticule.extentMinor(), parseExtent)
+ .option("--step ", "the major and minor step", parseStep)
+ .option("--step-minor ", "the minor step; defaults to " + graticule.stepMinor(), parseStep)
+ .option("--step-major ", "the major step; defaults to " + graticule.stepMajor(), parseStep)
+ .option("--precision ", "the precision; defaults to " + graticule.precision(), graticule.precision)
+ .parse(process.argv)
+ .opts();
+
+if (program.args.length !== 0) {
+ console.error();
+ console.error(" error: unexpected arguments");
+ console.error();
+ process.exit(1);
+}
+
+if (options.extent != null) {
+ if (options.extentMinor == null) options.extentMinor = options.extent;
+ if (options.extentMajor == null) options.extentMajor = options.extent;
+}
+if (options.step != null) {
+ if (options.stepMinor == null) options.stepMinor = options.step;
+ if (options.stepMajor == null) options.stepMajor = options.step;
+}
+if (options.extentMinor != null) graticule.extentMinor(options.extentMinor);
+if (options.extentMajor != null) graticule.extentMajor(options.extentMajor);
+if (options.stepMinor != null) graticule.stepMinor(options.stepMinor);
+if (options.stepMajor != null) graticule.stepMajor(options.stepMajor);
+
+var writer = write(options.out);
+writer.write(JSON.stringify(graticule()) + "\n");
+writer.end().catch(abort);
+
+function parseStep(x) {
+ return x = x.split(","), x.length === 1 ? [+x[0], +x[0]] : [+x[0], +x[1]];
+}
+
+function parseExtent(x) {
+ return x = x.split(","), [[+x[0], +x[1]], [+x[2], +x[3]]];
+}
+
+function abort(error) {
+ console.error(error.stack);
+}
diff --git a/node_modules/d3-geo-projection/bin/geoproject.js b/node_modules/d3-geo-projection/bin/geoproject.js
new file mode 100644
index 000000000..e71b980be
--- /dev/null
+++ b/node_modules/d3-geo-projection/bin/geoproject.js
@@ -0,0 +1,74 @@
+#!/usr/bin/env node
+
+import {program} from "commander";
+import {readFileSync} from "fs";
+import {dirname, resolve} from "path";
+import {fileURLToPath} from "url";
+import {createContext, Script} from "vm";
+import * as d3Geo from "d3-geo";
+import * as d3GeoProjection from "../src/index.js";
+import {geoProject} from "../src/index.js";
+import read from "./read.js";
+import write from "./write.js";
+
+const version = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../package.json"))).version;
+
+const d3 = {...d3Geo, ...d3GeoProjection};
+
+const options = program
+ .version(version)
+ .usage("[options] [file]")
+ .description("Transform GeoJSON, such as to project from spherical to planar coordinates.")
+ .option("-o, --out ", "output file name; defaults to “-” for stdout", "-")
+ .option("-p, --precision ", "number of output digits after the decimal point")
+ .option("-n, --newline-delimited", "use newline-delimited JSON")
+ .option("-r, --require <[name=]module>", "require (import) a module", require, [])
+ .parse(process.argv)
+ .opts();
+
+if (program.args.length < 1) {
+ console.error();
+ console.error(" error: missing projection");
+ console.error();
+ process.exit(1);
+} else if (program.args.length > 2) {
+ console.error();
+ console.error(" error: multiple input files");
+ console.error();
+ process.exit(1);
+} else if (program.args.length === 1) {
+ program.args.push("-");
+}
+
+var reader = projection().then(project => read(program.args[1], options.newlineDelimited, project)).then(end),
+ writer = write(options.out);
+
+reader.catch(error => {
+ console.error(error.stack);
+});
+
+async function projection() {
+ const sandbox = {d3, d: undefined, i: undefined};
+ for (const [name, module] of await Promise.all(options.require)) {
+ sandbox[name] = sandbox[name] ? {...sandbox[name], ...module} : module;
+ }
+ const context = createContext(sandbox);
+ const projection = new Script("(" + program.args[0] + ")");
+ return function project(d, i) {
+ sandbox.d = d, sandbox.i = i;
+ d = geoProject(d, projection.runInContext(context));
+ if (options.precision != null) d = geoQuantize(d, options.precision);
+ return writer.write(JSON.stringify(d) + "\n");
+ };
+}
+
+function end() {
+ return writer.end();
+}
+
+function require(module, requires) {
+ var i = module.indexOf("="), name = module;
+ if (i >= 0) name = module.slice(0, i), module = module.slice(i + 1);
+ requires.push(import(module).then(module => [name, module]));
+ return requires;
+}
diff --git a/node_modules/d3-geo-projection/bin/geoquantize.js b/node_modules/d3-geo-projection/bin/geoquantize.js
new file mode 100644
index 000000000..f0952c934
--- /dev/null
+++ b/node_modules/d3-geo-projection/bin/geoquantize.js
@@ -0,0 +1,46 @@
+#!/usr/bin/env node
+
+import {program} from "commander";
+import {readFileSync} from "fs";
+import {dirname, resolve} from "path";
+import {fileURLToPath} from "url";
+import {geoQuantize} from "../src/index.js";
+import read from "./read.js";
+import write from "./write.js";
+
+const version = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../package.json"))).version;
+
+const options = program
+ .version(version)
+ .usage("[options] [file]")
+ .description("Quantize GeoJSON.")
+ .option("-o, --out ", "output file name; defaults to “-” for stdout", "-")
+ .option("-p, --precision ", "number of output digits after the decimal point")
+ .option("-n, --newline-delimited", "use newline-delimited JSON")
+ .parse(process.argv)
+ .opts();
+
+if (program.args.length > 1) {
+ console.error();
+ console.error(" error: multiple input files");
+ console.error();
+ process.exit(1);
+} else if (program.args.length === 0) {
+ program.args.push("-");
+}
+
+var reader = read(program.args[0], options.newlineDelimited, quantize).then(end),
+ writer = write(options.out);
+
+reader.catch(error => {
+ console.error(error.stack);
+});
+
+function quantize(d, i) {
+ if (options.precision != null) d = geoQuantize(d, options.precision);
+ return writer.write(JSON.stringify(d) + "\n");
+}
+
+function end() {
+ return writer.end();
+}
diff --git a/node_modules/d3-geo-projection/bin/geostitch.js b/node_modules/d3-geo-projection/bin/geostitch.js
new file mode 100644
index 000000000..cd711bc78
--- /dev/null
+++ b/node_modules/d3-geo-projection/bin/geostitch.js
@@ -0,0 +1,43 @@
+#!/usr/bin/env node
+
+import {program} from "commander";
+import {readFileSync} from "fs";
+import {dirname, resolve} from "path";
+import {fileURLToPath} from "url";
+import {geoStitch} from "../src/index.js";
+import read from "./read.js";
+import write from "./write.js";
+
+const version = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../package.json"))).version;
+
+const options = program
+ .version(version)
+ .usage("[options] [file]")
+ .description("Stitch equirectangular GeoJSON in degrees, removing antimeridian and polar cuts.")
+ .option("-o, --out ", "output file name; defaults to “-” for stdout", "-")
+ .option("-n, --newline-delimited", "use newline-delimited JSON")
+ .parse(process.argv)
+ .opts();
+
+if (program.args.length === 0) program.args[0] = "-";
+else if (program.args.length !== 1) {
+ console.error();
+ console.error(" error: multiple input files");
+ console.error();
+ process.exit(1);
+}
+
+var reader = read(program.args[0], options.newlineDelimited, stitch).then(end),
+ writer = write(options.out);
+
+reader.catch(error => {
+ console.error(error.stack);
+});
+
+function stitch(d) {
+ return writer.write(JSON.stringify(geoStitch(d)) + "\n");
+}
+
+function end() {
+ return writer.end();
+}
diff --git a/node_modules/d3-geo-projection/bin/read.js b/node_modules/d3-geo-projection/bin/read.js
new file mode 100644
index 000000000..e5cc20f89
--- /dev/null
+++ b/node_modules/d3-geo-projection/bin/read.js
@@ -0,0 +1,39 @@
+import {createReadStream} from "fs";
+import {createInterface} from "readline";
+
+export default function(file, newlineDelimited, callback) {
+ var index = -1,
+ input = file === "-" ? process.stdin : createReadStream(file);
+
+ function readObject() {
+ return new Promise(function(resolve, reject) {
+ var data = [];
+ input
+ .on("data", function(d) { data.push(d); })
+ .on("end", function() { resolve(JSON.parse(Buffer.concat(data))); })
+ .on("error", reject);
+ });
+ }
+
+ function readNewlineDelimitedObjects() {
+ return new Promise(function(resolve, reject) {
+ var queue = Promise.resolve();
+ createInterface({
+ input: input,
+ output: null
+ }).on("line", function(line) {
+ queue = queue.then(function() { return callbackObject(JSON.parse(line)); });
+ }).on("close", function() {
+ queue.then(function() { resolve(); }, reject);
+ }).on("error", reject);
+ });
+ }
+
+ function callbackObject(object) {
+ return callback(object, ++index);
+ }
+
+ return newlineDelimited
+ ? readNewlineDelimitedObjects()
+ : readObject().then(callbackObject);
+}
diff --git a/node_modules/d3-geo-projection/bin/write.js b/node_modules/d3-geo-projection/bin/write.js
new file mode 100644
index 000000000..8ba147405
--- /dev/null
+++ b/node_modules/d3-geo-projection/bin/write.js
@@ -0,0 +1,35 @@
+import {createWriteStream} from "fs"
+
+function handleEpipe(error) {
+ if (error.code === "EPIPE" || error.errno === "EPIPE") {
+ process.exit(0);
+ }
+}
+
+export default function(file) {
+ var output = (file === "-" ? process.stdout : createWriteStream(file)).on("error", handleEpipe),
+ queue = Promise.resolve();
+ return {
+ write: function(data) {
+ return queue = queue.then(function() {
+ return new Promise(function(resolve, reject) {
+ output.write(data, function(error) {
+ if (error) reject(error);
+ else resolve();
+ });
+ });
+ });
+ },
+ end: function() {
+ if (output === process.stdout) return queue;
+ return queue = queue.then(function() {
+ return new Promise(function(resolve, reject) {
+ output.end(function(error) {
+ if (error) reject(error);
+ else resolve();
+ });
+ });
+ });
+ }
+ };
+}
diff --git a/node_modules/d3-geo-projection/dist/d3-geo-projection.js b/node_modules/d3-geo-projection/dist/d3-geo-projection.js
new file mode 100644
index 000000000..ac513abaf
--- /dev/null
+++ b/node_modules/d3-geo-projection/dist/d3-geo-projection.js
@@ -0,0 +1,5003 @@
+// https://d3js.org/d3-geo-projection/ v4.0.0 Copyright 2013-2021 Mike Bostock, 2015 Ricky Reusser
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-geo'), require('d3-array')) :
+typeof define === 'function' && define.amd ? define(['exports', 'd3-geo', 'd3-array'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3));
+}(this, (function (exports, d3Geo, d3Array) { 'use strict';
+
+var abs = Math.abs;
+var atan = Math.atan;
+var atan2 = Math.atan2;
+var cos = Math.cos;
+var exp = Math.exp;
+var floor = Math.floor;
+var log = Math.log;
+var max = Math.max;
+var min = Math.min;
+var pow = Math.pow;
+var round = Math.round;
+var sign = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
+var sin = Math.sin;
+var tan = Math.tan;
+
+var epsilon$1 = 1e-6;
+var epsilon2 = 1e-12;
+var pi = Math.PI;
+var halfPi = pi / 2;
+var quarterPi = pi / 4;
+var sqrt1_2 = Math.SQRT1_2;
+var sqrt2 = sqrt(2);
+var sqrtPi = sqrt(pi);
+var tau = pi * 2;
+var degrees = 180 / pi;
+var radians = pi / 180;
+
+function sinci(x) {
+ return x ? x / Math.sin(x) : 1;
+}
+
+function asin(x) {
+ return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
+}
+
+function acos(x) {
+ return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
+}
+
+function sqrt(x) {
+ return x > 0 ? Math.sqrt(x) : 0;
+}
+
+function tanh(x) {
+ x = exp(2 * x);
+ return (x - 1) / (x + 1);
+}
+
+function sinh(x) {
+ return (exp(x) - exp(-x)) / 2;
+}
+
+function cosh(x) {
+ return (exp(x) + exp(-x)) / 2;
+}
+
+function arsinh(x) {
+ return log(x + sqrt(x * x + 1));
+}
+
+function arcosh(x) {
+ return log(x + sqrt(x * x - 1));
+}
+
+function airyRaw(beta) {
+ var tanBeta_2 = tan(beta / 2),
+ b = 2 * log(cos(beta / 2)) / (tanBeta_2 * tanBeta_2);
+
+ function forward(x, y) {
+ var cosx = cos(x),
+ cosy = cos(y),
+ siny = sin(y),
+ cosz = cosy * cosx,
+ k = -((1 - cosz ? log((1 + cosz) / 2) / (1 - cosz) : -0.5) + b / (1 + cosz));
+ return [k * cosy * sin(x), k * siny];
+ }
+
+ forward.invert = function(x, y) {
+ var r = sqrt(x * x + y * y),
+ z = -beta / 2,
+ i = 50, delta;
+ if (!r) return [0, 0];
+ do {
+ var z_2 = z / 2,
+ cosz_2 = cos(z_2),
+ sinz_2 = sin(z_2),
+ tanz_2 = sinz_2 / cosz_2,
+ lnsecz_2 = -log(abs(cosz_2));
+ z -= delta = (2 / tanz_2 * lnsecz_2 - b * tanz_2 - r) / (-lnsecz_2 / (sinz_2 * sinz_2) + 1 - b / (2 * cosz_2 * cosz_2)) * (cosz_2 < 0 ? 0.7 : 1);
+ } while (abs(delta) > epsilon$1 && --i > 0);
+ var sinz = sin(z);
+ return [atan2(x * sinz, r * cos(z)), asin(y * sinz / r)];
+ };
+
+ return forward;
+}
+
+function airy() {
+ var beta = halfPi,
+ m = d3Geo.geoProjectionMutator(airyRaw),
+ p = m(beta);
+
+ p.radius = function(_) {
+ return arguments.length ? m(beta = _ * radians) : beta * degrees;
+ };
+
+ return p
+ .scale(179.976)
+ .clipAngle(147);
+}
+
+function aitoffRaw(x, y) {
+ var cosy = cos(y), sincia = sinci(acos(cosy * cos(x /= 2)));
+ return [2 * cosy * sin(x) * sincia, sin(y) * sincia];
+}
+
+// Abort if [x, y] is not within an ellipse centered at [0, 0] with
+// semi-major axis pi and semi-minor axis pi/2.
+aitoffRaw.invert = function(x, y) {
+ if (x * x + 4 * y * y > pi * pi + epsilon$1) return;
+ var x1 = x, y1 = y, i = 25;
+ do {
+ var sinx = sin(x1),
+ sinx_2 = sin(x1 / 2),
+ cosx_2 = cos(x1 / 2),
+ siny = sin(y1),
+ cosy = cos(y1),
+ sin_2y = sin(2 * y1),
+ sin2y = siny * siny,
+ cos2y = cosy * cosy,
+ sin2x_2 = sinx_2 * sinx_2,
+ c = 1 - cos2y * cosx_2 * cosx_2,
+ e = c ? acos(cosy * cosx_2) * sqrt(f = 1 / c) : f = 0,
+ f,
+ fx = 2 * e * cosy * sinx_2 - x,
+ fy = e * siny - y,
+ dxdx = f * (cos2y * sin2x_2 + e * cosy * cosx_2 * sin2y),
+ dxdy = f * (0.5 * sinx * sin_2y - e * 2 * siny * sinx_2),
+ dydx = f * 0.25 * (sin_2y * sinx_2 - e * siny * cos2y * sinx),
+ dydy = f * (sin2y * cosx_2 + e * sin2x_2 * cosy),
+ z = dxdy * dydx - dydy * dxdx;
+ if (!z) break;
+ var dx = (fy * dxdy - fx * dydy) / z,
+ dy = (fx * dydx - fy * dxdx) / z;
+ x1 -= dx, y1 -= dy;
+ } while ((abs(dx) > epsilon$1 || abs(dy) > epsilon$1) && --i > 0);
+ return [x1, y1];
+};
+
+function aitoff() {
+ return d3Geo.geoProjection(aitoffRaw)
+ .scale(152.63);
+}
+
+function armadilloRaw(phi0) {
+ var sinPhi0 = sin(phi0),
+ cosPhi0 = cos(phi0),
+ sPhi0 = phi0 >= 0 ? 1 : -1,
+ tanPhi0 = tan(sPhi0 * phi0),
+ k = (1 + sinPhi0 - cosPhi0) / 2;
+
+ function forward(lambda, phi) {
+ var cosPhi = cos(phi),
+ cosLambda = cos(lambda /= 2);
+ return [
+ (1 + cosPhi) * sin(lambda),
+ (sPhi0 * phi > -atan2(cosLambda, tanPhi0) - 1e-3 ? 0 : -sPhi0 * 10) + k + sin(phi) * cosPhi0 - (1 + cosPhi) * sinPhi0 * cosLambda // TODO D3 core should allow null or [NaN, NaN] to be returned.
+ ];
+ }
+
+ forward.invert = function(x, y) {
+ var lambda = 0,
+ phi = 0,
+ i = 50;
+ do {
+ var cosLambda = cos(lambda),
+ sinLambda = sin(lambda),
+ cosPhi = cos(phi),
+ sinPhi = sin(phi),
+ A = 1 + cosPhi,
+ fx = A * sinLambda - x,
+ fy = k + sinPhi * cosPhi0 - A * sinPhi0 * cosLambda - y,
+ dxdLambda = A * cosLambda / 2,
+ dxdPhi = -sinLambda * sinPhi,
+ dydLambda = sinPhi0 * A * sinLambda / 2,
+ dydPhi = cosPhi0 * cosPhi + sinPhi0 * cosLambda * sinPhi,
+ denominator = dxdPhi * dydLambda - dydPhi * dxdLambda,
+ dLambda = (fy * dxdPhi - fx * dydPhi) / denominator / 2,
+ dPhi = (fx * dydLambda - fy * dxdLambda) / denominator;
+ if (abs(dPhi) > 2) dPhi /= 2;
+ lambda -= dLambda, phi -= dPhi;
+ } while ((abs(dLambda) > epsilon$1 || abs(dPhi) > epsilon$1) && --i > 0);
+ return sPhi0 * phi > -atan2(cos(lambda), tanPhi0) - 1e-3 ? [lambda * 2, phi] : null;
+ };
+
+ return forward;
+}
+
+function armadillo() {
+ var phi0 = 20 * radians,
+ sPhi0 = phi0 >= 0 ? 1 : -1,
+ tanPhi0 = tan(sPhi0 * phi0),
+ m = d3Geo.geoProjectionMutator(armadilloRaw),
+ p = m(phi0),
+ stream_ = p.stream;
+
+ p.parallel = function(_) {
+ if (!arguments.length) return phi0 * degrees;
+ tanPhi0 = tan((sPhi0 = (phi0 = _ * radians) >= 0 ? 1 : -1) * phi0);
+ return m(phi0);
+ };
+
+ p.stream = function(stream) {
+ var rotate = p.rotate(),
+ rotateStream = stream_(stream),
+ sphereStream = (p.rotate([0, 0]), stream_(stream)),
+ precision = p.precision();
+ p.rotate(rotate);
+ rotateStream.sphere = function() {
+ sphereStream.polygonStart(), sphereStream.lineStart();
+ for (var lambda = sPhi0 * -180; sPhi0 * lambda < 180; lambda += sPhi0 * 90)
+ sphereStream.point(lambda, sPhi0 * 90);
+ if (phi0) while (sPhi0 * (lambda -= 3 * sPhi0 * precision) >= -180) {
+ sphereStream.point(lambda, sPhi0 * -atan2(cos(lambda * radians / 2), tanPhi0) * degrees);
+ }
+ sphereStream.lineEnd(), sphereStream.polygonEnd();
+ };
+ return rotateStream;
+ };
+
+ return p
+ .scale(218.695)
+ .center([0, 28.0974]);
+}
+
+function augustRaw(lambda, phi) {
+ var tanPhi = tan(phi / 2),
+ k = sqrt(1 - tanPhi * tanPhi),
+ c = 1 + k * cos(lambda /= 2),
+ x = sin(lambda) * k / c,
+ y = tanPhi / c,
+ x2 = x * x,
+ y2 = y * y;
+ return [
+ 4 / 3 * x * (3 + x2 - 3 * y2),
+ 4 / 3 * y * (3 + 3 * x2 - y2)
+ ];
+}
+
+augustRaw.invert = function(x, y) {
+ x *= 3 / 8, y *= 3 / 8;
+ if (!x && abs(y) > 1) return null;
+ var x2 = x * x,
+ y2 = y * y,
+ s = 1 + x2 + y2,
+ sin3Eta = sqrt((s - sqrt(s * s - 4 * y * y)) / 2),
+ eta = asin(sin3Eta) / 3,
+ xi = sin3Eta ? arcosh(abs(y / sin3Eta)) / 3 : arsinh(abs(x)) / 3,
+ cosEta = cos(eta),
+ coshXi = cosh(xi),
+ d = coshXi * coshXi - cosEta * cosEta;
+ return [
+ sign(x) * 2 * atan2(sinh(xi) * cosEta, 0.25 - d),
+ sign(y) * 2 * atan2(coshXi * sin(eta), 0.25 + d)
+ ];
+};
+
+function august() {
+ return d3Geo.geoProjection(augustRaw)
+ .scale(66.1603);
+}
+
+var sqrt8 = sqrt(8),
+ phi0 = log(1 + sqrt2);
+
+function bakerRaw(lambda, phi) {
+ var phi0 = abs(phi);
+ return phi0 < quarterPi
+ ? [lambda, log(tan(quarterPi + phi / 2))]
+ : [lambda * cos(phi0) * (2 * sqrt2 - 1 / sin(phi0)), sign(phi) * (2 * sqrt2 * (phi0 - quarterPi) - log(tan(phi0 / 2)))];
+}
+
+bakerRaw.invert = function(x, y) {
+ if ((y0 = abs(y)) < phi0) return [x, 2 * atan(exp(y)) - halfPi];
+ var phi = quarterPi, i = 25, delta, y0;
+ do {
+ var cosPhi_2 = cos(phi / 2), tanPhi_2 = tan(phi / 2);
+ phi -= delta = (sqrt8 * (phi - quarterPi) - log(tanPhi_2) - y0) / (sqrt8 - cosPhi_2 * cosPhi_2 / (2 * tanPhi_2));
+ } while (abs(delta) > epsilon2 && --i > 0);
+ return [x / (cos(phi) * (sqrt8 - 1 / sin(phi))), sign(y) * phi];
+};
+
+function baker() {
+ return d3Geo.geoProjection(bakerRaw)
+ .scale(112.314);
+}
+
+function berghausRaw(lobes) {
+ var k = 2 * pi / lobes;
+
+ function forward(lambda, phi) {
+ var p = d3Geo.geoAzimuthalEquidistantRaw(lambda, phi);
+ if (abs(lambda) > halfPi) { // back hemisphere
+ var theta = atan2(p[1], p[0]),
+ r = sqrt(p[0] * p[0] + p[1] * p[1]),
+ theta0 = k * round((theta - halfPi) / k) + halfPi,
+ alpha = atan2(sin(theta -= theta0), 2 - cos(theta)); // angle relative to lobe end
+ theta = theta0 + asin(pi / r * sin(alpha)) - alpha;
+ p[0] = r * cos(theta);
+ p[1] = r * sin(theta);
+ }
+ return p;
+ }
+
+ forward.invert = function(x, y) {
+ var r = sqrt(x * x + y * y);
+ if (r > halfPi) {
+ var theta = atan2(y, x),
+ theta0 = k * round((theta - halfPi) / k) + halfPi,
+ s = theta > theta0 ? -1 : 1,
+ A = r * cos(theta0 - theta),
+ cotAlpha = 1 / tan(s * acos((A - pi) / sqrt(pi * (pi - 2 * A) + r * r)));
+ theta = theta0 + 2 * atan((cotAlpha + s * sqrt(cotAlpha * cotAlpha - 3)) / 3);
+ x = r * cos(theta), y = r * sin(theta);
+ }
+ return d3Geo.geoAzimuthalEquidistantRaw.invert(x, y);
+ };
+
+ return forward;
+}
+
+function berghaus() {
+ var lobes = 5,
+ m = d3Geo.geoProjectionMutator(berghausRaw),
+ p = m(lobes),
+ projectionStream = p.stream,
+ epsilon = 1e-2,
+ cr = -cos(epsilon * radians),
+ sr = sin(epsilon * radians);
+
+ p.lobes = function(_) {
+ return arguments.length ? m(lobes = +_) : lobes;
+ };
+
+ p.stream = function(stream) {
+ var rotate = p.rotate(),
+ rotateStream = projectionStream(stream),
+ sphereStream = (p.rotate([0, 0]), projectionStream(stream));
+ p.rotate(rotate);
+ rotateStream.sphere = function() {
+ sphereStream.polygonStart(), sphereStream.lineStart();
+ for (var i = 0, delta = 360 / lobes, delta0 = 2 * pi / lobes, phi = 90 - 180 / lobes, phi0 = halfPi; i < lobes; ++i, phi -= delta, phi0 -= delta0) {
+ sphereStream.point(atan2(sr * cos(phi0), cr) * degrees, asin(sr * sin(phi0)) * degrees);
+ if (phi < -90) {
+ sphereStream.point(-90, -180 - phi - epsilon);
+ sphereStream.point(-90, -180 - phi + epsilon);
+ } else {
+ sphereStream.point(90, phi + epsilon);
+ sphereStream.point(90, phi - epsilon);
+ }
+ }
+ sphereStream.lineEnd(), sphereStream.polygonEnd();
+ };
+ return rotateStream;
+ };
+
+ return p
+ .scale(87.8076)
+ .center([0, 17.1875])
+ .clipAngle(180 - 1e-3);
+}
+
+function hammerRaw(A, B) {
+ if (arguments.length < 2) B = A;
+ if (B === 1) return d3Geo.geoAzimuthalEqualAreaRaw;
+ if (B === Infinity) return hammerQuarticAuthalicRaw;
+
+ function forward(lambda, phi) {
+ var coordinates = d3Geo.geoAzimuthalEqualAreaRaw(lambda / B, phi);
+ coordinates[0] *= A;
+ return coordinates;
+ }
+
+ forward.invert = function(x, y) {
+ var coordinates = d3Geo.geoAzimuthalEqualAreaRaw.invert(x / A, y);
+ coordinates[0] *= B;
+ return coordinates;
+ };
+
+ return forward;
+}
+
+function hammerQuarticAuthalicRaw(lambda, phi) {
+ return [
+ lambda * cos(phi) / cos(phi /= 2),
+ 2 * sin(phi)
+ ];
+}
+
+hammerQuarticAuthalicRaw.invert = function(x, y) {
+ var phi = 2 * asin(y / 2);
+ return [
+ x * cos(phi / 2) / cos(phi),
+ phi
+ ];
+};
+
+function hammer() {
+ var B = 2,
+ m = d3Geo.geoProjectionMutator(hammerRaw),
+ p = m(B);
+
+ p.coefficient = function(_) {
+ if (!arguments.length) return B;
+ return m(B = +_);
+ };
+
+ return p
+ .scale(169.529);
+}
+
+// Approximate Newton-Raphson
+// Solve f(x) = y, start from x
+function solve(f, y, x) {
+ var steps = 100, delta, f0, f1;
+ x = x === undefined ? 0 : +x;
+ y = +y;
+ do {
+ f0 = f(x);
+ f1 = f(x + epsilon$1);
+ if (f0 === f1) f1 = f0 + epsilon$1;
+ x -= delta = (-1 * epsilon$1 * (f0 - y)) / (f0 - f1);
+ } while (steps-- > 0 && abs(delta) > epsilon$1);
+ return steps < 0 ? NaN : x;
+}
+
+// Approximate Newton-Raphson in 2D
+// Solve f(a,b) = [x,y]
+function solve2d(f, MAX_ITERATIONS, eps) {
+ if (MAX_ITERATIONS === undefined) MAX_ITERATIONS = 40;
+ if (eps === undefined) eps = epsilon2;
+ return function(x, y, a, b) {
+ var err2, da, db;
+ a = a === undefined ? 0 : +a;
+ b = b === undefined ? 0 : +b;
+ for (var i = 0; i < MAX_ITERATIONS; i++) {
+ var p = f(a, b),
+ // diffs
+ tx = p[0] - x,
+ ty = p[1] - y;
+ if (abs(tx) < eps && abs(ty) < eps) break; // we're there!
+
+ // backtrack if we overshot
+ var h = tx * tx + ty * ty;
+ if (h > err2) {
+ a -= da /= 2;
+ b -= db /= 2;
+ continue;
+ }
+ err2 = h;
+
+ // partial derivatives
+ var ea = (a > 0 ? -1 : 1) * eps,
+ eb = (b > 0 ? -1 : 1) * eps,
+ pa = f(a + ea, b),
+ pb = f(a, b + eb),
+ dxa = (pa[0] - p[0]) / ea,
+ dya = (pa[1] - p[1]) / ea,
+ dxb = (pb[0] - p[0]) / eb,
+ dyb = (pb[1] - p[1]) / eb,
+ // determinant
+ D = dyb * dxa - dya * dxb,
+ // newton step — or half-step for small D
+ l = (abs(D) < 0.5 ? 0.5 : 1) / D;
+ da = (ty * dxb - tx * dyb) * l;
+ db = (tx * dya - ty * dxa) * l;
+ a += da;
+ b += db;
+ if (abs(da) < eps && abs(db) < eps) break; // we're crawling
+ }
+ return [a, b];
+ };
+}
+
+// Bertin 1953 as a modified Briesemeister
+// https://bl.ocks.org/Fil/5b9ee9636dfb6ffa53443c9006beb642
+function bertin1953Raw() {
+ var hammer = hammerRaw(1.68, 2),
+ fu = 1.4, k = 12;
+
+ function forward(lambda, phi) {
+
+ if (lambda + phi < -fu) {
+ var u = (lambda - phi + 1.6) * (lambda + phi + fu) / 8;
+ lambda += u;
+ phi -= 0.8 * u * sin(phi + pi / 2);
+ }
+
+ var r = hammer(lambda, phi);
+
+ var d = (1 - cos(lambda * phi)) / k;
+
+ if (r[1] < 0) {
+ r[0] *= 1 + d;
+ }
+ if (r[1] > 0) {
+ r[1] *= 1 + d / 1.5 * r[0] * r[0];
+ }
+
+ return r;
+ }
+
+ forward.invert = solve2d(forward);
+ return forward;
+}
+
+function bertin() {
+ // this projection should not be rotated
+ return d3Geo.geoProjection(bertin1953Raw())
+ .rotate([-16.5, -42])
+ .scale(176.57)
+ .center([7.93, 0.09]);
+}
+
+function mollweideBromleyTheta(cp, phi) {
+ var cpsinPhi = cp * sin(phi), i = 30, delta;
+ do phi -= delta = (phi + sin(phi) - cpsinPhi) / (1 + cos(phi));
+ while (abs(delta) > epsilon$1 && --i > 0);
+ return phi / 2;
+}
+
+function mollweideBromleyRaw(cx, cy, cp) {
+
+ function forward(lambda, phi) {
+ return [cx * lambda * cos(phi = mollweideBromleyTheta(cp, phi)), cy * sin(phi)];
+ }
+
+ forward.invert = function(x, y) {
+ return y = asin(y / cy), [x / (cx * cos(y)), asin((2 * y + sin(2 * y)) / cp)];
+ };
+
+ return forward;
+}
+
+var mollweideRaw = mollweideBromleyRaw(sqrt2 / halfPi, sqrt2, pi);
+
+function mollweide$1() {
+ return d3Geo.geoProjection(mollweideRaw)
+ .scale(169.529);
+}
+
+var k = 2.00276,
+ w = 1.11072;
+
+function boggsRaw(lambda, phi) {
+ var theta = mollweideBromleyTheta(pi, phi);
+ return [k * lambda / (1 / cos(phi) + w / cos(theta)), (phi + sqrt2 * sin(theta)) / k];
+}
+
+boggsRaw.invert = function(x, y) {
+ var ky = k * y, theta = y < 0 ? -quarterPi : quarterPi, i = 25, delta, phi;
+ do {
+ phi = ky - sqrt2 * sin(theta);
+ theta -= delta = (sin(2 * theta) + 2 * theta - pi * sin(phi)) / (2 * cos(2 * theta) + 2 + pi * cos(phi) * sqrt2 * cos(theta));
+ } while (abs(delta) > epsilon$1 && --i > 0);
+ phi = ky - sqrt2 * sin(theta);
+ return [x * (1 / cos(phi) + w / cos(theta)) / k, phi];
+};
+
+function boggs$1() {
+ return d3Geo.geoProjection(boggsRaw)
+ .scale(160.857);
+}
+
+function parallel1(projectAt) {
+ var phi0 = 0,
+ m = d3Geo.geoProjectionMutator(projectAt),
+ p = m(phi0);
+
+ p.parallel = function(_) {
+ return arguments.length ? m(phi0 = _ * radians) : phi0 * degrees;
+ };
+
+ return p;
+}
+
+function sinusoidalRaw(lambda, phi) {
+ return [lambda * cos(phi), phi];
+}
+
+sinusoidalRaw.invert = function(x, y) {
+ return [x / cos(y), y];
+};
+
+function sinusoidal$1() {
+ return d3Geo.geoProjection(sinusoidalRaw)
+ .scale(152.63);
+}
+
+function bonneRaw(phi0) {
+ if (!phi0) return sinusoidalRaw;
+ var cotPhi0 = 1 / tan(phi0);
+
+ function forward(lambda, phi) {
+ var rho = cotPhi0 + phi0 - phi,
+ e = rho ? lambda * cos(phi) / rho : rho;
+ return [rho * sin(e), cotPhi0 - rho * cos(e)];
+ }
+
+ forward.invert = function(x, y) {
+ var rho = sqrt(x * x + (y = cotPhi0 - y) * y),
+ phi = cotPhi0 + phi0 - rho;
+ return [rho / cos(phi) * atan2(x, y), phi];
+ };
+
+ return forward;
+}
+
+function bonne() {
+ return parallel1(bonneRaw)
+ .scale(123.082)
+ .center([0, 26.1441])
+ .parallel(45);
+}
+
+function bottomleyRaw(sinPsi) {
+
+ function forward(lambda, phi) {
+ var rho = halfPi - phi,
+ eta = rho ? lambda * sinPsi * sin(rho) / rho : rho;
+ return [rho * sin(eta) / sinPsi, halfPi - rho * cos(eta)];
+ }
+
+ forward.invert = function(x, y) {
+ var x1 = x * sinPsi,
+ y1 = halfPi - y,
+ rho = sqrt(x1 * x1 + y1 * y1),
+ eta = atan2(x1, y1);
+ return [(rho ? rho / sin(rho) : 1) * eta / sinPsi, halfPi - rho];
+ };
+
+ return forward;
+}
+
+function bottomley() {
+ var sinPsi = 0.5,
+ m = d3Geo.geoProjectionMutator(bottomleyRaw),
+ p = m(sinPsi);
+
+ p.fraction = function(_) {
+ return arguments.length ? m(sinPsi = +_) : sinPsi;
+ };
+
+ return p
+ .scale(158.837);
+}
+
+var bromleyRaw = mollweideBromleyRaw(1, 4 / pi, pi);
+
+function bromley() {
+ return d3Geo.geoProjection(bromleyRaw)
+ .scale(152.63);
+}
+
+// Azimuthal distance.
+function distance(dPhi, c1, s1, c2, s2, dLambda) {
+ var cosdLambda = cos(dLambda), r;
+ if (abs(dPhi) > 1 || abs(dLambda) > 1) {
+ r = acos(s1 * s2 + c1 * c2 * cosdLambda);
+ } else {
+ var sindPhi = sin(dPhi / 2), sindLambda = sin(dLambda / 2);
+ r = 2 * asin(sqrt(sindPhi * sindPhi + c1 * c2 * sindLambda * sindLambda));
+ }
+ return abs(r) > epsilon$1 ? [r, atan2(c2 * sin(dLambda), c1 * s2 - s1 * c2 * cosdLambda)] : [0, 0];
+}
+
+// Angle opposite a, and contained between sides of lengths b and c.
+function angle$1(b, c, a) {
+ return acos((b * b + c * c - a * a) / (2 * b * c));
+}
+
+// Normalize longitude.
+function longitude(lambda) {
+ return lambda - 2 * pi * floor((lambda + pi) / (2 * pi));
+}
+
+function chamberlinRaw(p0, p1, p2) {
+ var points = [
+ [p0[0], p0[1], sin(p0[1]), cos(p0[1])],
+ [p1[0], p1[1], sin(p1[1]), cos(p1[1])],
+ [p2[0], p2[1], sin(p2[1]), cos(p2[1])]
+ ];
+
+ for (var a = points[2], b, i = 0; i < 3; ++i, a = b) {
+ b = points[i];
+ a.v = distance(b[1] - a[1], a[3], a[2], b[3], b[2], b[0] - a[0]);
+ a.point = [0, 0];
+ }
+
+ var beta0 = angle$1(points[0].v[0], points[2].v[0], points[1].v[0]),
+ beta1 = angle$1(points[0].v[0], points[1].v[0], points[2].v[0]),
+ beta2 = pi - beta0;
+
+ points[2].point[1] = 0;
+ points[0].point[0] = -(points[1].point[0] = points[0].v[0] / 2);
+
+ var mean = [
+ points[2].point[0] = points[0].point[0] + points[2].v[0] * cos(beta0),
+ 2 * (points[0].point[1] = points[1].point[1] = points[2].v[0] * sin(beta0))
+ ];
+
+ function forward(lambda, phi) {
+ var sinPhi = sin(phi),
+ cosPhi = cos(phi),
+ v = new Array(3), i;
+
+ // Compute distance and azimuth from control points.
+ for (i = 0; i < 3; ++i) {
+ var p = points[i];
+ v[i] = distance(phi - p[1], p[3], p[2], cosPhi, sinPhi, lambda - p[0]);
+ if (!v[i][0]) return p.point;
+ v[i][1] = longitude(v[i][1] - p.v[1]);
+ }
+
+ // Arithmetic mean of interception points.
+ var point = mean.slice();
+ for (i = 0; i < 3; ++i) {
+ var j = i == 2 ? 0 : i + 1;
+ var a = angle$1(points[i].v[0], v[i][0], v[j][0]);
+ if (v[i][1] < 0) a = -a;
+
+ if (!i) {
+ point[0] += v[i][0] * cos(a);
+ point[1] -= v[i][0] * sin(a);
+ } else if (i == 1) {
+ a = beta1 - a;
+ point[0] -= v[i][0] * cos(a);
+ point[1] -= v[i][0] * sin(a);
+ } else {
+ a = beta2 - a;
+ point[0] += v[i][0] * cos(a);
+ point[1] += v[i][0] * sin(a);
+ }
+ }
+
+ point[0] /= 3, point[1] /= 3;
+ return point;
+ }
+
+ return forward;
+}
+
+function pointRadians(p) {
+ return p[0] *= radians, p[1] *= radians, p;
+}
+
+function chamberlinAfrica() {
+ return chamberlin([0, 22], [45, 22], [22.5, -22])
+ .scale(380)
+ .center([22.5, 2]);
+}
+
+function chamberlin(p0, p1, p2) { // TODO order matters!
+ var c = d3Geo.geoCentroid({type: "MultiPoint", coordinates: [p0, p1, p2]}),
+ R = [-c[0], -c[1]],
+ r = d3Geo.geoRotation(R),
+ f = chamberlinRaw(pointRadians(r(p0)), pointRadians(r(p1)), pointRadians(r(p2)));
+ f.invert = solve2d(f);
+ var p = d3Geo.geoProjection(f).rotate(R),
+ center = p.center;
+
+ delete p.rotate;
+
+ p.center = function(_) {
+ return arguments.length ? center(r(_)) : r.invert(center());
+ };
+
+ return p
+ .clipAngle(90);
+}
+
+function collignonRaw(lambda, phi) {
+ var alpha = sqrt(1 - sin(phi));
+ return [(2 / sqrtPi) * lambda * alpha, sqrtPi * (1 - alpha)];
+}
+
+collignonRaw.invert = function(x, y) {
+ var lambda = (lambda = y / sqrtPi - 1) * lambda;
+ return [lambda > 0 ? x * sqrt(pi / lambda) / 2 : 0, asin(1 - lambda)];
+};
+
+function collignon$1() {
+ return d3Geo.geoProjection(collignonRaw)
+ .scale(95.6464)
+ .center([0, 30]);
+}
+
+function craigRaw(phi0) {
+ var tanPhi0 = tan(phi0);
+
+ function forward(lambda, phi) {
+ return [lambda, (lambda ? lambda / sin(lambda) : 1) * (sin(phi) * cos(lambda) - tanPhi0 * cos(phi))];
+ }
+
+ forward.invert = tanPhi0 ? function(x, y) {
+ if (x) y *= sin(x) / x;
+ var cosLambda = cos(x);
+ return [x, 2 * atan2(sqrt(cosLambda * cosLambda + tanPhi0 * tanPhi0 - y * y) - cosLambda, tanPhi0 - y)];
+ } : function(x, y) {
+ return [x, asin(x ? y * tan(x) / x : y)];
+ };
+
+ return forward;
+}
+
+function craig() {
+ return parallel1(craigRaw)
+ .scale(249.828)
+ .clipAngle(90);
+}
+
+var sqrt3 = sqrt(3);
+
+function crasterRaw(lambda, phi) {
+ return [sqrt3 * lambda * (2 * cos(2 * phi / 3) - 1) / sqrtPi, sqrt3 * sqrtPi * sin(phi / 3)];
+}
+
+crasterRaw.invert = function(x, y) {
+ var phi = 3 * asin(y / (sqrt3 * sqrtPi));
+ return [sqrtPi * x / (sqrt3 * (2 * cos(2 * phi / 3) - 1)), phi];
+};
+
+function craster() {
+ return d3Geo.geoProjection(crasterRaw)
+ .scale(156.19);
+}
+
+function cylindricalEqualAreaRaw(phi0) {
+ var cosPhi0 = cos(phi0);
+
+ function forward(lambda, phi) {
+ return [lambda * cosPhi0, sin(phi) / cosPhi0];
+ }
+
+ forward.invert = function(x, y) {
+ return [x / cosPhi0, asin(y * cosPhi0)];
+ };
+
+ return forward;
+}
+
+function cylindricalEqualArea() {
+ return parallel1(cylindricalEqualAreaRaw)
+ .parallel(38.58) // acos(sqrt(width / height / pi)) * radians
+ .scale(195.044); // width / (sqrt(width / height / pi) * 2 * pi)
+}
+
+function cylindricalStereographicRaw(phi0) {
+ var cosPhi0 = cos(phi0);
+
+ function forward(lambda, phi) {
+ return [lambda * cosPhi0, (1 + cosPhi0) * tan(phi / 2)];
+ }
+
+ forward.invert = function(x, y) {
+ return [x / cosPhi0, atan(y / (1 + cosPhi0)) * 2];
+ };
+
+ return forward;
+}
+
+function cylindricalStereographic() {
+ return parallel1(cylindricalStereographicRaw)
+ .scale(124.75);
+}
+
+function eckert1Raw(lambda, phi) {
+ var alpha = sqrt(8 / (3 * pi));
+ return [
+ alpha * lambda * (1 - abs(phi) / pi),
+ alpha * phi
+ ];
+}
+
+eckert1Raw.invert = function(x, y) {
+ var alpha = sqrt(8 / (3 * pi)),
+ phi = y / alpha;
+ return [
+ x / (alpha * (1 - abs(phi) / pi)),
+ phi
+ ];
+};
+
+function eckert1() {
+ return d3Geo.geoProjection(eckert1Raw)
+ .scale(165.664);
+}
+
+function eckert2Raw(lambda, phi) {
+ var alpha = sqrt(4 - 3 * sin(abs(phi)));
+ return [
+ 2 / sqrt(6 * pi) * lambda * alpha,
+ sign(phi) * sqrt(2 * pi / 3) * (2 - alpha)
+ ];
+}
+
+eckert2Raw.invert = function(x, y) {
+ var alpha = 2 - abs(y) / sqrt(2 * pi / 3);
+ return [
+ x * sqrt(6 * pi) / (2 * alpha),
+ sign(y) * asin((4 - alpha * alpha) / 3)
+ ];
+};
+
+function eckert2() {
+ return d3Geo.geoProjection(eckert2Raw)
+ .scale(165.664);
+}
+
+function eckert3Raw(lambda, phi) {
+ var k = sqrt(pi * (4 + pi));
+ return [
+ 2 / k * lambda * (1 + sqrt(1 - 4 * phi * phi / (pi * pi))),
+ 4 / k * phi
+ ];
+}
+
+eckert3Raw.invert = function(x, y) {
+ var k = sqrt(pi * (4 + pi)) / 2;
+ return [
+ x * k / (1 + sqrt(1 - y * y * (4 + pi) / (4 * pi))),
+ y * k / 2
+ ];
+};
+
+function eckert3() {
+ return d3Geo.geoProjection(eckert3Raw)
+ .scale(180.739);
+}
+
+function eckert4Raw(lambda, phi) {
+ var k = (2 + halfPi) * sin(phi);
+ phi /= 2;
+ for (var i = 0, delta = Infinity; i < 10 && abs(delta) > epsilon$1; i++) {
+ var cosPhi = cos(phi);
+ phi -= delta = (phi + sin(phi) * (cosPhi + 2) - k) / (2 * cosPhi * (1 + cosPhi));
+ }
+ return [
+ 2 / sqrt(pi * (4 + pi)) * lambda * (1 + cos(phi)),
+ 2 * sqrt(pi / (4 + pi)) * sin(phi)
+ ];
+}
+
+eckert4Raw.invert = function(x, y) {
+ var A = y * sqrt((4 + pi) / pi) / 2,
+ k = asin(A),
+ c = cos(k);
+ return [
+ x / (2 / sqrt(pi * (4 + pi)) * (1 + c)),
+ asin((k + A * (c + 2)) / (2 + halfPi))
+ ];
+};
+
+function eckert4() {
+ return d3Geo.geoProjection(eckert4Raw)
+ .scale(180.739);
+}
+
+function eckert5Raw(lambda, phi) {
+ return [
+ lambda * (1 + cos(phi)) / sqrt(2 + pi),
+ 2 * phi / sqrt(2 + pi)
+ ];
+}
+
+eckert5Raw.invert = function(x, y) {
+ var k = sqrt(2 + pi),
+ phi = y * k / 2;
+ return [
+ k * x / (1 + cos(phi)),
+ phi
+ ];
+};
+
+function eckert5() {
+ return d3Geo.geoProjection(eckert5Raw)
+ .scale(173.044);
+}
+
+function eckert6Raw(lambda, phi) {
+ var k = (1 + halfPi) * sin(phi);
+ for (var i = 0, delta = Infinity; i < 10 && abs(delta) > epsilon$1; i++) {
+ phi -= delta = (phi + sin(phi) - k) / (1 + cos(phi));
+ }
+ k = sqrt(2 + pi);
+ return [
+ lambda * (1 + cos(phi)) / k,
+ 2 * phi / k
+ ];
+}
+
+eckert6Raw.invert = function(x, y) {
+ var j = 1 + halfPi,
+ k = sqrt(j / 2);
+ return [
+ x * 2 * k / (1 + cos(y *= k)),
+ asin((y + sin(y)) / j)
+ ];
+};
+
+function eckert6() {
+ return d3Geo.geoProjection(eckert6Raw)
+ .scale(173.044);
+}
+
+var eisenlohrK = 3 + 2 * sqrt2;
+
+function eisenlohrRaw(lambda, phi) {
+ var s0 = sin(lambda /= 2),
+ c0 = cos(lambda),
+ k = sqrt(cos(phi)),
+ c1 = cos(phi /= 2),
+ t = sin(phi) / (c1 + sqrt2 * c0 * k),
+ c = sqrt(2 / (1 + t * t)),
+ v = sqrt((sqrt2 * c1 + (c0 + s0) * k) / (sqrt2 * c1 + (c0 - s0) * k));
+ return [
+ eisenlohrK * (c * (v - 1 / v) - 2 * log(v)),
+ eisenlohrK * (c * t * (v + 1 / v) - 2 * atan(t))
+ ];
+}
+
+eisenlohrRaw.invert = function(x, y) {
+ if (!(p = augustRaw.invert(x / 1.2, y * 1.065))) return null;
+ var lambda = p[0], phi = p[1], i = 20, p;
+ x /= eisenlohrK, y /= eisenlohrK;
+ do {
+ var _0 = lambda / 2,
+ _1 = phi / 2,
+ s0 = sin(_0),
+ c0 = cos(_0),
+ s1 = sin(_1),
+ c1 = cos(_1),
+ cos1 = cos(phi),
+ k = sqrt(cos1),
+ t = s1 / (c1 + sqrt2 * c0 * k),
+ t2 = t * t,
+ c = sqrt(2 / (1 + t2)),
+ v0 = (sqrt2 * c1 + (c0 + s0) * k),
+ v1 = (sqrt2 * c1 + (c0 - s0) * k),
+ v2 = v0 / v1,
+ v = sqrt(v2),
+ vm1v = v - 1 / v,
+ vp1v = v + 1 / v,
+ fx = c * vm1v - 2 * log(v) - x,
+ fy = c * t * vp1v - 2 * atan(t) - y,
+ deltatDeltaLambda = s1 && sqrt1_2 * k * s0 * t2 / s1,
+ deltatDeltaPhi = (sqrt2 * c0 * c1 + k) / (2 * (c1 + sqrt2 * c0 * k) * (c1 + sqrt2 * c0 * k) * k),
+ deltacDeltat = -0.5 * t * c * c * c,
+ deltacDeltaLambda = deltacDeltat * deltatDeltaLambda,
+ deltacDeltaPhi = deltacDeltat * deltatDeltaPhi,
+ A = (A = 2 * c1 + sqrt2 * k * (c0 - s0)) * A * v,
+ deltavDeltaLambda = (sqrt2 * c0 * c1 * k + cos1) / A,
+ deltavDeltaPhi = -(sqrt2 * s0 * s1) / (k * A),
+ deltaxDeltaLambda = vm1v * deltacDeltaLambda - 2 * deltavDeltaLambda / v + c * (deltavDeltaLambda + deltavDeltaLambda / v2),
+ deltaxDeltaPhi = vm1v * deltacDeltaPhi - 2 * deltavDeltaPhi / v + c * (deltavDeltaPhi + deltavDeltaPhi / v2),
+ deltayDeltaLambda = t * vp1v * deltacDeltaLambda - 2 * deltatDeltaLambda / (1 + t2) + c * vp1v * deltatDeltaLambda + c * t * (deltavDeltaLambda - deltavDeltaLambda / v2),
+ deltayDeltaPhi = t * vp1v * deltacDeltaPhi - 2 * deltatDeltaPhi / (1 + t2) + c * vp1v * deltatDeltaPhi + c * t * (deltavDeltaPhi - deltavDeltaPhi / v2),
+ denominator = deltaxDeltaPhi * deltayDeltaLambda - deltayDeltaPhi * deltaxDeltaLambda;
+ if (!denominator) break;
+ var deltaLambda = (fy * deltaxDeltaPhi - fx * deltayDeltaPhi) / denominator,
+ deltaPhi = (fx * deltayDeltaLambda - fy * deltaxDeltaLambda) / denominator;
+ lambda -= deltaLambda;
+ phi = max(-halfPi, min(halfPi, phi - deltaPhi));
+ } while ((abs(deltaLambda) > epsilon$1 || abs(deltaPhi) > epsilon$1) && --i > 0);
+ return abs(abs(phi) - halfPi) < epsilon$1 ? [0, phi] : i && [lambda, phi];
+};
+
+function eisenlohr() {
+ return d3Geo.geoProjection(eisenlohrRaw)
+ .scale(62.5271);
+}
+
+var faheyK = cos(35 * radians);
+
+function faheyRaw(lambda, phi) {
+ var t = tan(phi / 2);
+ return [lambda * faheyK * sqrt(1 - t * t), (1 + faheyK) * t];
+}
+
+faheyRaw.invert = function(x, y) {
+ var t = y / (1 + faheyK);
+ return [x && x / (faheyK * sqrt(1 - t * t)), 2 * atan(t)];
+};
+
+function fahey() {
+ return d3Geo.geoProjection(faheyRaw)
+ .scale(137.152);
+}
+
+function foucautRaw(lambda, phi) {
+ var k = phi / 2, cosk = cos(k);
+ return [ 2 * lambda / sqrtPi * cos(phi) * cosk * cosk, sqrtPi * tan(k)];
+}
+
+foucautRaw.invert = function(x, y) {
+ var k = atan(y / sqrtPi), cosk = cos(k), phi = 2 * k;
+ return [x * sqrtPi / 2 / (cos(phi) * cosk * cosk), phi];
+};
+
+function foucaut() {
+ return d3Geo.geoProjection(foucautRaw)
+ .scale(135.264);
+}
+
+function foucautSinusoidalRaw(alpha) {
+ var beta = 1 - alpha,
+ equatorial = raw(pi, 0)[0] - raw(-pi, 0)[0],
+ polar = raw(0, halfPi)[1] - raw(0, -halfPi)[1],
+ ratio = sqrt(2 * polar / equatorial);
+
+ function raw(lambda, phi) {
+ var cosphi = cos(phi),
+ sinphi = sin(phi);
+ return [
+ cosphi / (beta + alpha * cosphi) * lambda,
+ beta * phi + alpha * sinphi
+ ];
+ }
+
+ function forward(lambda, phi) {
+ var p = raw(lambda, phi);
+ return [p[0] * ratio, p[1] / ratio];
+ }
+
+ function forwardMeridian(phi) {
+ return forward(0, phi)[1];
+ }
+
+ forward.invert = function(x, y) {
+ var phi = solve(forwardMeridian, y),
+ lambda = x / ratio * (alpha + beta / cos(phi));
+ return [lambda, phi];
+ };
+
+ return forward;
+}
+
+function foucautSinusoidal() {
+ var alpha = 0.5,
+ m = d3Geo.geoProjectionMutator(foucautSinusoidalRaw),
+ p = m(alpha);
+
+ p.alpha = function(_) {
+ return arguments.length ? m(alpha = +_) : alpha;
+ };
+
+ return p
+ .scale(168.725);
+}
+
+function gilbertForward(point) {
+ return [point[0] / 2, asin(tan(point[1] / 2 * radians)) * degrees];
+}
+
+function gilbertInvert(point) {
+ return [point[0] * 2, 2 * atan(sin(point[1] * radians)) * degrees];
+}
+
+function gilbert(projectionType) {
+ if (projectionType == null) projectionType = d3Geo.geoOrthographic;
+ var projection = projectionType(),
+ equirectangular = d3Geo.geoEquirectangular().scale(degrees).precision(0).clipAngle(null).translate([0, 0]); // antimeridian cutting
+
+ function gilbert(point) {
+ return projection(gilbertForward(point));
+ }
+
+ if (projection.invert) gilbert.invert = function(point) {
+ return gilbertInvert(projection.invert(point));
+ };
+
+ gilbert.stream = function(stream) {
+ var s1 = projection.stream(stream), s0 = equirectangular.stream({
+ point: function(lambda, phi) { s1.point(lambda / 2, asin(tan(-phi / 2 * radians)) * degrees); },
+ lineStart: function() { s1.lineStart(); },
+ lineEnd: function() { s1.lineEnd(); },
+ polygonStart: function() { s1.polygonStart(); },
+ polygonEnd: function() { s1.polygonEnd(); }
+ });
+ s0.sphere = s1.sphere;
+ return s0;
+ };
+
+ function property(name) {
+ gilbert[name] = function() {
+ return arguments.length ? (projection[name].apply(projection, arguments), gilbert) : projection[name]();
+ };
+ }
+
+ gilbert.rotate = function(_) {
+ return arguments.length ? (equirectangular.rotate(_), gilbert) : equirectangular.rotate();
+ };
+
+ gilbert.center = function(_) {
+ return arguments.length ? (projection.center(gilbertForward(_)), gilbert) : gilbertInvert(projection.center());
+ };
+
+ property("angle");
+ property("clipAngle");
+ property("clipExtent");
+ property("fitExtent");
+ property("fitHeight");
+ property("fitSize");
+ property("fitWidth");
+ property("scale");
+ property("translate");
+ property("precision");
+
+ return gilbert
+ .scale(249.5);
+}
+
+function gingeryRaw(rho, n) {
+ var k = 2 * pi / n,
+ rho2 = rho * rho;
+
+ function forward(lambda, phi) {
+ var p = d3Geo.geoAzimuthalEquidistantRaw(lambda, phi),
+ x = p[0],
+ y = p[1],
+ r2 = x * x + y * y;
+
+ if (r2 > rho2) {
+ var r = sqrt(r2),
+ theta = atan2(y, x),
+ theta0 = k * round(theta / k),
+ alpha = theta - theta0,
+ rhoCosAlpha = rho * cos(alpha),
+ k_ = (rho * sin(alpha) - alpha * sin(rhoCosAlpha)) / (halfPi - rhoCosAlpha),
+ s_ = gingeryLength(alpha, k_),
+ e = (pi - rho) / gingeryIntegrate(s_, rhoCosAlpha, pi);
+
+ x = r;
+ var i = 50, delta;
+ do {
+ x -= delta = (rho + gingeryIntegrate(s_, rhoCosAlpha, x) * e - r) / (s_(x) * e);
+ } while (abs(delta) > epsilon$1 && --i > 0);
+
+ y = alpha * sin(x);
+ if (x < halfPi) y -= k_ * (x - halfPi);
+
+ var s = sin(theta0),
+ c = cos(theta0);
+ p[0] = x * c - y * s;
+ p[1] = x * s + y * c;
+ }
+ return p;
+ }
+
+ forward.invert = function(x, y) {
+ var r2 = x * x + y * y;
+ if (r2 > rho2) {
+ var r = sqrt(r2),
+ theta = atan2(y, x),
+ theta0 = k * round(theta / k),
+ dTheta = theta - theta0;
+
+ x = r * cos(dTheta);
+ y = r * sin(dTheta);
+
+ var x_halfPi = x - halfPi,
+ sinx = sin(x),
+ alpha = y / sinx,
+ delta = x < halfPi ? Infinity : 0,
+ i = 10;
+
+ while (true) {
+ var rhosinAlpha = rho * sin(alpha),
+ rhoCosAlpha = rho * cos(alpha),
+ sinRhoCosAlpha = sin(rhoCosAlpha),
+ halfPi_RhoCosAlpha = halfPi - rhoCosAlpha,
+ k_ = (rhosinAlpha - alpha * sinRhoCosAlpha) / halfPi_RhoCosAlpha,
+ s_ = gingeryLength(alpha, k_);
+
+ if (abs(delta) < epsilon2 || !--i) break;
+
+ alpha -= delta = (alpha * sinx - k_ * x_halfPi - y) / (
+ sinx - x_halfPi * 2 * (
+ halfPi_RhoCosAlpha * (rhoCosAlpha + alpha * rhosinAlpha * cos(rhoCosAlpha) - sinRhoCosAlpha) -
+ rhosinAlpha * (rhosinAlpha - alpha * sinRhoCosAlpha)
+ ) / (halfPi_RhoCosAlpha * halfPi_RhoCosAlpha));
+ }
+ r = rho + gingeryIntegrate(s_, rhoCosAlpha, x) * (pi - rho) / gingeryIntegrate(s_, rhoCosAlpha, pi);
+ theta = theta0 + alpha;
+ x = r * cos(theta);
+ y = r * sin(theta);
+ }
+ return d3Geo.geoAzimuthalEquidistantRaw.invert(x, y);
+ };
+
+ return forward;
+}
+
+function gingeryLength(alpha, k) {
+ return function(x) {
+ var y_ = alpha * cos(x);
+ if (x < halfPi) y_ -= k;
+ return sqrt(1 + y_ * y_);
+ };
+}
+
+// Numerical integration: trapezoidal rule.
+function gingeryIntegrate(f, a, b) {
+ var n = 50,
+ h = (b - a) / n,
+ s = f(a) + f(b);
+ for (var i = 1, x = a; i < n; ++i) s += 2 * f(x += h);
+ return s * 0.5 * h;
+}
+
+function gingery() {
+ var n = 6,
+ rho = 30 * radians,
+ cRho = cos(rho),
+ sRho = sin(rho),
+ m = d3Geo.geoProjectionMutator(gingeryRaw),
+ p = m(rho, n),
+ stream_ = p.stream,
+ epsilon = 1e-2,
+ cr = -cos(epsilon * radians),
+ sr = sin(epsilon * radians);
+
+ p.radius = function(_) {
+ if (!arguments.length) return rho * degrees;
+ cRho = cos(rho = _ * radians);
+ sRho = sin(rho);
+ return m(rho, n);
+ };
+
+ p.lobes = function(_) {
+ if (!arguments.length) return n;
+ return m(rho, n = +_);
+ };
+
+ p.stream = function(stream) {
+ var rotate = p.rotate(),
+ rotateStream = stream_(stream),
+ sphereStream = (p.rotate([0, 0]), stream_(stream));
+ p.rotate(rotate);
+ rotateStream.sphere = function() {
+ sphereStream.polygonStart(), sphereStream.lineStart();
+ for (var i = 0, delta = 2 * pi / n, phi = 0; i < n; ++i, phi -= delta) {
+ sphereStream.point(atan2(sr * cos(phi), cr) * degrees, asin(sr * sin(phi)) * degrees);
+ sphereStream.point(atan2(sRho * cos(phi - delta / 2), cRho) * degrees, asin(sRho * sin(phi - delta / 2)) * degrees);
+ }
+ sphereStream.lineEnd(), sphereStream.polygonEnd();
+ };
+ return rotateStream;
+ };
+
+ return p
+ .rotate([90, -40])
+ .scale(91.7095)
+ .clipAngle(180 - 1e-3);
+}
+
+function ginzburgPolyconicRaw(a, b, c, d, e, f, g, h) {
+ if (arguments.length < 8) h = 0;
+
+ function forward(lambda, phi) {
+ if (!phi) return [a * lambda / pi, 0];
+ var phi2 = phi * phi,
+ xB = a + phi2 * (b + phi2 * (c + phi2 * d)),
+ yB = phi * (e - 1 + phi2 * (f - h + phi2 * g)),
+ m = (xB * xB + yB * yB) / (2 * yB),
+ alpha = lambda * asin(xB / m) / pi;
+ return [m * sin(alpha), phi * (1 + phi2 * h) + m * (1 - cos(alpha))];
+ }
+
+ forward.invert = function(x, y) {
+ var lambda = pi * x / a,
+ phi = y,
+ deltaLambda, deltaPhi, i = 50;
+ do {
+ var phi2 = phi * phi,
+ xB = a + phi2 * (b + phi2 * (c + phi2 * d)),
+ yB = phi * (e - 1 + phi2 * (f - h + phi2 * g)),
+ p = xB * xB + yB * yB,
+ q = 2 * yB,
+ m = p / q,
+ m2 = m * m,
+ dAlphadLambda = asin(xB / m) / pi,
+ alpha = lambda * dAlphadLambda,
+ xB2 = xB * xB,
+ dxBdPhi = (2 * b + phi2 * (4 * c + phi2 * 6 * d)) * phi,
+ dyBdPhi = e + phi2 * (3 * f + phi2 * 5 * g),
+ dpdPhi = 2 * (xB * dxBdPhi + yB * (dyBdPhi - 1)),
+ dqdPhi = 2 * (dyBdPhi - 1),
+ dmdPhi = (dpdPhi * q - p * dqdPhi) / (q * q),
+ cosAlpha = cos(alpha),
+ sinAlpha = sin(alpha),
+ mcosAlpha = m * cosAlpha,
+ msinAlpha = m * sinAlpha,
+ dAlphadPhi = ((lambda / pi) * (1 / sqrt(1 - xB2 / m2)) * (dxBdPhi * m - xB * dmdPhi)) / m2,
+ fx = msinAlpha - x,
+ fy = phi * (1 + phi2 * h) + m - mcosAlpha - y,
+ deltaxDeltaPhi = dmdPhi * sinAlpha + mcosAlpha * dAlphadPhi,
+ deltaxDeltaLambda = mcosAlpha * dAlphadLambda,
+ deltayDeltaPhi = 1 + dmdPhi - (dmdPhi * cosAlpha - msinAlpha * dAlphadPhi),
+ deltayDeltaLambda = msinAlpha * dAlphadLambda,
+ denominator = deltaxDeltaPhi * deltayDeltaLambda - deltayDeltaPhi * deltaxDeltaLambda;
+ if (!denominator) break;
+ lambda -= deltaLambda = (fy * deltaxDeltaPhi - fx * deltayDeltaPhi) / denominator;
+ phi -= deltaPhi = (fx * deltayDeltaLambda - fy * deltaxDeltaLambda) / denominator;
+ } while ((abs(deltaLambda) > epsilon$1 || abs(deltaPhi) > epsilon$1) && --i > 0);
+ return [lambda, phi];
+ };
+
+ return forward;
+}
+
+var ginzburg4Raw = ginzburgPolyconicRaw(2.8284, -1.6988, 0.75432, -0.18071, 1.76003, -0.38914, 0.042555);
+
+function ginzburg4() {
+ return d3Geo.geoProjection(ginzburg4Raw)
+ .scale(149.995);
+}
+
+var ginzburg5Raw = ginzburgPolyconicRaw(2.583819, -0.835827, 0.170354, -0.038094, 1.543313, -0.411435,0.082742);
+
+function ginzburg5() {
+ return d3Geo.geoProjection(ginzburg5Raw)
+ .scale(153.93);
+}
+
+var ginzburg6Raw = ginzburgPolyconicRaw(5 / 6 * pi, -0.62636, -0.0344, 0, 1.3493, -0.05524, 0, 0.045);
+
+function ginzburg6() {
+ return d3Geo.geoProjection(ginzburg6Raw)
+ .scale(130.945);
+}
+
+function ginzburg8Raw(lambda, phi) {
+ var lambda2 = lambda * lambda,
+ phi2 = phi * phi;
+ return [
+ lambda * (1 - 0.162388 * phi2) * (0.87 - 0.000952426 * lambda2 * lambda2),
+ phi * (1 + phi2 / 12)
+ ];
+}
+
+ginzburg8Raw.invert = function(x, y) {
+ var lambda = x,
+ phi = y,
+ i = 50, delta;
+ do {
+ var phi2 = phi * phi;
+ phi -= delta = (phi * (1 + phi2 / 12) - y) / (1 + phi2 / 4);
+ } while (abs(delta) > epsilon$1 && --i > 0);
+ i = 50;
+ x /= 1 -0.162388 * phi2;
+ do {
+ var lambda4 = (lambda4 = lambda * lambda) * lambda4;
+ lambda -= delta = (lambda * (0.87 - 0.000952426 * lambda4) - x) / (0.87 - 0.00476213 * lambda4);
+ } while (abs(delta) > epsilon$1 && --i > 0);
+ return [lambda, phi];
+};
+
+function ginzburg8() {
+ return d3Geo.geoProjection(ginzburg8Raw)
+ .scale(131.747);
+}
+
+var ginzburg9Raw = ginzburgPolyconicRaw(2.6516, -0.76534, 0.19123, -0.047094, 1.36289, -0.13965,0.031762);
+
+function ginzburg9() {
+ return d3Geo.geoProjection(ginzburg9Raw)
+ .scale(131.087);
+}
+
+function squareRaw(project) {
+ var dx = project(halfPi, 0)[0] - project(-halfPi, 0)[0];
+
+ function projectSquare(lambda, phi) {
+ var s = lambda > 0 ? -0.5 : 0.5,
+ point = project(lambda + s * pi, phi);
+ point[0] -= s * dx;
+ return point;
+ }
+
+ if (project.invert) projectSquare.invert = function(x, y) {
+ var s = x > 0 ? -0.5 : 0.5,
+ location = project.invert(x + s * dx, y),
+ lambda = location[0] - s * pi;
+ if (lambda < -pi) lambda += 2 * pi;
+ else if (lambda > pi) lambda -= 2 * pi;
+ location[0] = lambda;
+ return location;
+ };
+
+ return projectSquare;
+}
+
+function gringortenRaw(lambda, phi) {
+ var sLambda = sign(lambda),
+ sPhi = sign(phi),
+ cosPhi = cos(phi),
+ x = cos(lambda) * cosPhi,
+ y = sin(lambda) * cosPhi,
+ z = sin(sPhi * phi);
+ lambda = abs(atan2(y, z));
+ phi = asin(x);
+ if (abs(lambda - halfPi) > epsilon$1) lambda %= halfPi;
+ var point = gringortenHexadecant(lambda > pi / 4 ? halfPi - lambda : lambda, phi);
+ if (lambda > pi / 4) z = point[0], point[0] = -point[1], point[1] = -z;
+ return (point[0] *= sLambda, point[1] *= -sPhi, point);
+}
+
+gringortenRaw.invert = function(x, y) {
+ if (abs(x) > 1) x = sign(x) * 2 - x;
+ if (abs(y) > 1) y = sign(y) * 2 - y;
+ var sx = sign(x),
+ sy = sign(y),
+ x0 = -sx * x,
+ y0 = -sy * y,
+ t = y0 / x0 < 1,
+ p = gringortenHexadecantInvert(t ? y0 : x0, t ? x0 : y0),
+ lambda = p[0],
+ phi = p[1],
+ cosPhi = cos(phi);
+ if (t) lambda = -halfPi - lambda;
+ return [sx * (atan2(sin(lambda) * cosPhi, -sin(phi)) + pi), sy * asin(cos(lambda) * cosPhi)];
+};
+
+function gringortenHexadecant(lambda, phi) {
+ if (phi === halfPi) return [0, 0];
+
+ var sinPhi = sin(phi),
+ r = sinPhi * sinPhi,
+ r2 = r * r,
+ j = 1 + r2,
+ k = 1 + 3 * r2,
+ q = 1 - r2,
+ z = asin(1 / sqrt(j)),
+ v = q + r * j * z,
+ p2 = (1 - sinPhi) / v,
+ p = sqrt(p2),
+ a2 = p2 * j,
+ a = sqrt(a2),
+ h = p * q,
+ x,
+ i;
+
+ if (lambda === 0) return [0, -(h + r * a)];
+
+ var cosPhi = cos(phi),
+ secPhi = 1 / cosPhi,
+ drdPhi = 2 * sinPhi * cosPhi,
+ dvdPhi = (-3 * r + z * k) * drdPhi,
+ dp2dPhi = (-v * cosPhi - (1 - sinPhi) * dvdPhi) / (v * v),
+ dpdPhi = (0.5 * dp2dPhi) / p,
+ dhdPhi = q * dpdPhi - 2 * r * p * drdPhi,
+ dra2dPhi = r * j * dp2dPhi + p2 * k * drdPhi,
+ mu = -secPhi * drdPhi,
+ nu = -secPhi * dra2dPhi,
+ zeta = -2 * secPhi * dhdPhi,
+ lambda1 = 4 * lambda / pi,
+ delta;
+
+ // Slower but accurate bisection method.
+ if (lambda > 0.222 * pi || phi < pi / 4 && lambda > 0.175 * pi) {
+ x = (h + r * sqrt(a2 * (1 + r2) - h * h)) / (1 + r2);
+ if (lambda > pi / 4) return [x, x];
+ var x1 = x, x0 = 0.5 * x;
+ x = 0.5 * (x0 + x1), i = 50;
+ do {
+ var g = sqrt(a2 - x * x),
+ f = (x * (zeta + mu * g) + nu * asin(x / a)) - lambda1;
+ if (!f) break;
+ if (f < 0) x0 = x;
+ else x1 = x;
+ x = 0.5 * (x0 + x1);
+ } while (abs(x1 - x0) > epsilon$1 && --i > 0);
+ }
+
+ // Newton-Raphson.
+ else {
+ x = epsilon$1, i = 25;
+ do {
+ var x2 = x * x,
+ g2 = sqrt(a2 - x2),
+ zetaMug = zeta + mu * g2,
+ f2 = x * zetaMug + nu * asin(x / a) - lambda1,
+ df = zetaMug + (nu - mu * x2) / g2;
+ x -= delta = g2 ? f2 / df : 0;
+ } while (abs(delta) > epsilon$1 && --i > 0);
+ }
+
+ return [x, -h - r * sqrt(a2 - x * x)];
+}
+
+function gringortenHexadecantInvert(x, y) {
+ var x0 = 0,
+ x1 = 1,
+ r = 0.5,
+ i = 50;
+
+ while (true) {
+ var r2 = r * r,
+ sinPhi = sqrt(r),
+ z = asin(1 / sqrt(1 + r2)),
+ v = (1 - r2) + r * (1 + r2) * z,
+ p2 = (1 - sinPhi) / v,
+ p = sqrt(p2),
+ a2 = p2 * (1 + r2),
+ h = p * (1 - r2),
+ g2 = a2 - x * x,
+ g = sqrt(g2),
+ y0 = y + h + r * g;
+ if (abs(x1 - x0) < epsilon2 || --i === 0 || y0 === 0) break;
+ if (y0 > 0) x0 = r;
+ else x1 = r;
+ r = 0.5 * (x0 + x1);
+ }
+
+ if (!i) return null;
+
+ var phi = asin(sinPhi),
+ cosPhi = cos(phi),
+ secPhi = 1 / cosPhi,
+ drdPhi = 2 * sinPhi * cosPhi,
+ dvdPhi = (-3 * r + z * (1 + 3 * r2)) * drdPhi,
+ dp2dPhi = (-v * cosPhi - (1 - sinPhi) * dvdPhi) / (v * v),
+ dpdPhi = 0.5 * dp2dPhi / p,
+ dhdPhi = (1 - r2) * dpdPhi - 2 * r * p * drdPhi,
+ zeta = -2 * secPhi * dhdPhi,
+ mu = -secPhi * drdPhi,
+ nu = -secPhi * (r * (1 + r2) * dp2dPhi + p2 * (1 + 3 * r2) * drdPhi);
+
+ return [pi / 4 * (x * (zeta + mu * g) + nu * asin(x / sqrt(a2))), phi];
+}
+
+function gringorten$1() {
+ return d3Geo.geoProjection(squareRaw(gringortenRaw))
+ .scale(239.75);
+}
+
+// Returns [sn, cn, dn](u + iv|m).
+function ellipticJi(u, v, m) {
+ var a, b, c;
+ if (!u) {
+ b = ellipticJ(v, 1 - m);
+ return [
+ [0, b[0] / b[1]],
+ [1 / b[1], 0],
+ [b[2] / b[1], 0]
+ ];
+ }
+ a = ellipticJ(u, m);
+ if (!v) return [[a[0], 0], [a[1], 0], [a[2], 0]];
+ b = ellipticJ(v, 1 - m);
+ c = b[1] * b[1] + m * a[0] * a[0] * b[0] * b[0];
+ return [
+ [a[0] * b[2] / c, a[1] * a[2] * b[0] * b[1] / c],
+ [a[1] * b[1] / c, -a[0] * a[2] * b[0] * b[2] / c],
+ [a[2] * b[1] * b[2] / c, -m * a[0] * a[1] * b[0] / c]
+ ];
+}
+
+// Returns [sn, cn, dn, ph](u|m).
+function ellipticJ(u, m) {
+ var ai, b, phi, t, twon;
+ if (m < epsilon$1) {
+ t = sin(u);
+ b = cos(u);
+ ai = m * (u - t * b) / 4;
+ return [
+ t - ai * b,
+ b + ai * t,
+ 1 - m * t * t / 2,
+ u - ai
+ ];
+ }
+ if (m >= 1 - epsilon$1) {
+ ai = (1 - m) / 4;
+ b = cosh(u);
+ t = tanh(u);
+ phi = 1 / b;
+ twon = b * sinh(u);
+ return [
+ t + ai * (twon - u) / (b * b),
+ phi - ai * t * phi * (twon - u),
+ phi + ai * t * phi * (twon + u),
+ 2 * atan(exp(u)) - halfPi + ai * (twon - u) / b
+ ];
+ }
+
+ var a = [1, 0, 0, 0, 0, 0, 0, 0, 0],
+ c = [sqrt(m), 0, 0, 0, 0, 0, 0, 0, 0],
+ i = 0;
+ b = sqrt(1 - m);
+ twon = 1;
+
+ while (abs(c[i] / a[i]) > epsilon$1 && i < 8) {
+ ai = a[i++];
+ c[i] = (ai - b) / 2;
+ a[i] = (ai + b) / 2;
+ b = sqrt(ai * b);
+ twon *= 2;
+ }
+
+ phi = twon * a[i] * u;
+ do {
+ t = c[i] * sin(b = phi) / a[i];
+ phi = (asin(t) + phi) / 2;
+ } while (--i);
+
+ return [sin(phi), t = cos(phi), t / cos(phi - b), phi];
+}
+
+// Calculate F(phi+iPsi|m).
+// See Abramowitz and Stegun, 17.4.11.
+function ellipticFi(phi, psi, m) {
+ var r = abs(phi),
+ i = abs(psi),
+ sinhPsi = sinh(i);
+ if (r) {
+ var cscPhi = 1 / sin(r),
+ cotPhi2 = 1 / (tan(r) * tan(r)),
+ b = -(cotPhi2 + m * (sinhPsi * sinhPsi * cscPhi * cscPhi) - 1 + m),
+ c = (m - 1) * cotPhi2,
+ cotLambda2 = (-b + sqrt(b * b - 4 * c)) / 2;
+ return [
+ ellipticF(atan(1 / sqrt(cotLambda2)), m) * sign(phi),
+ ellipticF(atan(sqrt((cotLambda2 / cotPhi2 - 1) / m)), 1 - m) * sign(psi)
+ ];
+ }
+ return [
+ 0,
+ ellipticF(atan(sinhPsi), 1 - m) * sign(psi)
+ ];
+}
+
+// Calculate F(phi|m) where m = k² = sin²α.
+// See Abramowitz and Stegun, 17.6.7.
+function ellipticF(phi, m) {
+ if (!m) return phi;
+ if (m === 1) return log(tan(phi / 2 + quarterPi));
+ var a = 1,
+ b = sqrt(1 - m),
+ c = sqrt(m);
+ for (var i = 0; abs(c) > epsilon$1; i++) {
+ if (phi % pi) {
+ var dPhi = atan(b * tan(phi) / a);
+ if (dPhi < 0) dPhi += pi;
+ phi += dPhi + ~~(phi / pi) * pi;
+ } else phi += phi;
+ c = (a + b) / 2;
+ b = sqrt(a * b);
+ c = ((a = c) - b) / 2;
+ }
+ return phi / (pow(2, i) * a);
+}
+
+function guyouRaw(lambda, phi) {
+ var k_ = (sqrt2 - 1) / (sqrt2 + 1),
+ k = sqrt(1 - k_ * k_),
+ K = ellipticF(halfPi, k * k),
+ f = -1,
+ psi = log(tan(pi / 4 + abs(phi) / 2)),
+ r = exp(f * psi) / sqrt(k_),
+ at = guyouComplexAtan(r * cos(f * lambda), r * sin(f * lambda)),
+ t = ellipticFi(at[0], at[1], k * k);
+ return [-t[1], (phi >= 0 ? 1 : -1) * (0.5 * K - t[0])];
+}
+
+function guyouComplexAtan(x, y) {
+ var x2 = x * x,
+ y_1 = y + 1,
+ t = 1 - x2 - y * y;
+ return [
+ 0.5 * ((x >= 0 ? halfPi : -halfPi) - atan2(t, 2 * x)),
+ -0.25 * log(t * t + 4 * x2) +0.5 * log(y_1 * y_1 + x2)
+ ];
+}
+
+function guyouComplexDivide(a, b) {
+ var denominator = b[0] * b[0] + b[1] * b[1];
+ return [
+ (a[0] * b[0] + a[1] * b[1]) / denominator,
+ (a[1] * b[0] - a[0] * b[1]) / denominator
+ ];
+}
+
+guyouRaw.invert = function(x, y) {
+ var k_ = (sqrt2 - 1) / (sqrt2 + 1),
+ k = sqrt(1 - k_ * k_),
+ K = ellipticF(halfPi, k * k),
+ f = -1,
+ j = ellipticJi(0.5 * K - y, -x, k * k),
+ tn = guyouComplexDivide(j[0], j[1]),
+ lambda = atan2(tn[1], tn[0]) / f;
+ return [
+ lambda,
+ 2 * atan(exp(0.5 / f * log(k_ * tn[0] * tn[0] + k_ * tn[1] * tn[1]))) - halfPi
+ ];
+};
+
+function guyou() {
+ return d3Geo.geoProjection(squareRaw(guyouRaw))
+ .scale(151.496);
+}
+
+function hammerRetroazimuthalRaw(phi0) {
+ var sinPhi0 = sin(phi0),
+ cosPhi0 = cos(phi0),
+ rotate = hammerRetroazimuthalRotation(phi0);
+
+ rotate.invert = hammerRetroazimuthalRotation(-phi0);
+
+ function forward(lambda, phi) {
+ var p = rotate(lambda, phi);
+ lambda = p[0], phi = p[1];
+ var sinPhi = sin(phi),
+ cosPhi = cos(phi),
+ cosLambda = cos(lambda),
+ z = acos(sinPhi0 * sinPhi + cosPhi0 * cosPhi * cosLambda),
+ sinz = sin(z),
+ K = abs(sinz) > epsilon$1 ? z / sinz : 1;
+ return [
+ K * cosPhi0 * sin(lambda),
+ (abs(lambda) > halfPi ? K : -K) // rotate for back hemisphere
+ * (sinPhi0 * cosPhi - cosPhi0 * sinPhi * cosLambda)
+ ];
+ }
+
+ forward.invert = function(x, y) {
+ var rho = sqrt(x * x + y * y),
+ sinz = -sin(rho),
+ cosz = cos(rho),
+ a = rho * cosz,
+ b = -y * sinz,
+ c = rho * sinPhi0,
+ d = sqrt(a * a + b * b - c * c),
+ phi = atan2(a * c + b * d, b * c - a * d),
+ lambda = (rho > halfPi ? -1 : 1) * atan2(x * sinz, rho * cos(phi) * cosz + y * sin(phi) * sinz);
+ return rotate.invert(lambda, phi);
+ };
+
+ return forward;
+}
+
+// Latitudinal rotation by phi0.
+// Temporary hack until D3 supports arbitrary small-circle clipping origins.
+function hammerRetroazimuthalRotation(phi0) {
+ var sinPhi0 = sin(phi0),
+ cosPhi0 = cos(phi0);
+
+ return function(lambda, phi) {
+ var cosPhi = cos(phi),
+ x = cos(lambda) * cosPhi,
+ y = sin(lambda) * cosPhi,
+ z = sin(phi);
+ return [
+ atan2(y, x * cosPhi0 - z * sinPhi0),
+ asin(z * cosPhi0 + x * sinPhi0)
+ ];
+ };
+}
+
+function hammerRetroazimuthal() {
+ var phi0 = 0,
+ m = d3Geo.geoProjectionMutator(hammerRetroazimuthalRaw),
+ p = m(phi0),
+ rotate_ = p.rotate,
+ stream_ = p.stream,
+ circle = d3Geo.geoCircle();
+
+ p.parallel = function(_) {
+ if (!arguments.length) return phi0 * degrees;
+ var r = p.rotate();
+ return m(phi0 = _ * radians).rotate(r);
+ };
+
+ // Temporary hack; see hammerRetroazimuthalRotation.
+ p.rotate = function(_) {
+ if (!arguments.length) return (_ = rotate_.call(p), _[1] += phi0 * degrees, _);
+ rotate_.call(p, [_[0], _[1] - phi0 * degrees]);
+ circle.center([-_[0], -_[1]]);
+ return p;
+ };
+
+ p.stream = function(stream) {
+ stream = stream_(stream);
+ stream.sphere = function() {
+ stream.polygonStart();
+ var epsilon = 1e-2,
+ ring = circle.radius(90 - epsilon)().coordinates[0],
+ n = ring.length - 1,
+ i = -1,
+ p;
+ stream.lineStart();
+ while (++i < n) stream.point((p = ring[i])[0], p[1]);
+ stream.lineEnd();
+ ring = circle.radius(90 + epsilon)().coordinates[0];
+ n = ring.length - 1;
+ stream.lineStart();
+ while (--i >= 0) stream.point((p = ring[i])[0], p[1]);
+ stream.lineEnd();
+ stream.polygonEnd();
+ };
+ return stream;
+ };
+
+ return p
+ .scale(79.4187)
+ .parallel(45)
+ .clipAngle(180 - 1e-3);
+}
+
+var K$1 = 3,
+ healpixParallel = asin(1 - 1 / K$1) * degrees,
+ healpixLambert = cylindricalEqualAreaRaw(0);
+
+function healpixRaw(H) {
+ var phi0 = healpixParallel * radians,
+ dx = collignonRaw(pi, phi0)[0] - collignonRaw(-pi, phi0)[0],
+ y0 = healpixLambert(0, phi0)[1],
+ y1 = collignonRaw(0, phi0)[1],
+ dy1 = sqrtPi - y1,
+ k = tau / H,
+ w = 4 / tau,
+ h = y0 + (dy1 * dy1 * 4) / tau;
+
+ function forward(lambda, phi) {
+ var point,
+ phi2 = abs(phi);
+ if (phi2 > phi0) {
+ var i = min(H - 1, max(0, floor((lambda + pi) / k)));
+ lambda += pi * (H - 1) / H - i * k;
+ point = collignonRaw(lambda, phi2);
+ point[0] = point[0] * tau / dx - tau * (H - 1) / (2 * H) + i * tau / H;
+ point[1] = y0 + (point[1] - y1) * 4 * dy1 / tau;
+ if (phi < 0) point[1] = -point[1];
+ } else {
+ point = healpixLambert(lambda, phi);
+ }
+ point[0] *= w, point[1] /= h;
+ return point;
+ }
+
+ forward.invert = function(x, y) {
+ x /= w, y *= h;
+ var y2 = abs(y);
+ if (y2 > y0) {
+ var i = min(H - 1, max(0, floor((x + pi) / k)));
+ x = (x + pi * (H - 1) / H - i * k) * dx / tau;
+ var point = collignonRaw.invert(x, 0.25 * (y2 - y0) * tau / dy1 + y1);
+ point[0] -= pi * (H - 1) / H - i * k;
+ if (y < 0) point[1] = -point[1];
+ return point;
+ }
+ return healpixLambert.invert(x, y);
+ };
+
+ return forward;
+}
+
+function sphereTop(x, i) {
+ return [x, i & 1 ? 90 - epsilon$1 : healpixParallel];
+}
+
+function sphereBottom(x, i) {
+ return [x, i & 1 ? -90 + epsilon$1 : -healpixParallel];
+}
+
+function sphereNudge(d) {
+ return [d[0] * (1 - epsilon$1), d[1]];
+}
+
+function sphere(step) {
+ var c = [].concat(
+ d3Array.range(-180, 180 + step / 2, step).map(sphereTop),
+ d3Array.range(180, -180 - step / 2, -step).map(sphereBottom)
+ );
+ return {
+ type: "Polygon",
+ coordinates: [step === 180 ? c.map(sphereNudge) : c]
+ };
+}
+
+function healpix() {
+ var H = 4,
+ m = d3Geo.geoProjectionMutator(healpixRaw),
+ p = m(H),
+ stream_ = p.stream;
+
+ p.lobes = function(_) {
+ return arguments.length ? m(H = +_) : H;
+ };
+
+ p.stream = function(stream) {
+ var rotate = p.rotate(),
+ rotateStream = stream_(stream),
+ sphereStream = (p.rotate([0, 0]), stream_(stream));
+ p.rotate(rotate);
+ rotateStream.sphere = function() { d3Geo.geoStream(sphere(180 / H), sphereStream); };
+ return rotateStream;
+ };
+
+ return p
+ .scale(239.75);
+}
+
+function hillRaw(K) {
+ var L = 1 + K,
+ sinBt = sin(1 / L),
+ Bt = asin(sinBt),
+ A = 2 * sqrt(pi / (B = pi + 4 * Bt * L)),
+ B,
+ rho0 = 0.5 * A * (L + sqrt(K * (2 + K))),
+ K2 = K * K,
+ L2 = L * L;
+
+ function forward(lambda, phi) {
+ var t = 1 - sin(phi),
+ rho,
+ omega;
+ if (t && t < 2) {
+ var theta = halfPi - phi, i = 25, delta;
+ do {
+ var sinTheta = sin(theta),
+ cosTheta = cos(theta),
+ Bt_Bt1 = Bt + atan2(sinTheta, L - cosTheta),
+ C = 1 + L2 - 2 * L * cosTheta;
+ theta -= delta = (theta - K2 * Bt - L * sinTheta + C * Bt_Bt1 -0.5 * t * B) / (2 * L * sinTheta * Bt_Bt1);
+ } while (abs(delta) > epsilon2 && --i > 0);
+ rho = A * sqrt(C);
+ omega = lambda * Bt_Bt1 / pi;
+ } else {
+ rho = A * (K + t);
+ omega = lambda * Bt / pi;
+ }
+ return [
+ rho * sin(omega),
+ rho0 - rho * cos(omega)
+ ];
+ }
+
+ forward.invert = function(x, y) {
+ var rho2 = x * x + (y -= rho0) * y,
+ cosTheta = (1 + L2 - rho2 / (A * A)) / (2 * L),
+ theta = acos(cosTheta),
+ sinTheta = sin(theta),
+ Bt_Bt1 = Bt + atan2(sinTheta, L - cosTheta);
+ return [
+ asin(x / sqrt(rho2)) * pi / Bt_Bt1,
+ asin(1 - 2 * (theta - K2 * Bt - L * sinTheta + (1 + L2 - 2 * L * cosTheta) * Bt_Bt1) / B)
+ ];
+ };
+
+ return forward;
+}
+
+function hill() {
+ var K = 1,
+ m = d3Geo.geoProjectionMutator(hillRaw),
+ p = m(K);
+
+ p.ratio = function(_) {
+ return arguments.length ? m(K = +_) : K;
+ };
+
+ return p
+ .scale(167.774)
+ .center([0, 18.67]);
+}
+
+var sinuMollweidePhi = 0.7109889596207567;
+
+var sinuMollweideY = 0.0528035274542;
+
+function sinuMollweideRaw(lambda, phi) {
+ return phi > -sinuMollweidePhi
+ ? (lambda = mollweideRaw(lambda, phi), lambda[1] += sinuMollweideY, lambda)
+ : sinusoidalRaw(lambda, phi);
+}
+
+sinuMollweideRaw.invert = function(x, y) {
+ return y > -sinuMollweidePhi
+ ? mollweideRaw.invert(x, y - sinuMollweideY)
+ : sinusoidalRaw.invert(x, y);
+};
+
+function sinuMollweide$1() {
+ return d3Geo.geoProjection(sinuMollweideRaw)
+ .rotate([-20, -55])
+ .scale(164.263)
+ .center([0, -5.4036]);
+}
+
+function homolosineRaw(lambda, phi) {
+ return abs(phi) > sinuMollweidePhi
+ ? (lambda = mollweideRaw(lambda, phi), lambda[1] -= phi > 0 ? sinuMollweideY : -sinuMollweideY, lambda)
+ : sinusoidalRaw(lambda, phi);
+}
+
+homolosineRaw.invert = function(x, y) {
+ return abs(y) > sinuMollweidePhi
+ ? mollweideRaw.invert(x, y + (y > 0 ? sinuMollweideY : -sinuMollweideY))
+ : sinusoidalRaw.invert(x, y);
+};
+
+function homolosine$1() {
+ return d3Geo.geoProjection(homolosineRaw)
+ .scale(152.63);
+}
+
+function hufnagelRaw(a, b, psiMax, ratio) {
+ var k = sqrt(
+ (4 * pi) /
+ (2 * psiMax +
+ (1 + a - b / 2) * sin(2 * psiMax) +
+ ((a + b) / 2) * sin(4 * psiMax) +
+ (b / 2) * sin(6 * psiMax))
+ ),
+ c = sqrt(
+ ratio *
+ sin(psiMax) *
+ sqrt((1 + a * cos(2 * psiMax) + b * cos(4 * psiMax)) / (1 + a + b))
+ ),
+ M = psiMax * mapping(1);
+
+ function radius(psi) {
+ return sqrt(1 + a * cos(2 * psi) + b * cos(4 * psi));
+ }
+
+ function mapping(t) {
+ var psi = t * psiMax;
+ return (
+ (2 * psi +
+ (1 + a - b / 2) * sin(2 * psi) +
+ ((a + b) / 2) * sin(4 * psi) +
+ (b / 2) * sin(6 * psi)) /
+ psiMax
+ );
+ }
+
+ function inversemapping(psi) {
+ return radius(psi) * sin(psi);
+ }
+
+ var forward = function(lambda, phi) {
+ var psi = psiMax * solve(mapping, (M * sin(phi)) / psiMax, phi / pi);
+ if (isNaN(psi)) psi = psiMax * sign(phi);
+ var kr = k * radius(psi);
+ return [((kr * c * lambda) / pi) * cos(psi), (kr / c) * sin(psi)];
+ };
+
+ forward.invert = function(x, y) {
+ var psi = solve(inversemapping, (y * c) / k);
+ return [
+ (x * pi) / (cos(psi) * k * c * radius(psi)),
+ asin((psiMax * mapping(psi / psiMax)) / M)
+ ];
+ };
+
+ if (psiMax === 0) {
+ k = sqrt(ratio / pi);
+ forward = function(lambda, phi) {
+ return [lambda * k, sin(phi) / k];
+ };
+ forward.invert = function(x, y) {
+ return [x / k, asin(y * k)];
+ };
+ }
+
+ return forward;
+}
+
+function hufnagel() {
+ var a = 1,
+ b = 0,
+ psiMax = 45 * radians,
+ ratio = 2,
+ mutate = d3Geo.geoProjectionMutator(hufnagelRaw),
+ projection = mutate(a, b, psiMax, ratio);
+
+ projection.a = function(_) {
+ return arguments.length ? mutate((a = +_), b, psiMax, ratio) : a;
+ };
+ projection.b = function(_) {
+ return arguments.length ? mutate(a, (b = +_), psiMax, ratio) : b;
+ };
+ projection.psiMax = function(_) {
+ return arguments.length
+ ? mutate(a, b, (psiMax = +_ * radians), ratio)
+ : psiMax * degrees;
+ };
+ projection.ratio = function(_) {
+ return arguments.length ? mutate(a, b, psiMax, (ratio = +_)) : ratio;
+ };
+
+ return projection.scale(180.739);
+}
+
+// https://github.com/scijs/integrate-adaptive-simpson
+
+// This algorithm adapted from pseudocode in:
+// http://www.math.utk.edu/~ccollins/refs/Handouts/rich.pdf
+function adsimp (f, a, b, fa, fm, fb, V0, tol, maxdepth, depth, state) {
+ if (state.nanEncountered) {
+ return NaN;
+ }
+
+ var h, f1, f2, sl, sr, s2, m, V1, V2, err;
+
+ h = b - a;
+ f1 = f(a + h * 0.25);
+ f2 = f(b - h * 0.25);
+
+ // Simple check for NaN:
+ if (isNaN(f1)) {
+ state.nanEncountered = true;
+ return;
+ }
+
+ // Simple check for NaN:
+ if (isNaN(f2)) {
+ state.nanEncountered = true;
+ return;
+ }
+
+ sl = h * (fa + 4 * f1 + fm) / 12;
+ sr = h * (fm + 4 * f2 + fb) / 12;
+ s2 = sl + sr;
+ err = (s2 - V0) / 15;
+
+ if (depth > maxdepth) {
+ state.maxDepthCount++;
+ return s2 + err;
+ } else if (Math.abs(err) < tol) {
+ return s2 + err;
+ } else {
+ m = a + h * 0.5;
+
+ V1 = adsimp(f, a, m, fa, f1, fm, sl, tol * 0.5, maxdepth, depth + 1, state);
+
+ if (isNaN(V1)) {
+ state.nanEncountered = true;
+ return NaN;
+ }
+
+ V2 = adsimp(f, m, b, fm, f2, fb, sr, tol * 0.5, maxdepth, depth + 1, state);
+
+ if (isNaN(V2)) {
+ state.nanEncountered = true;
+ return NaN;
+ }
+
+ return V1 + V2;
+ }
+}
+
+function integrate (f, a, b, tol, maxdepth) {
+ var state = {
+ maxDepthCount: 0,
+ nanEncountered: false
+ };
+
+ if (tol === undefined) {
+ tol = 1e-8;
+ }
+ if (maxdepth === undefined) {
+ maxdepth = 20;
+ }
+
+ var fa = f(a);
+ var fm = f(0.5 * (a + b));
+ var fb = f(b);
+
+ var V0 = (fa + 4 * fm + fb) * (b - a) / 6;
+
+ var result = adsimp(f, a, b, fa, fm, fb, V0, tol, maxdepth, 1, state);
+
+/*
+ if (state.maxDepthCount > 0 && console && console.warn) {
+ console.warn('integrate-adaptive-simpson: Warning: maximum recursion depth (' + maxdepth + ') reached ' + state.maxDepthCount + ' times');
+ }
+
+ if (state.nanEncountered && console && console.warn) {
+ console.warn('integrate-adaptive-simpson: Warning: NaN encountered. Halting early.');
+ }
+*/
+
+ return result;
+}
+
+function hyperellipticalRaw(alpha, k, gamma) {
+
+ function elliptic (f) {
+ return alpha + (1 - alpha) * pow(1 - pow(f, k), 1 / k);
+ }
+
+ function z(f) {
+ return integrate(elliptic, 0, f, 1e-4);
+ }
+
+ var G = 1 / z(1),
+ n = 1000,
+ m = (1 + 1e-8) * G,
+ approx = [];
+ for (var i = 0; i <= n; i++)
+ approx.push(z(i / n) * m);
+
+ function Y(sinphi) {
+ var rmin = 0, rmax = n, r = n >> 1;
+ do {
+ if (approx[r] > sinphi) rmax = r; else rmin = r;
+ r = (rmin + rmax) >> 1;
+ } while (r > rmin);
+ var u = approx[r + 1] - approx[r];
+ if (u) u = (sinphi - approx[r + 1]) / u;
+ return (r + 1 + u) / n;
+ }
+
+ var ratio = 2 * Y(1) / pi * G / gamma;
+
+ var forward = function(lambda, phi) {
+ var y = Y(abs(sin(phi))),
+ x = elliptic(y) * lambda;
+ y /= ratio;
+ return [ x, (phi >= 0) ? y : -y ];
+ };
+
+ forward.invert = function(x, y) {
+ var phi;
+ y *= ratio;
+ if (abs(y) < 1) phi = sign(y) * asin(z(abs(y)) * G);
+ return [ x / elliptic(abs(y)), phi ];
+ };
+
+ return forward;
+}
+
+function hyperelliptical() {
+ var alpha = 0,
+ k = 2.5,
+ gamma = 1.183136, // affine = sqrt(2 * gamma / pi) = 0.8679
+ m = d3Geo.geoProjectionMutator(hyperellipticalRaw),
+ p = m(alpha, k, gamma);
+
+ p.alpha = function(_) {
+ return arguments.length ? m(alpha = +_, k, gamma) : alpha;
+ };
+
+ p.k = function(_) {
+ return arguments.length ? m(alpha, k = +_, gamma) : k;
+ };
+
+ p.gamma = function(_) {
+ return arguments.length ? m(alpha, k, gamma = +_) : gamma;
+ };
+
+ return p
+ .scale(152.63);
+}
+
+function pointEqual$1(a, b) {
+ return abs(a[0] - b[0]) < epsilon$1 && abs(a[1] - b[1]) < epsilon$1;
+}
+
+function interpolateLine(coordinates, m) {
+ var i = -1,
+ n = coordinates.length,
+ p0 = coordinates[0],
+ p1,
+ dx,
+ dy,
+ resampled = [];
+ while (++i < n) {
+ p1 = coordinates[i];
+ dx = (p1[0] - p0[0]) / m;
+ dy = (p1[1] - p0[1]) / m;
+ for (var j = 0; j < m; ++j) resampled.push([p0[0] + j * dx, p0[1] + j * dy]);
+ p0 = p1;
+ }
+ resampled.push(p1);
+ return resampled;
+}
+
+function interpolateSphere(lobes) {
+ var coordinates = [],
+ lobe,
+ lambda0, phi0, phi1,
+ lambda2, phi2,
+ i, n = lobes[0].length;
+
+ // Northern Hemisphere
+ for (i = 0; i < n; ++i) {
+ lobe = lobes[0][i];
+ lambda0 = lobe[0][0], phi0 = lobe[0][1], phi1 = lobe[1][1];
+ lambda2 = lobe[2][0], phi2 = lobe[2][1];
+ coordinates.push(interpolateLine([
+ [lambda0 + epsilon$1, phi0 + epsilon$1],
+ [lambda0 + epsilon$1, phi1 - epsilon$1],
+ [lambda2 - epsilon$1, phi1 - epsilon$1],
+ [lambda2 - epsilon$1, phi2 + epsilon$1]
+ ], 30));
+ }
+
+ // Southern Hemisphere
+ for (i = lobes[1].length - 1; i >= 0; --i) {
+ lobe = lobes[1][i];
+ lambda0 = lobe[0][0], phi0 = lobe[0][1], phi1 = lobe[1][1];
+ lambda2 = lobe[2][0], phi2 = lobe[2][1];
+ coordinates.push(interpolateLine([
+ [lambda2 - epsilon$1, phi2 - epsilon$1],
+ [lambda2 - epsilon$1, phi1 + epsilon$1],
+ [lambda0 + epsilon$1, phi1 + epsilon$1],
+ [lambda0 + epsilon$1, phi0 - epsilon$1]
+ ], 30));
+ }
+
+ return {
+ type: "Polygon",
+ coordinates: [d3Array.merge(coordinates)]
+ };
+}
+
+function interrupt(project, lobes, inverse) {
+ var sphere, bounds;
+
+ function forward(lambda, phi) {
+ var sign = phi < 0 ? -1 : +1, lobe = lobes[+(phi < 0)];
+ for (var i = 0, n = lobe.length - 1; i < n && lambda > lobe[i][2][0]; ++i);
+ var p = project(lambda - lobe[i][1][0], phi);
+ p[0] += project(lobe[i][1][0], sign * phi > sign * lobe[i][0][1] ? lobe[i][0][1] : phi)[0];
+ return p;
+ }
+
+ if (inverse) {
+ forward.invert = inverse(forward);
+ } else if (project.invert) {
+ forward.invert = function(x, y) {
+ var bound = bounds[+(y < 0)], lobe = lobes[+(y < 0)];
+ for (var i = 0, n = bound.length; i < n; ++i) {
+ var b = bound[i];
+ if (b[0][0] <= x && x < b[1][0] && b[0][1] <= y && y < b[1][1]) {
+ var p = project.invert(x - project(lobe[i][1][0], 0)[0], y);
+ p[0] += lobe[i][1][0];
+ return pointEqual$1(forward(p[0], p[1]), [x, y]) ? p : null;
+ }
+ }
+ };
+ }
+
+ var p = d3Geo.geoProjection(forward),
+ stream_ = p.stream;
+
+ p.stream = function(stream) {
+ var rotate = p.rotate(),
+ rotateStream = stream_(stream),
+ sphereStream = (p.rotate([0, 0]), stream_(stream));
+ p.rotate(rotate);
+ rotateStream.sphere = function() { d3Geo.geoStream(sphere, sphereStream); };
+ return rotateStream;
+ };
+
+ p.lobes = function(_) {
+ if (!arguments.length) return lobes.map(function(lobe) {
+ return lobe.map(function(l) {
+ return [
+ [l[0][0] * degrees, l[0][1] * degrees],
+ [l[1][0] * degrees, l[1][1] * degrees],
+ [l[2][0] * degrees, l[2][1] * degrees]
+ ];
+ });
+ });
+
+ sphere = interpolateSphere(_);
+
+ lobes = _.map(function(lobe) {
+ return lobe.map(function(l) {
+ return [
+ [l[0][0] * radians, l[0][1] * radians],
+ [l[1][0] * radians, l[1][1] * radians],
+ [l[2][0] * radians, l[2][1] * radians]
+ ];
+ });
+ });
+
+ bounds = lobes.map(function(lobe) {
+ return lobe.map(function(l) {
+ var x0 = project(l[0][0], l[0][1])[0],
+ x1 = project(l[2][0], l[2][1])[0],
+ y0 = project(l[1][0], l[0][1])[1],
+ y1 = project(l[1][0], l[1][1])[1],
+ t;
+ if (y0 > y1) t = y0, y0 = y1, y1 = t;
+ return [[x0, y0], [x1, y1]];
+ });
+ });
+
+ return p;
+ };
+
+ if (lobes != null) p.lobes(lobes);
+
+ return p;
+}
+
+var lobes$6 = [[ // northern hemisphere
+ [[-180, 0], [-100, 90], [ -40, 0]],
+ [[ -40, 0], [ 30, 90], [ 180, 0]]
+], [ // southern hemisphere
+ [[-180, 0], [-160, -90], [-100, 0]],
+ [[-100, 0], [ -60, -90], [ -20, 0]],
+ [[ -20, 0], [ 20, -90], [ 80, 0]],
+ [[ 80, 0], [ 140, -90], [ 180, 0]]
+]];
+
+function boggs() {
+ return interrupt(boggsRaw, lobes$6)
+ .scale(160.857);
+}
+
+var lobes$5 = [[ // northern hemisphere
+ [[-180, 0], [-100, 90], [ -40, 0]],
+ [[ -40, 0], [ 30, 90], [ 180, 0]]
+], [ // southern hemisphere
+ [[-180, 0], [-160, -90], [-100, 0]],
+ [[-100, 0], [ -60, -90], [ -20, 0]],
+ [[ -20, 0], [ 20, -90], [ 80, 0]],
+ [[ 80, 0], [ 140, -90], [ 180, 0]]
+]];
+
+function homolosine() {
+ return interrupt(homolosineRaw, lobes$5)
+ .scale(152.63);
+}
+
+var lobes$4 = [[ // northern hemisphere
+ [[-180, 0], [-100, 90], [ -40, 0]],
+ [[ -40, 0], [ 30, 90], [ 180, 0]]
+], [ // southern hemisphere
+ [[-180, 0], [-160, -90], [-100, 0]],
+ [[-100, 0], [ -60, -90], [ -20, 0]],
+ [[ -20, 0], [ 20, -90], [ 80, 0]],
+ [[ 80, 0], [ 140, -90], [ 180, 0]]
+]];
+
+function mollweide() {
+ return interrupt(mollweideRaw, lobes$4)
+ .scale(169.529);
+}
+
+var lobes$3 = [[ // northern hemisphere
+ [[-180, 0], [ -90, 90], [ 0, 0]],
+ [[ 0, 0], [ 90, 90], [ 180, 0]]
+], [ // southern hemisphere
+ [[-180, 0], [ -90, -90], [ 0, 0]],
+ [[ 0, 0], [ 90, -90], [ 180, 0]]
+]];
+
+function mollweideHemispheres() {
+ return interrupt(mollweideRaw, lobes$3)
+ .scale(169.529)
+ .rotate([20, 0]);
+}
+
+var lobes$2 = [[ // northern hemisphere
+ [[-180, 35], [ -30, 90], [ 0, 35]],
+ [[ 0, 35], [ 30, 90], [ 180, 35]]
+], [ // southern hemisphere
+ [[-180, -10], [-102, -90], [ -65, -10]],
+ [[ -65, -10], [ 5, -90], [ 77, -10]],
+ [[ 77, -10], [ 103, -90], [ 180, -10]]
+]];
+
+function sinuMollweide() {
+ return interrupt(sinuMollweideRaw, lobes$2, solve2d)
+ .rotate([-20, -55])
+ .scale(164.263)
+ .center([0, -5.4036]);
+}
+
+var lobes$1 = [[ // northern hemisphere
+ [[-180, 0], [-110, 90], [ -40, 0]],
+ [[ -40, 0], [ 0, 90], [ 40, 0]],
+ [[ 40, 0], [ 110, 90], [ 180, 0]]
+], [ // southern hemisphere
+ [[-180, 0], [-110, -90], [ -40, 0]],
+ [[ -40, 0], [ 0, -90], [ 40, 0]],
+ [[ 40, 0], [ 110, -90], [ 180, 0]]
+]];
+
+function sinusoidal() {
+ return interrupt(sinusoidalRaw, lobes$1)
+ .scale(152.63)
+ .rotate([-20, 0]);
+}
+
+function kavrayskiy7Raw(lambda, phi) {
+ return [3 / tau * lambda * sqrt(pi * pi / 3 - phi * phi), phi];
+}
+
+kavrayskiy7Raw.invert = function(x, y) {
+ return [tau / 3 * x / sqrt(pi * pi / 3 - y * y), y];
+};
+
+function kavrayskiy7() {
+ return d3Geo.geoProjection(kavrayskiy7Raw)
+ .scale(158.837);
+}
+
+function lagrangeRaw(n) {
+
+ function forward(lambda, phi) {
+ if (abs(abs(phi) - halfPi) < epsilon$1) return [0, phi < 0 ? -2 : 2];
+ var sinPhi = sin(phi),
+ v = pow((1 + sinPhi) / (1 - sinPhi), n / 2),
+ c = 0.5 * (v + 1 / v) + cos(lambda *= n);
+ return [
+ 2 * sin(lambda) / c,
+ (v - 1 / v) / c
+ ];
+ }
+
+ forward.invert = function(x, y) {
+ var y0 = abs(y);
+ if (abs(y0 - 2) < epsilon$1) return x ? null : [0, sign(y) * halfPi];
+ if (y0 > 2) return null;
+
+ x /= 2, y /= 2;
+ var x2 = x * x,
+ y2 = y * y,
+ t = 2 * y / (1 + x2 + y2); // tanh(nPhi)
+ t = pow((1 + t) / (1 - t), 1 / n);
+ return [
+ atan2(2 * x, 1 - x2 - y2) / n,
+ asin((t - 1) / (t + 1))
+ ];
+ };
+
+ return forward;
+}
+
+function lagrange() {
+ var n = 0.5,
+ m = d3Geo.geoProjectionMutator(lagrangeRaw),
+ p = m(n);
+
+ p.spacing = function(_) {
+ return arguments.length ? m(n = +_) : n;
+ };
+
+ return p
+ .scale(124.75);
+}
+
+var pi_sqrt2 = pi / sqrt2;
+
+function larriveeRaw(lambda, phi) {
+ return [
+ lambda * (1 + sqrt(cos(phi))) / 2,
+ phi / (cos(phi / 2) * cos(lambda / 6))
+ ];
+}
+
+larriveeRaw.invert = function(x, y) {
+ var x0 = abs(x),
+ y0 = abs(y),
+ lambda = epsilon$1,
+ phi = halfPi;
+ if (y0 < pi_sqrt2) phi *= y0 / pi_sqrt2;
+ else lambda += 6 * acos(pi_sqrt2 / y0);
+ for (var i = 0; i < 25; i++) {
+ var sinPhi = sin(phi),
+ sqrtcosPhi = sqrt(cos(phi)),
+ sinPhi_2 = sin(phi / 2),
+ cosPhi_2 = cos(phi / 2),
+ sinLambda_6 = sin(lambda / 6),
+ cosLambda_6 = cos(lambda / 6),
+ f0 = 0.5 * lambda * (1 + sqrtcosPhi) - x0,
+ f1 = phi / (cosPhi_2 * cosLambda_6) - y0,
+ df0dPhi = sqrtcosPhi ? -0.25 * lambda * sinPhi / sqrtcosPhi : 0,
+ df0dLambda = 0.5 * (1 + sqrtcosPhi),
+ df1dPhi = (1 + 0.5 * phi * sinPhi_2 / cosPhi_2) / (cosPhi_2 * cosLambda_6),
+ df1dLambda = (phi / cosPhi_2) * (sinLambda_6 / 6) / (cosLambda_6 * cosLambda_6),
+ denom = df0dPhi * df1dLambda - df1dPhi * df0dLambda,
+ dPhi = (f0 * df1dLambda - f1 * df0dLambda) / denom,
+ dLambda = (f1 * df0dPhi - f0 * df1dPhi) / denom;
+ phi -= dPhi;
+ lambda -= dLambda;
+ if (abs(dPhi) < epsilon$1 && abs(dLambda) < epsilon$1) break;
+ }
+ return [x < 0 ? -lambda : lambda, y < 0 ? -phi : phi];
+};
+
+function larrivee() {
+ return d3Geo.geoProjection(larriveeRaw)
+ .scale(97.2672);
+}
+
+function laskowskiRaw(lambda, phi) {
+ var lambda2 = lambda * lambda, phi2 = phi * phi;
+ return [
+ lambda * (0.975534 + phi2 * (-0.119161 + lambda2 * -0.0143059 + phi2 * -0.0547009)),
+ phi * (1.00384 + lambda2 * (0.0802894 + phi2 * -0.02855 + lambda2 * 0.000199025) + phi2 * (0.0998909 + phi2 * -0.0491032))
+ ];
+}
+
+laskowskiRaw.invert = function(x, y) {
+ var lambda = sign(x) * pi,
+ phi = y / 2,
+ i = 50;
+ do {
+ var lambda2 = lambda * lambda,
+ phi2 = phi * phi,
+ lambdaPhi = lambda * phi,
+ fx = lambda * (0.975534 + phi2 * (-0.119161 + lambda2 * -0.0143059 + phi2 * -0.0547009)) - x,
+ fy = phi * (1.00384 + lambda2 * (0.0802894 + phi2 * -0.02855 + lambda2 * 0.000199025) + phi2 * (0.0998909 + phi2 * -0.0491032)) - y,
+ deltaxDeltaLambda = 0.975534 - phi2 * (0.119161 + 3 * lambda2 * 0.0143059 + phi2 * 0.0547009),
+ deltaxDeltaPhi = -lambdaPhi * (2 * 0.119161 + 4 * 0.0547009 * phi2 + 2 * 0.0143059 * lambda2),
+ deltayDeltaLambda = lambdaPhi * (2 * 0.0802894 + 4 * 0.000199025 * lambda2 + 2 * -0.02855 * phi2),
+ deltayDeltaPhi = 1.00384 + lambda2 * (0.0802894 + 0.000199025 * lambda2) + phi2 * (3 * (0.0998909 - 0.02855 * lambda2) - 5 * 0.0491032 * phi2),
+ denominator = deltaxDeltaPhi * deltayDeltaLambda - deltayDeltaPhi * deltaxDeltaLambda,
+ deltaLambda = (fy * deltaxDeltaPhi - fx * deltayDeltaPhi) / denominator,
+ deltaPhi = (fx * deltayDeltaLambda - fy * deltaxDeltaLambda) / denominator;
+ lambda -= deltaLambda, phi -= deltaPhi;
+ } while ((abs(deltaLambda) > epsilon$1 || abs(deltaPhi) > epsilon$1) && --i > 0);
+ return i && [lambda, phi];
+};
+
+function laskowski() {
+ return d3Geo.geoProjection(laskowskiRaw)
+ .scale(139.98);
+}
+
+function littrowRaw(lambda, phi) {
+ return [
+ sin(lambda) / cos(phi),
+ tan(phi) * cos(lambda)
+ ];
+}
+
+littrowRaw.invert = function(x, y) {
+ var x2 = x * x,
+ y2 = y * y,
+ y2_1 = y2 + 1,
+ x2_y2_1 = x2 + y2_1,
+ cosPhi = x
+ ? sqrt1_2 * sqrt((x2_y2_1 - sqrt(x2_y2_1 * x2_y2_1 - 4 * x2)) / x2)
+ : 1 / sqrt(y2_1);
+ return [
+ asin(x * cosPhi),
+ sign(y) * acos(cosPhi)
+ ];
+};
+
+function littrow() {
+ return d3Geo.geoProjection(littrowRaw)
+ .scale(144.049)
+ .clipAngle(90 - 1e-3);
+}
+
+function loximuthalRaw(phi0) {
+ var cosPhi0 = cos(phi0),
+ tanPhi0 = tan(quarterPi + phi0 / 2);
+
+ function forward(lambda, phi) {
+ var y = phi - phi0,
+ x = abs(y) < epsilon$1 ? lambda * cosPhi0
+ : abs(x = quarterPi + phi / 2) < epsilon$1 || abs(abs(x) - halfPi) < epsilon$1
+ ? 0 : lambda * y / log(tan(x) / tanPhi0);
+ return [x, y];
+ }
+
+ forward.invert = function(x, y) {
+ var lambda,
+ phi = y + phi0;
+ return [
+ abs(y) < epsilon$1 ? x / cosPhi0
+ : (abs(lambda = quarterPi + phi / 2) < epsilon$1 || abs(abs(lambda) - halfPi) < epsilon$1) ? 0
+ : x * log(tan(lambda) / tanPhi0) / y,
+ phi
+ ];
+ };
+
+ return forward;
+}
+
+function loximuthal() {
+ return parallel1(loximuthalRaw)
+ .parallel(40)
+ .scale(158.837);
+}
+
+function millerRaw(lambda, phi) {
+ return [lambda, 1.25 * log(tan(quarterPi + 0.4 * phi))];
+}
+
+millerRaw.invert = function(x, y) {
+ return [x, 2.5 * atan(exp(0.8 * y)) - 0.625 * pi];
+};
+
+function miller$1() {
+ return d3Geo.geoProjection(millerRaw)
+ .scale(108.318);
+}
+
+function modifiedStereographicRaw(C) {
+ var m = C.length - 1;
+
+ function forward(lambda, phi) {
+ var cosPhi = cos(phi),
+ k = 2 / (1 + cosPhi * cos(lambda)),
+ zr = k * cosPhi * sin(lambda),
+ zi = k * sin(phi),
+ i = m,
+ w = C[i],
+ ar = w[0],
+ ai = w[1],
+ t;
+ while (--i >= 0) {
+ w = C[i];
+ ar = w[0] + zr * (t = ar) - zi * ai;
+ ai = w[1] + zr * ai + zi * t;
+ }
+ ar = zr * (t = ar) - zi * ai;
+ ai = zr * ai + zi * t;
+ return [ar, ai];
+ }
+
+ forward.invert = function(x, y) {
+ var i = 20,
+ zr = x,
+ zi = y;
+ do {
+ var j = m,
+ w = C[j],
+ ar = w[0],
+ ai = w[1],
+ br = 0,
+ bi = 0,
+ t;
+
+ while (--j >= 0) {
+ w = C[j];
+ br = ar + zr * (t = br) - zi * bi;
+ bi = ai + zr * bi + zi * t;
+ ar = w[0] + zr * (t = ar) - zi * ai;
+ ai = w[1] + zr * ai + zi * t;
+ }
+ br = ar + zr * (t = br) - zi * bi;
+ bi = ai + zr * bi + zi * t;
+ ar = zr * (t = ar) - zi * ai - x;
+ ai = zr * ai + zi * t - y;
+
+ var denominator = br * br + bi * bi, deltar, deltai;
+ zr -= deltar = (ar * br + ai * bi) / denominator;
+ zi -= deltai = (ai * br - ar * bi) / denominator;
+ } while (abs(deltar) + abs(deltai) > epsilon$1 * epsilon$1 && --i > 0);
+
+ if (i) {
+ var rho = sqrt(zr * zr + zi * zi),
+ c = 2 * atan(rho * 0.5),
+ sinc = sin(c);
+ return [atan2(zr * sinc, rho * cos(c)), rho ? asin(zi * sinc / rho) : 0];
+ }
+ };
+
+ return forward;
+}
+
+var alaska = [[0.9972523, 0], [0.0052513, -0.0041175], [0.0074606, 0.0048125], [-0.0153783, -0.1968253], [0.0636871, -0.1408027], [0.3660976, -0.2937382]],
+ gs48 = [[0.98879, 0], [0, 0], [-0.050909, 0], [0, 0], [0.075528, 0]],
+ gs50 = [[0.9842990, 0], [0.0211642, 0.0037608], [-0.1036018, -0.0575102], [-0.0329095, -0.0320119], [0.0499471, 0.1223335], [0.0260460, 0.0899805], [0.0007388, -0.1435792], [0.0075848, -0.1334108], [-0.0216473, 0.0776645], [-0.0225161, 0.0853673]],
+ miller = [[0.9245, 0], [0, 0], [0.01943, 0]],
+ lee = [[0.721316, 0], [0, 0], [-0.00881625, -0.00617325]];
+
+function modifiedStereographicAlaska() {
+ return modifiedStereographic(alaska, [152, -64])
+ .scale(1400)
+ .center([-160.908, 62.4864])
+ .clipAngle(30)
+ .angle(7.8);
+}
+
+function modifiedStereographicGs48() {
+ return modifiedStereographic(gs48, [95, -38])
+ .scale(1000)
+ .clipAngle(55)
+ .center([-96.5563, 38.8675]);
+}
+
+function modifiedStereographicGs50() {
+ return modifiedStereographic(gs50, [120, -45])
+ .scale(359.513)
+ .clipAngle(55)
+ .center([-117.474, 53.0628]);
+}
+
+function modifiedStereographicMiller() {
+ return modifiedStereographic(miller, [-20, -18])
+ .scale(209.091)
+ .center([20, 16.7214])
+ .clipAngle(82);
+}
+
+function modifiedStereographicLee() {
+ return modifiedStereographic(lee, [165, 10])
+ .scale(250)
+ .clipAngle(130)
+ .center([-165, -10]);
+}
+
+function modifiedStereographic(coefficients, rotate) {
+ var p = d3Geo.geoProjection(modifiedStereographicRaw(coefficients)).rotate(rotate).clipAngle(90),
+ r = d3Geo.geoRotation(rotate),
+ center = p.center;
+
+ delete p.rotate;
+
+ p.center = function(_) {
+ return arguments.length ? center(r(_)) : r.invert(center());
+ };
+
+ return p;
+}
+
+var sqrt6 = sqrt(6),
+ sqrt7 = sqrt(7);
+
+function mtFlatPolarParabolicRaw(lambda, phi) {
+ var theta = asin(7 * sin(phi) / (3 * sqrt6));
+ return [
+ sqrt6 * lambda * (2 * cos(2 * theta / 3) - 1) / sqrt7,
+ 9 * sin(theta / 3) / sqrt7
+ ];
+}
+
+mtFlatPolarParabolicRaw.invert = function(x, y) {
+ var theta = 3 * asin(y * sqrt7 / 9);
+ return [
+ x * sqrt7 / (sqrt6 * (2 * cos(2 * theta / 3) - 1)),
+ asin(sin(theta) * 3 * sqrt6 / 7)
+ ];
+};
+
+function mtFlatPolarParabolic() {
+ return d3Geo.geoProjection(mtFlatPolarParabolicRaw)
+ .scale(164.859);
+}
+
+function mtFlatPolarQuarticRaw(lambda, phi) {
+ var k = (1 + sqrt1_2) * sin(phi),
+ theta = phi;
+ for (var i = 0, delta; i < 25; i++) {
+ theta -= delta = (sin(theta / 2) + sin(theta) - k) / (0.5 * cos(theta / 2) + cos(theta));
+ if (abs(delta) < epsilon$1) break;
+ }
+ return [
+ lambda * (1 + 2 * cos(theta) / cos(theta / 2)) / (3 * sqrt2),
+ 2 * sqrt(3) * sin(theta / 2) / sqrt(2 + sqrt2)
+ ];
+}
+
+mtFlatPolarQuarticRaw.invert = function(x, y) {
+ var sinTheta_2 = y * sqrt(2 + sqrt2) / (2 * sqrt(3)),
+ theta = 2 * asin(sinTheta_2);
+ return [
+ 3 * sqrt2 * x / (1 + 2 * cos(theta) / cos(theta / 2)),
+ asin((sinTheta_2 + sin(theta)) / (1 + sqrt1_2))
+ ];
+};
+
+function mtFlatPolarQuartic() {
+ return d3Geo.geoProjection(mtFlatPolarQuarticRaw)
+ .scale(188.209);
+}
+
+function mtFlatPolarSinusoidalRaw(lambda, phi) {
+ var A = sqrt(6 / (4 + pi)),
+ k = (1 + pi / 4) * sin(phi),
+ theta = phi / 2;
+ for (var i = 0, delta; i < 25; i++) {
+ theta -= delta = (theta / 2 + sin(theta) - k) / (0.5 + cos(theta));
+ if (abs(delta) < epsilon$1) break;
+ }
+ return [
+ A * (0.5 + cos(theta)) * lambda / 1.5,
+ A * theta
+ ];
+}
+
+mtFlatPolarSinusoidalRaw.invert = function(x, y) {
+ var A = sqrt(6 / (4 + pi)),
+ theta = y / A;
+ if (abs(abs(theta) - halfPi) < epsilon$1) theta = theta < 0 ? -halfPi : halfPi;
+ return [
+ 1.5 * x / (A * (0.5 + cos(theta))),
+ asin((theta / 2 + sin(theta)) / (1 + pi / 4))
+ ];
+};
+
+function mtFlatPolarSinusoidal() {
+ return d3Geo.geoProjection(mtFlatPolarSinusoidalRaw)
+ .scale(166.518);
+}
+
+function naturalEarth2Raw(lambda, phi) {
+ var phi2 = phi * phi, phi4 = phi2 * phi2, phi6 = phi2 * phi4;
+ return [
+ lambda * (0.84719 - 0.13063 * phi2 + phi6 * phi6 * (-0.04515 + 0.05494 * phi2 - 0.02326 * phi4 + 0.00331 * phi6)),
+ phi * (1.01183 + phi4 * phi4 * (-0.02625 + 0.01926 * phi2 - 0.00396 * phi4))
+ ];
+}
+
+naturalEarth2Raw.invert = function(x, y) {
+ var phi = y, i = 25, delta, phi2, phi4, phi6;
+ do {
+ phi2 = phi * phi; phi4 = phi2 * phi2;
+ phi -= delta = ((phi * (1.01183 + phi4 * phi4 * (-0.02625 + 0.01926 * phi2 - 0.00396 * phi4))) - y) /
+ (1.01183 + phi4 * phi4 * ((9 * -0.02625) + (11 * 0.01926) * phi2 + (13 * -0.00396) * phi4));
+ } while (abs(delta) > epsilon2 && --i > 0);
+ phi2 = phi * phi; phi4 = phi2 * phi2; phi6 = phi2 * phi4;
+ return [
+ x / (0.84719 - 0.13063 * phi2 + phi6 * phi6 * (-0.04515 + 0.05494 * phi2 - 0.02326 * phi4 + 0.00331 * phi6)),
+ phi
+ ];
+};
+
+function naturalEarth2() {
+ return d3Geo.geoProjection(naturalEarth2Raw)
+ .scale(175.295);
+}
+
+function nellHammerRaw(lambda, phi) {
+ return [
+ lambda * (1 + cos(phi)) / 2,
+ 2 * (phi - tan(phi / 2))
+ ];
+}
+
+nellHammerRaw.invert = function(x, y) {
+ var p = y / 2;
+ for (var i = 0, delta = Infinity; i < 10 && abs(delta) > epsilon$1; ++i) {
+ var c = cos(y / 2);
+ y -= delta = (y - tan(y / 2) - p) / (1 - 0.5 / (c * c));
+ }
+ return [
+ 2 * x / (1 + cos(y)),
+ y
+ ];
+};
+
+function nellHammer() {
+ return d3Geo.geoProjection(nellHammerRaw)
+ .scale(152.63);
+}
+
+var lobes = [[ // northern hemisphere
+ [[-180, 0], [-90, 90], [ 0, 0]],
+ [[ 0, 0], [ 90, 90], [ 180, 0]]
+], [ // southern hemisphere
+ [[-180, 0], [-90, -90], [ 0, 0]],
+ [[ 0, 0], [ 90, -90], [180, 0]]
+]];
+
+function quarticAuthalic() {
+ return interrupt(hammerRaw(Infinity), lobes)
+ .rotate([20, 0])
+ .scale(152.63);
+}
+
+// Based on Torben Jansen's implementation
+// https://beta.observablehq.com/@toja/nicolosi-globular-projection
+// https://beta.observablehq.com/@toja/nicolosi-globular-inverse
+
+function nicolosiRaw(lambda, phi) {
+ var sinPhi = sin(phi),
+ q = cos(phi),
+ s = sign(lambda);
+
+ if (lambda === 0 || abs(phi) === halfPi) return [0, phi];
+ else if (phi === 0) return [lambda, 0];
+ else if (abs(lambda) === halfPi) return [lambda * q, halfPi * sinPhi];
+
+ var b = pi / (2 * lambda) - (2 * lambda) / pi,
+ c = (2 * phi) / pi,
+ d = (1 - c * c) / (sinPhi - c);
+
+ var b2 = b * b,
+ d2 = d * d,
+ b2d2 = 1 + b2 / d2,
+ d2b2 = 1 + d2 / b2;
+
+ var M = ((b * sinPhi) / d - b / 2) / b2d2,
+ N = ((d2 * sinPhi) / b2 + d / 2) / d2b2,
+ m = M * M + (q * q) / b2d2,
+ n = N * N - ((d2 * sinPhi * sinPhi) / b2 + d * sinPhi - 1) / d2b2;
+
+ return [
+ halfPi * (M + sqrt(m) * s),
+ halfPi * (N + sqrt(n < 0 ? 0 : n) * sign(-phi * b) * s)
+ ];
+}
+
+nicolosiRaw.invert = function(x, y) {
+
+ x /= halfPi;
+ y /= halfPi;
+
+ var x2 = x * x,
+ y2 = y * y,
+ x2y2 = x2 + y2,
+ pi2 = pi * pi;
+
+ return [
+ x ? (x2y2 -1 + sqrt((1 - x2y2) * (1 - x2y2) + 4 * x2)) / (2 * x) * halfPi : 0,
+ solve(function(phi) {
+ return (
+ x2y2 * (pi * sin(phi) - 2 * phi) * pi +
+ 4 * phi * phi * (y - sin(phi)) +
+ 2 * pi * phi -
+ pi2 * y
+ );
+ }, 0)
+ ];
+};
+
+function nicolosi() {
+ return d3Geo.geoProjection(nicolosiRaw)
+ .scale(127.267);
+}
+
+// Based on Java implementation by Bojan Savric.
+// https://github.com/OSUCartography/JMapProjLib/blob/master/src/com/jhlabs/map/proj/PattersonProjection.java
+
+var pattersonK1 = 1.0148,
+ pattersonK2 = 0.23185,
+ pattersonK3 = -0.14499,
+ pattersonK4 = 0.02406,
+ pattersonC1 = pattersonK1,
+ pattersonC2 = 5 * pattersonK2,
+ pattersonC3 = 7 * pattersonK3,
+ pattersonC4 = 9 * pattersonK4,
+ pattersonYmax = 1.790857183;
+
+function pattersonRaw(lambda, phi) {
+ var phi2 = phi * phi;
+ return [
+ lambda,
+ phi * (pattersonK1 + phi2 * phi2 * (pattersonK2 + phi2 * (pattersonK3 + pattersonK4 * phi2)))
+ ];
+}
+
+pattersonRaw.invert = function(x, y) {
+ if (y > pattersonYmax) y = pattersonYmax;
+ else if (y < -pattersonYmax) y = -pattersonYmax;
+ var yc = y, delta;
+
+ do { // Newton-Raphson
+ var y2 = yc * yc;
+ yc -= delta = ((yc * (pattersonK1 + y2 * y2 * (pattersonK2 + y2 * (pattersonK3 + pattersonK4 * y2)))) - y) / (pattersonC1 + y2 * y2 * (pattersonC2 + y2 * (pattersonC3 + pattersonC4 * y2)));
+ } while (abs(delta) > epsilon$1);
+
+ return [x, yc];
+};
+
+function patterson() {
+ return d3Geo.geoProjection(pattersonRaw)
+ .scale(139.319);
+}
+
+function polyconicRaw(lambda, phi) {
+ if (abs(phi) < epsilon$1) return [lambda, 0];
+ var tanPhi = tan(phi),
+ k = lambda * sin(phi);
+ return [
+ sin(k) / tanPhi,
+ phi + (1 - cos(k)) / tanPhi
+ ];
+}
+
+polyconicRaw.invert = function(x, y) {
+ if (abs(y) < epsilon$1) return [x, 0];
+ var k = x * x + y * y,
+ phi = y * 0.5,
+ i = 10, delta;
+ do {
+ var tanPhi = tan(phi),
+ secPhi = 1 / cos(phi),
+ j = k - 2 * y * phi + phi * phi;
+ phi -= delta = (tanPhi * j + 2 * (phi - y)) / (2 + j * secPhi * secPhi + 2 * (phi - y) * tanPhi);
+ } while (abs(delta) > epsilon$1 && --i > 0);
+ tanPhi = tan(phi);
+ return [
+ (abs(y) < abs(phi + 1 / tanPhi) ? asin(x * tanPhi) : sign(y) * sign(x) * (acos(abs(x * tanPhi)) + halfPi)) / sin(phi),
+ phi
+ ];
+};
+
+function polyconic() {
+ return d3Geo.geoProjection(polyconicRaw)
+ .scale(103.74);
+}
+
+// Note: 6-element arrays are used to denote the 3x3 affine transform matrix:
+// [a, b, c,
+// d, e, f,
+// 0, 0, 1] - this redundant row is left out.
+
+// Transform matrix for [a0, a1] -> [b0, b1].
+function matrix(a, b) {
+ var u = subtract(a[1], a[0]),
+ v = subtract(b[1], b[0]),
+ phi = angle(u, v),
+ s = length(u) / length(v);
+
+ return multiply([
+ 1, 0, a[0][0],
+ 0, 1, a[0][1]
+ ], multiply([
+ s, 0, 0,
+ 0, s, 0
+ ], multiply([
+ cos(phi), sin(phi), 0,
+ -sin(phi), cos(phi), 0
+ ], [
+ 1, 0, -b[0][0],
+ 0, 1, -b[0][1]
+ ])));
+}
+
+// Inverts a transform matrix.
+function inverse(m) {
+ var k = 1 / (m[0] * m[4] - m[1] * m[3]);
+ return [
+ k * m[4], -k * m[1], k * (m[1] * m[5] - m[2] * m[4]),
+ -k * m[3], k * m[0], k * (m[2] * m[3] - m[0] * m[5])
+ ];
+}
+
+// Multiplies two 3x2 matrices.
+function multiply(a, b) {
+ return [
+ a[0] * b[0] + a[1] * b[3],
+ a[0] * b[1] + a[1] * b[4],
+ a[0] * b[2] + a[1] * b[5] + a[2],
+ a[3] * b[0] + a[4] * b[3],
+ a[3] * b[1] + a[4] * b[4],
+ a[3] * b[2] + a[4] * b[5] + a[5]
+ ];
+}
+
+// Subtracts 2D vectors.
+function subtract(a, b) {
+ return [a[0] - b[0], a[1] - b[1]];
+}
+
+// Magnitude of a 2D vector.
+function length(v) {
+ return sqrt(v[0] * v[0] + v[1] * v[1]);
+}
+
+// Angle between two 2D vectors.
+function angle(a, b) {
+ return atan2(a[0] * b[1] - a[1] * b[0], a[0] * b[0] + a[1] * b[1]);
+}
+
+// Creates a polyhedral projection.
+// * root: a spanning tree of polygon faces. Nodes are automatically
+// augmented with a transform matrix.
+// * face: a function that returns the appropriate node for a given {lambda, phi}
+// point (radians).
+function polyhedral(root, face) {
+
+ recurse(root, {transform: null});
+
+ function recurse(node, parent) {
+ node.edges = faceEdges(node.face);
+ // Find shared edge.
+ if (parent.face) {
+ var shared = node.shared = sharedEdge(node.face, parent.face),
+ m = matrix(shared.map(parent.project), shared.map(node.project));
+ node.transform = parent.transform ? multiply(parent.transform, m) : m;
+ // Replace shared edge in parent edges array.
+ var edges = parent.edges;
+ for (var i = 0, n = edges.length; i < n; ++i) {
+ if (pointEqual(shared[0], edges[i][1]) && pointEqual(shared[1], edges[i][0])) edges[i] = node;
+ if (pointEqual(shared[0], edges[i][0]) && pointEqual(shared[1], edges[i][1])) edges[i] = node;
+ }
+ edges = node.edges;
+ for (i = 0, n = edges.length; i < n; ++i) {
+ if (pointEqual(shared[0], edges[i][0]) && pointEqual(shared[1], edges[i][1])) edges[i] = parent;
+ if (pointEqual(shared[0], edges[i][1]) && pointEqual(shared[1], edges[i][0])) edges[i] = parent;
+ }
+ } else {
+ node.transform = parent.transform;
+ }
+ if (node.children) {
+ node.children.forEach(function(child) {
+ recurse(child, node);
+ });
+ }
+ return node;
+ }
+
+ function forward(lambda, phi) {
+ var node = face(lambda, phi),
+ point = node.project([lambda * degrees, phi * degrees]),
+ t;
+ if (t = node.transform) {
+ return [
+ t[0] * point[0] + t[1] * point[1] + t[2],
+ -(t[3] * point[0] + t[4] * point[1] + t[5])
+ ];
+ }
+ point[1] = -point[1];
+ return point;
+ }
+
+ // Naive inverse! A faster solution would use bounding boxes, or even a
+ // polygonal quadtree.
+ if (hasInverse(root)) forward.invert = function(x, y) {
+ var coordinates = faceInvert(root, [x, -y]);
+ return coordinates && (coordinates[0] *= radians, coordinates[1] *= radians, coordinates);
+ };
+
+ function faceInvert(node, coordinates) {
+ var invert = node.project.invert,
+ t = node.transform,
+ point = coordinates;
+ if (t) {
+ t = inverse(t);
+ point = [
+ t[0] * point[0] + t[1] * point[1] + t[2],
+ (t[3] * point[0] + t[4] * point[1] + t[5])
+ ];
+ }
+ if (invert && node === faceDegrees(p = invert(point))) return p;
+ var p,
+ children = node.children;
+ for (var i = 0, n = children && children.length; i < n; ++i) {
+ if (p = faceInvert(children[i], coordinates)) return p;
+ }
+ }
+
+ function faceDegrees(coordinates) {
+ return face(coordinates[0] * radians, coordinates[1] * radians);
+ }
+
+ var proj = d3Geo.geoProjection(forward),
+ stream_ = proj.stream;
+
+ proj.stream = function(stream) {
+ var rotate = proj.rotate(),
+ rotateStream = stream_(stream),
+ sphereStream = (proj.rotate([0, 0]), stream_(stream));
+ proj.rotate(rotate);
+ rotateStream.sphere = function() {
+ sphereStream.polygonStart();
+ sphereStream.lineStart();
+ outline(sphereStream, root);
+ sphereStream.lineEnd();
+ sphereStream.polygonEnd();
+ };
+ return rotateStream;
+ };
+
+ return proj.angle(-30);
+}
+
+function outline(stream, node, parent) {
+ var point,
+ edges = node.edges,
+ n = edges.length,
+ edge,
+ multiPoint = {type: "MultiPoint", coordinates: node.face},
+ notPoles = node.face.filter(function(d) { return abs(d[1]) !== 90; }),
+ b = d3Geo.geoBounds({type: "MultiPoint", coordinates: notPoles}),
+ inside = false,
+ j = -1,
+ dx = b[1][0] - b[0][0];
+ // TODO
+ var c = dx === 180 || dx === 360
+ ? [(b[0][0] + b[1][0]) / 2, (b[0][1] + b[1][1]) / 2]
+ : d3Geo.geoCentroid(multiPoint);
+ // First find the shared edge…
+ if (parent) while (++j < n) {
+ if (edges[j] === parent) break;
+ }
+ ++j;
+ for (var i = 0; i < n; ++i) {
+ edge = edges[(i + j) % n];
+ if (Array.isArray(edge)) {
+ if (!inside) {
+ stream.point((point = d3Geo.geoInterpolate(edge[0], c)(epsilon$1))[0], point[1]);
+ inside = true;
+ }
+ stream.point((point = d3Geo.geoInterpolate(edge[1], c)(epsilon$1))[0], point[1]);
+ } else {
+ inside = false;
+ if (edge !== parent) outline(stream, edge, node);
+ }
+ }
+}
+
+// Tests equality of two spherical points.
+function pointEqual(a, b) {
+ return a && b && a[0] === b[0] && a[1] === b[1];
+}
+
+// Finds a shared edge given two clockwise polygons.
+function sharedEdge(a, b) {
+ var x, y, n = a.length, found = null;
+ for (var i = 0; i < n; ++i) {
+ x = a[i];
+ for (var j = b.length; --j >= 0;) {
+ y = b[j];
+ if (x[0] === y[0] && x[1] === y[1]) {
+ if (found) return [found, x];
+ found = x;
+ }
+ }
+ }
+}
+
+// Converts an array of n face vertices to an array of n + 1 edges.
+function faceEdges(face) {
+ var n = face.length,
+ edges = [];
+ for (var a = face[n - 1], i = 0; i < n; ++i) edges.push([a, a = face[i]]);
+ return edges;
+}
+
+function hasInverse(node) {
+ return node.project.invert || node.children && node.children.some(hasInverse);
+}
+
+// TODO generate on-the-fly to avoid external modification.
+var octahedron = [
+ [0, 90],
+ [-90, 0], [0, 0], [90, 0], [180, 0],
+ [0, -90]
+];
+
+var octahedron$1 = [
+ [0, 2, 1],
+ [0, 3, 2],
+ [5, 1, 2],
+ [5, 2, 3],
+ [0, 1, 4],
+ [0, 4, 3],
+ [5, 4, 1],
+ [5, 3, 4]
+].map(function(face) {
+ return face.map(function(i) {
+ return octahedron[i];
+ });
+});
+
+function butterfly(faceProjection) {
+
+ faceProjection = faceProjection || function(face) {
+ var c = d3Geo.geoCentroid({type: "MultiPoint", coordinates: face});
+ return d3Geo.geoGnomonic().scale(1).translate([0, 0]).rotate([-c[0], -c[1]]);
+ };
+
+ var faces = octahedron$1.map(function(face) {
+ return {face: face, project: faceProjection(face)};
+ });
+
+ [-1, 0, 0, 1, 0, 1, 4, 5].forEach(function(d, i) {
+ var node = faces[d];
+ node && (node.children || (node.children = [])).push(faces[i]);
+ });
+
+ return polyhedral(faces[0], function(lambda, phi) {
+ return faces[lambda < -pi / 2 ? phi < 0 ? 6 : 4
+ : lambda < 0 ? phi < 0 ? 2 : 0
+ : lambda < pi / 2 ? phi < 0 ? 3 : 1
+ : phi < 0 ? 7 : 5];
+ })
+ .angle(-30)
+ .scale(101.858)
+ .center([0, 45]);
+}
+
+var kx = 2 / sqrt(3);
+
+function collignonK(a, b) {
+ var p = collignonRaw(a, b);
+ return [p[0] * kx, p[1]];
+}
+
+collignonK.invert = function(x,y) {
+ return collignonRaw.invert(x / kx, y);
+};
+
+function collignon(faceProjection) {
+
+ faceProjection = faceProjection || function(face) {
+ var c = d3Geo.geoCentroid({type: "MultiPoint", coordinates: face});
+ return d3Geo.geoProjection(collignonK).translate([0, 0]).scale(1).rotate(c[1] > 0 ? [-c[0], 0] : [180 - c[0], 180]);
+ };
+
+ var faces = octahedron$1.map(function(face) {
+ return {face: face, project: faceProjection(face)};
+ });
+
+ [-1, 0, 0, 1, 0, 1, 4, 5].forEach(function(d, i) {
+ var node = faces[d];
+ node && (node.children || (node.children = [])).push(faces[i]);
+ });
+
+ return polyhedral(faces[0], function(lambda, phi) {
+ return faces[lambda < -pi / 2 ? phi < 0 ? 6 : 4
+ : lambda < 0 ? phi < 0 ? 2 : 0
+ : lambda < pi / 2 ? phi < 0 ? 3 : 1
+ : phi < 0 ? 7 : 5];
+ })
+ .angle(-30)
+ .scale(121.906)
+ .center([0, 48.5904]);
+}
+
+function waterman(faceProjection) {
+
+ faceProjection = faceProjection || function(face) {
+ var c = face.length === 6 ? d3Geo.geoCentroid({type: "MultiPoint", coordinates: face}) : face[0];
+ return d3Geo.geoGnomonic().scale(1).translate([0, 0]).rotate([-c[0], -c[1]]);
+ };
+
+ var w5 = octahedron$1.map(function(face) {
+ var xyz = face.map(cartesian),
+ n = xyz.length,
+ a = xyz[n - 1],
+ b,
+ hexagon = [];
+ for (var i = 0; i < n; ++i) {
+ b = xyz[i];
+ hexagon.push(spherical([
+ a[0] * 0.9486832980505138 + b[0] * 0.31622776601683794,
+ a[1] * 0.9486832980505138 + b[1] * 0.31622776601683794,
+ a[2] * 0.9486832980505138 + b[2] * 0.31622776601683794
+ ]), spherical([
+ b[0] * 0.9486832980505138 + a[0] * 0.31622776601683794,
+ b[1] * 0.9486832980505138 + a[1] * 0.31622776601683794,
+ b[2] * 0.9486832980505138 + a[2] * 0.31622776601683794
+ ]));
+ a = b;
+ }
+ return hexagon;
+ });
+
+ var cornerNormals = [];
+
+ var parents = [-1, 0, 0, 1, 0, 1, 4, 5];
+
+ w5.forEach(function(hexagon, j) {
+ var face = octahedron$1[j],
+ n = face.length,
+ normals = cornerNormals[j] = [];
+ for (var i = 0; i < n; ++i) {
+ w5.push([
+ face[i],
+ hexagon[(i * 2 + 2) % (2 * n)],
+ hexagon[(i * 2 + 1) % (2 * n)]
+ ]);
+ parents.push(j);
+ normals.push(cross(
+ cartesian(hexagon[(i * 2 + 2) % (2 * n)]),
+ cartesian(hexagon[(i * 2 + 1) % (2 * n)])
+ ));
+ }
+ });
+
+ var faces = w5.map(function(face) {
+ return {
+ project: faceProjection(face),
+ face: face
+ };
+ });
+
+ parents.forEach(function(d, i) {
+ var parent = faces[d];
+ parent && (parent.children || (parent.children = [])).push(faces[i]);
+ });
+
+ function face(lambda, phi) {
+ var cosphi = cos(phi),
+ p = [cosphi * cos(lambda), cosphi * sin(lambda), sin(phi)];
+
+ var hexagon = lambda < -pi / 2 ? phi < 0 ? 6 : 4
+ : lambda < 0 ? phi < 0 ? 2 : 0
+ : lambda < pi / 2 ? phi < 0 ? 3 : 1
+ : phi < 0 ? 7 : 5;
+
+ var n = cornerNormals[hexagon];
+
+ return faces[dot(n[0], p) < 0 ? 8 + 3 * hexagon
+ : dot(n[1], p) < 0 ? 8 + 3 * hexagon + 1
+ : dot(n[2], p) < 0 ? 8 + 3 * hexagon + 2
+ : hexagon];
+ }
+
+ return polyhedral(faces[0], face)
+ .angle(-30)
+ .scale(110.625)
+ .center([0,45]);
+}
+
+function dot(a, b) {
+ for (var i = 0, n = a.length, s = 0; i < n; ++i) s += a[i] * b[i];
+ return s;
+}
+
+function cross(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]
+ ];
+}
+
+// Converts 3D Cartesian to spherical coordinates (degrees).
+function spherical(cartesian) {
+ return [
+ atan2(cartesian[1], cartesian[0]) * degrees,
+ asin(max(-1, min(1, cartesian[2]))) * degrees
+ ];
+}
+
+// Converts spherical coordinates (degrees) to 3D Cartesian.
+function cartesian(coordinates) {
+ var lambda = coordinates[0] * radians,
+ phi = coordinates[1] * radians,
+ cosphi = cos(phi);
+ return [
+ cosphi * cos(lambda),
+ cosphi * sin(lambda),
+ sin(phi)
+ ];
+}
+
+var noop = () => {};
+
+function clockwise(ring) {
+ if ((n = ring.length) < 4) return false;
+ var i = 0,
+ n,
+ area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1];
+ while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1];
+ return area <= 0;
+}
+
+function contains(ring, point) {
+ var x = point[0],
+ y = point[1],
+ contains = false;
+ for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) {
+ var pi = ring[i], xi = pi[0], yi = pi[1],
+ pj = ring[j], xj = pj[0], yj = pj[1];
+ if (((yi > y) ^ (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi)) contains = !contains;
+ }
+ return contains;
+}
+
+function index(object, projection) {
+ var stream = projection.stream, project;
+ if (!stream) throw new Error("invalid projection");
+ switch (object && object.type) {
+ case "Feature": project = projectFeature; break;
+ case "FeatureCollection": project = projectFeatureCollection; break;
+ default: project = projectGeometry; break;
+ }
+ return project(object, stream);
+}
+
+function projectFeatureCollection(o, stream) {
+ return {
+ type: "FeatureCollection",
+ features: o.features.map(function(f) {
+ return projectFeature(f, stream);
+ })
+ };
+}
+
+function projectFeature(o, stream) {
+ return {
+ type: "Feature",
+ id: o.id,
+ properties: o.properties,
+ geometry: projectGeometry(o.geometry, stream)
+ };
+}
+
+function projectGeometryCollection(o, stream) {
+ return {
+ type: "GeometryCollection",
+ geometries: o.geometries.map(function(o) {
+ return projectGeometry(o, stream);
+ })
+ };
+}
+
+function projectGeometry(o, stream) {
+ if (!o) return null;
+ if (o.type === "GeometryCollection") return projectGeometryCollection(o, stream);
+ var sink;
+ switch (o.type) {
+ case "Point": sink = sinkPoint; break;
+ case "MultiPoint": sink = sinkPoint; break;
+ case "LineString": sink = sinkLine; break;
+ case "MultiLineString": sink = sinkLine; break;
+ case "Polygon": sink = sinkPolygon; break;
+ case "MultiPolygon": sink = sinkPolygon; break;
+ case "Sphere": sink = sinkPolygon; break;
+ default: return null;
+ }
+ d3Geo.geoStream(o, stream(sink));
+ return sink.result();
+}
+
+var points = [],
+ lines = [];
+
+var sinkPoint = {
+ point: function(x, y) {
+ points.push([x, y]);
+ },
+ result: function() {
+ var result = !points.length ? null
+ : points.length < 2 ? {type: "Point", coordinates: points[0]}
+ : {type: "MultiPoint", coordinates: points};
+ points = [];
+ return result;
+ }
+};
+
+var sinkLine = {
+ lineStart: noop,
+ point: function(x, y) {
+ points.push([x, y]);
+ },
+ lineEnd: function() {
+ if (points.length) lines.push(points), points = [];
+ },
+ result: function() {
+ var result = !lines.length ? null
+ : lines.length < 2 ? {type: "LineString", coordinates: lines[0]}
+ : {type: "MultiLineString", coordinates: lines};
+ lines = [];
+ return result;
+ }
+};
+
+var sinkPolygon = {
+ polygonStart: noop,
+ lineStart: noop,
+ point: function(x, y) {
+ points.push([x, y]);
+ },
+ lineEnd: function() {
+ var n = points.length;
+ if (n) {
+ do points.push(points[0].slice()); while (++n < 4);
+ lines.push(points), points = [];
+ }
+ },
+ polygonEnd: noop,
+ result: function() {
+ if (!lines.length) return null;
+ var polygons = [],
+ holes = [];
+
+ // https://github.com/d3/d3/issues/1558
+ lines.forEach(function(ring) {
+ if (clockwise(ring)) polygons.push([ring]);
+ else holes.push(ring);
+ });
+
+ holes.forEach(function(hole) {
+ var point = hole[0];
+ polygons.some(function(polygon) {
+ if (contains(polygon[0], point)) {
+ polygon.push(hole);
+ return true;
+ }
+ }) || polygons.push([hole]);
+ });
+
+ lines = [];
+
+ return !polygons.length ? null
+ : polygons.length > 1 ? {type: "MultiPolygon", coordinates: polygons}
+ : {type: "Polygon", coordinates: polygons[0]};
+ }
+};
+
+function quincuncial(project) {
+ var dx = project(halfPi, 0)[0] - project(-halfPi, 0)[0];
+
+ function projectQuincuncial(lambda, phi) {
+ var t = abs(lambda) < halfPi,
+ p = project(t ? lambda : lambda > 0 ? lambda - pi : lambda + pi, phi),
+ x = (p[0] - p[1]) * sqrt1_2,
+ y = (p[0] + p[1]) * sqrt1_2;
+ if (t) return [x, y];
+ var d = dx * sqrt1_2,
+ s = x > 0 ^ y > 0 ? -1 : 1;
+ return [s * x - sign(y) * d, s * y - sign(x) * d];
+ }
+
+ if (project.invert) projectQuincuncial.invert = function(x0, y0) {
+ var x = (x0 + y0) * sqrt1_2,
+ y = (y0 - x0) * sqrt1_2,
+ t = abs(x) < 0.5 * dx && abs(y) < 0.5 * dx;
+
+ if (!t) {
+ var d = dx * sqrt1_2,
+ s = x > 0 ^ y > 0 ? -1 : 1,
+ x1 = -s * x0 + (y > 0 ? 1 : -1) * d,
+ y1 = -s * y0 + (x > 0 ? 1 : -1) * d;
+ x = (-x1 - y1) * sqrt1_2;
+ y = (x1 - y1) * sqrt1_2;
+ }
+
+ var p = project.invert(x, y);
+ if (!t) p[0] += x > 0 ? pi : -pi;
+ return p;
+ };
+
+ return d3Geo.geoProjection(projectQuincuncial)
+ .rotate([-90, -90, 45])
+ .clipAngle(180 - 1e-3);
+}
+
+function gringorten() {
+ return quincuncial(gringortenRaw)
+ .scale(176.423);
+}
+
+function peirce() {
+ return quincuncial(guyouRaw)
+ .scale(111.48);
+}
+
+function quantize$1(input, digits) {
+ if (!(0 <= (digits = +digits) && digits <= 20)) throw new Error("invalid digits");
+
+ function quantizePoint(input) {
+ var n = input.length, i = 2, output = new Array(n);
+ output[0] = +input[0].toFixed(digits);
+ output[1] = +input[1].toFixed(digits);
+ while (i < n) output[i] = input[i], ++i;
+ return output;
+ }
+
+ function quantizePoints(input) {
+ return input.map(quantizePoint);
+ }
+
+ function quantizePointsNoDuplicates(input) {
+ var point0 = quantizePoint(input[0]);
+ var output = [point0];
+ for (var i = 1; i < input.length; i++) {
+ var point = quantizePoint(input[i]);
+ if (point.length > 2 || point[0] != point0[0] || point[1] != point0[1]) {
+ output.push(point);
+ point0 = point;
+ }
+ }
+ if (output.length === 1 && input.length > 1) {
+ output.push(quantizePoint(input[input.length - 1]));
+ }
+ return output;
+ }
+
+ function quantizePolygon(input) {
+ return input.map(quantizePointsNoDuplicates);
+ }
+
+ function quantizeGeometry(input) {
+ if (input == null) return input;
+ var output;
+ switch (input.type) {
+ case "GeometryCollection": output = {type: "GeometryCollection", geometries: input.geometries.map(quantizeGeometry)}; break;
+ case "Point": output = {type: "Point", coordinates: quantizePoint(input.coordinates)}; break;
+ case "MultiPoint": output = {type: input.type, coordinates: quantizePoints(input.coordinates)}; break;
+ case "LineString": output = {type: input.type, coordinates: quantizePointsNoDuplicates(input.coordinates)}; break;
+ case "MultiLineString": case "Polygon": output = {type: input.type, coordinates: quantizePolygon(input.coordinates)}; break;
+ case "MultiPolygon": output = {type: "MultiPolygon", coordinates: input.coordinates.map(quantizePolygon)}; break;
+ default: return input;
+ }
+ if (input.bbox != null) output.bbox = input.bbox;
+ return output;
+ }
+
+ function quantizeFeature(input) {
+ var output = {type: "Feature", properties: input.properties, geometry: quantizeGeometry(input.geometry)};
+ if (input.id != null) output.id = input.id;
+ if (input.bbox != null) output.bbox = input.bbox;
+ return output;
+ }
+
+ if (input != null) switch (input.type) {
+ case "Feature": return quantizeFeature(input);
+ case "FeatureCollection": {
+ var output = {type: "FeatureCollection", features: input.features.map(quantizeFeature)};
+ if (input.bbox != null) output.bbox = input.bbox;
+ return output;
+ }
+ default: return quantizeGeometry(input);
+ }
+
+ return input;
+}
+
+function rectangularPolyconicRaw(phi0) {
+ var sinPhi0 = sin(phi0);
+
+ function forward(lambda, phi) {
+ var A = sinPhi0 ? tan(lambda * sinPhi0 / 2) / sinPhi0 : lambda / 2;
+ if (!phi) return [2 * A, -phi0];
+ var E = 2 * atan(A * sin(phi)),
+ cotPhi = 1 / tan(phi);
+ return [
+ sin(E) * cotPhi,
+ phi + (1 - cos(E)) * cotPhi - phi0
+ ];
+ }
+
+ // TODO return null for points outside outline.
+ forward.invert = function(x, y) {
+ if (abs(y += phi0) < epsilon$1) return [sinPhi0 ? 2 * atan(sinPhi0 * x / 2) / sinPhi0 : x, 0];
+ var k = x * x + y * y,
+ phi = 0,
+ i = 10, delta;
+ do {
+ var tanPhi = tan(phi),
+ secPhi = 1 / cos(phi),
+ j = k - 2 * y * phi + phi * phi;
+ phi -= delta = (tanPhi * j + 2 * (phi - y)) / (2 + j * secPhi * secPhi + 2 * (phi - y) * tanPhi);
+ } while (abs(delta) > epsilon$1 && --i > 0);
+ var E = x * (tanPhi = tan(phi)),
+ A = tan(abs(y) < abs(phi + 1 / tanPhi) ? asin(E) * 0.5 : acos(E) * 0.5 + pi / 4) / sin(phi);
+ return [
+ sinPhi0 ? 2 * atan(sinPhi0 * A) / sinPhi0 : 2 * A,
+ phi
+ ];
+ };
+
+ return forward;
+}
+
+function rectangularPolyconic() {
+ return parallel1(rectangularPolyconicRaw)
+ .scale(131.215);
+}
+
+var K = [
+ [0.9986, -0.062],
+ [1.0000, 0.0000],
+ [0.9986, 0.0620],
+ [0.9954, 0.1240],
+ [0.9900, 0.1860],
+ [0.9822, 0.2480],
+ [0.9730, 0.3100],
+ [0.9600, 0.3720],
+ [0.9427, 0.4340],
+ [0.9216, 0.4958],
+ [0.8962, 0.5571],
+ [0.8679, 0.6176],
+ [0.8350, 0.6769],
+ [0.7986, 0.7346],
+ [0.7597, 0.7903],
+ [0.7186, 0.8435],
+ [0.6732, 0.8936],
+ [0.6213, 0.9394],
+ [0.5722, 0.9761],
+ [0.5322, 1.0000]
+];
+
+K.forEach(function(d) {
+ d[1] *= 1.593415793900743;
+});
+
+function robinsonRaw(lambda, phi) {
+ var i = min(18, abs(phi) * 36 / pi),
+ i0 = floor(i),
+ di = i - i0,
+ ax = (k = K[i0])[0],
+ ay = k[1],
+ bx = (k = K[++i0])[0],
+ by = k[1],
+ cx = (k = K[min(19, ++i0)])[0],
+ cy = k[1],
+ k;
+ return [
+ lambda * (bx + di * (cx - ax) / 2 + di * di * (cx - 2 * bx + ax) / 2),
+ sign(phi) * (by + di * (cy - ay) / 2 + di * di * (cy - 2 * by + ay) / 2)
+ ];
+}
+
+robinsonRaw.invert = function(x, y) {
+ var phi = y * 90,
+ i = min(18, abs(phi / 5)),
+ i0 = max(0, floor(i));
+ do {
+ var ay = K[i0][1],
+ by = K[i0 + 1][1],
+ cy = K[min(19, i0 + 2)][1],
+ u = cy - ay,
+ v = cy - 2 * by + ay,
+ t = 2 * (abs(y) - by) / u,
+ c = v / u,
+ di = t * (1 - c * t * (1 - 2 * c * t));
+ if (di >= 0 || i0 === 1) {
+ phi = (y >= 0 ? 5 : -5) * (di + i);
+ var j = 50, delta;
+ do {
+ i = min(18, abs(phi) / 5);
+ i0 = floor(i);
+ di = i - i0;
+ ay = K[i0][1];
+ by = K[i0 + 1][1];
+ cy = K[min(19, i0 + 2)][1];
+ phi -= (delta = sign(y) * (by + di * (cy - ay) / 2 + di * di * (cy - 2 * by + ay) / 2) - y) * degrees;
+ } while (abs(delta) > epsilon2 && --j > 0);
+ break;
+ }
+ } while (--i0 >= 0);
+ var ax = K[i0][0],
+ bx = K[i0 + 1][0],
+ cx = K[min(19, i0 + 2)][0];
+ return [
+ x / (bx + di * (cx - ax) / 2 + di * di * (cx - 2 * bx + ax) / 2),
+ phi * radians
+ ];
+};
+
+function robinson() {
+ return d3Geo.geoProjection(robinsonRaw)
+ .scale(152.63);
+}
+
+function satelliteVerticalRaw(P) {
+ function forward(lambda, phi) {
+ var cosPhi = cos(phi),
+ k = (P - 1) / (P - cosPhi * cos(lambda));
+ return [
+ k * cosPhi * sin(lambda),
+ k * sin(phi)
+ ];
+ }
+
+ forward.invert = function(x, y) {
+ var rho2 = x * x + y * y,
+ rho = sqrt(rho2),
+ sinc = (P - sqrt(1 - rho2 * (P + 1) / (P - 1))) / ((P - 1) / rho + rho / (P - 1));
+ return [
+ atan2(x * sinc, rho * sqrt(1 - sinc * sinc)),
+ rho ? asin(y * sinc / rho) : 0
+ ];
+ };
+
+ return forward;
+}
+
+function satelliteRaw(P, omega) {
+ var vertical = satelliteVerticalRaw(P);
+ if (!omega) return vertical;
+ var cosOmega = cos(omega),
+ sinOmega = sin(omega);
+
+ function forward(lambda, phi) {
+ var coordinates = vertical(lambda, phi),
+ y = coordinates[1],
+ A = y * sinOmega / (P - 1) + cosOmega;
+ return [
+ coordinates[0] * cosOmega / A,
+ y / A
+ ];
+ }
+
+ forward.invert = function(x, y) {
+ var k = (P - 1) / (P - 1 - y * sinOmega);
+ return vertical.invert(k * x, k * y * cosOmega);
+ };
+
+ return forward;
+}
+
+function satellite() {
+ var distance = 2,
+ omega = 0,
+ m = d3Geo.geoProjectionMutator(satelliteRaw),
+ p = m(distance, omega);
+
+ // As a multiple of radius.
+ p.distance = function(_) {
+ if (!arguments.length) return distance;
+ return m(distance = +_, omega);
+ };
+
+ p.tilt = function(_) {
+ if (!arguments.length) return omega * degrees;
+ return m(distance, omega = _ * radians);
+ };
+
+ return p
+ .scale(432.147)
+ .clipAngle(acos(1 / distance) * degrees - 1e-6);
+}
+
+var epsilon = 1e-4,
+ epsilonInverse = 1e4,
+ x0 = -180, x0e = x0 + epsilon,
+ x1 = 180, x1e = x1 - epsilon,
+ y0 = -90, y0e = y0 + epsilon,
+ y1 = 90, y1e = y1 - epsilon;
+
+function nonempty(coordinates) {
+ return coordinates.length > 0;
+}
+
+function quantize(x) {
+ return Math.floor(x * epsilonInverse) / epsilonInverse;
+}
+
+function normalizePoint(y) {
+ return y === y0 || y === y1 ? [0, y] : [x0, quantize(y)]; // pole or antimeridian?
+}
+
+function clampPoint(p) {
+ var x = p[0], y = p[1], clamped = false;
+ if (x <= x0e) x = x0, clamped = true;
+ else if (x >= x1e) x = x1, clamped = true;
+ if (y <= y0e) y = y0, clamped = true;
+ else if (y >= y1e) y = y1, clamped = true;
+ return clamped ? [x, y] : p;
+}
+
+function clampPoints(points) {
+ return points.map(clampPoint);
+}
+
+// For each ring, detect where it crosses the antimeridian or pole.
+function extractFragments(rings, polygon, fragments) {
+ for (var j = 0, m = rings.length; j < m; ++j) {
+ var ring = rings[j].slice();
+
+ // By default, assume that this ring doesn’t need any stitching.
+ fragments.push({index: -1, polygon: polygon, ring: ring});
+
+ for (var i = 0, n = ring.length; i < n; ++i) {
+ var point = ring[i],
+ x = point[0],
+ y = point[1];
+
+ // If this is an antimeridian or polar point…
+ if (x <= x0e || x >= x1e || y <= y0e || y >= y1e) {
+ ring[i] = clampPoint(point);
+
+ // Advance through any antimeridian or polar points…
+ for (var k = i + 1; k < n; ++k) {
+ var pointk = ring[k],
+ xk = pointk[0],
+ yk = pointk[1];
+ if (xk > x0e && xk < x1e && yk > y0e && yk < y1e) break;
+ }
+
+ // If this was just a single antimeridian or polar point,
+ // we don’t need to cut this ring into a fragment;
+ // we can just leave it as-is.
+ if (k === i + 1) continue;
+
+ // Otherwise, if this is not the first point in the ring,
+ // cut the current fragment so that it ends at the current point.
+ // The current point is also normalized for later joining.
+ if (i) {
+ var fragmentBefore = {index: -1, polygon: polygon, ring: ring.slice(0, i + 1)};
+ fragmentBefore.ring[fragmentBefore.ring.length - 1] = normalizePoint(y);
+ fragments[fragments.length - 1] = fragmentBefore;
+ }
+
+ // If the ring started with an antimeridian fragment,
+ // we can ignore that fragment entirely.
+ else fragments.pop();
+
+ // If the remainder of the ring is an antimeridian fragment,
+ // move on to the next ring.
+ if (k >= n) break;
+
+ // Otherwise, add the remaining ring fragment and continue.
+ fragments.push({index: -1, polygon: polygon, ring: ring = ring.slice(k - 1)});
+ ring[0] = normalizePoint(ring[0][1]);
+ i = -1;
+ n = ring.length;
+ }
+ }
+ }
+}
+
+// Now stitch the fragments back together into rings.
+function stitchFragments(fragments) {
+ var i, n = fragments.length;
+
+ // To connect the fragments start-to-end, create a simple index by end.
+ var fragmentByStart = {},
+ fragmentByEnd = {},
+ fragment,
+ start,
+ startFragment,
+ end,
+ endFragment;
+
+ // For each fragment…
+ for (i = 0; i < n; ++i) {
+ fragment = fragments[i];
+ start = fragment.ring[0];
+ end = fragment.ring[fragment.ring.length - 1];
+
+ // If this fragment is closed, add it as a standalone ring.
+ if (start[0] === end[0] && start[1] === end[1]) {
+ fragment.polygon.push(fragment.ring);
+ fragments[i] = null;
+ continue;
+ }
+
+ fragment.index = i;
+ fragmentByStart[start] = fragmentByEnd[end] = fragment;
+ }
+
+ // For each open fragment…
+ for (i = 0; i < n; ++i) {
+ fragment = fragments[i];
+ if (fragment) {
+ start = fragment.ring[0];
+ end = fragment.ring[fragment.ring.length - 1];
+ startFragment = fragmentByEnd[start];
+ endFragment = fragmentByStart[end];
+
+ delete fragmentByStart[start];
+ delete fragmentByEnd[end];
+
+ // If this fragment is closed, add it as a standalone ring.
+ if (start[0] === end[0] && start[1] === end[1]) {
+ fragment.polygon.push(fragment.ring);
+ continue;
+ }
+
+ if (startFragment) {
+ delete fragmentByEnd[start];
+ delete fragmentByStart[startFragment.ring[0]];
+ startFragment.ring.pop(); // drop the shared coordinate
+ fragments[startFragment.index] = null;
+ fragment = {index: -1, polygon: startFragment.polygon, ring: startFragment.ring.concat(fragment.ring)};
+
+ if (startFragment === endFragment) {
+ // Connect both ends to this single fragment to create a ring.
+ fragment.polygon.push(fragment.ring);
+ } else {
+ fragment.index = n++;
+ fragments.push(fragmentByStart[fragment.ring[0]] = fragmentByEnd[fragment.ring[fragment.ring.length - 1]] = fragment);
+ }
+ } else if (endFragment) {
+ delete fragmentByStart[end];
+ delete fragmentByEnd[endFragment.ring[endFragment.ring.length - 1]];
+ fragment.ring.pop(); // drop the shared coordinate
+ fragment = {index: n++, polygon: endFragment.polygon, ring: fragment.ring.concat(endFragment.ring)};
+ fragments[endFragment.index] = null;
+ fragments.push(fragmentByStart[fragment.ring[0]] = fragmentByEnd[fragment.ring[fragment.ring.length - 1]] = fragment);
+ } else {
+ fragment.ring.push(fragment.ring[0]); // close ring
+ fragment.polygon.push(fragment.ring);
+ }
+ }
+ }
+}
+
+function stitchFeature(input) {
+ var output = {type: "Feature", geometry: stitchGeometry(input.geometry)};
+ if (input.id != null) output.id = input.id;
+ if (input.bbox != null) output.bbox = input.bbox;
+ if (input.properties != null) output.properties = input.properties;
+ return output;
+}
+
+function stitchGeometry(input) {
+ if (input == null) return input;
+ var output, fragments, i, n;
+ switch (input.type) {
+ case "GeometryCollection": output = {type: "GeometryCollection", geometries: input.geometries.map(stitchGeometry)}; break;
+ case "Point": output = {type: "Point", coordinates: clampPoint(input.coordinates)}; break;
+ case "MultiPoint": case "LineString": output = {type: input.type, coordinates: clampPoints(input.coordinates)}; break;
+ case "MultiLineString": output = {type: "MultiLineString", coordinates: input.coordinates.map(clampPoints)}; break;
+ case "Polygon": {
+ var polygon = [];
+ extractFragments(input.coordinates, polygon, fragments = []);
+ stitchFragments(fragments);
+ output = {type: "Polygon", coordinates: polygon};
+ break;
+ }
+ case "MultiPolygon": {
+ fragments = [], i = -1, n = input.coordinates.length;
+ var polygons = new Array(n);
+ while (++i < n) extractFragments(input.coordinates[i], polygons[i] = [], fragments);
+ stitchFragments(fragments);
+ output = {type: "MultiPolygon", coordinates: polygons.filter(nonempty)};
+ break;
+ }
+ default: return input;
+ }
+ if (input.bbox != null) output.bbox = input.bbox;
+ return output;
+}
+
+function stitch(input) {
+ if (input == null) return input;
+ switch (input.type) {
+ case "Feature": return stitchFeature(input);
+ case "FeatureCollection": {
+ var output = {type: "FeatureCollection", features: input.features.map(stitchFeature)};
+ if (input.bbox != null) output.bbox = input.bbox;
+ return output;
+ }
+ default: return stitchGeometry(input);
+ }
+}
+
+function timesRaw(lambda, phi) {
+ var t = tan(phi / 2),
+ s = sin(quarterPi * t);
+ return [
+ lambda * (0.74482 - 0.34588 * s * s),
+ 1.70711 * t
+ ];
+}
+
+timesRaw.invert = function(x, y) {
+ var t = y / 1.70711,
+ s = sin(quarterPi * t);
+ return [
+ x / (0.74482 - 0.34588 * s * s),
+ 2 * atan(t)
+ ];
+};
+
+function times() {
+ return d3Geo.geoProjection(timesRaw)
+ .scale(146.153);
+}
+
+// Compute the origin as the midpoint of the two reference points.
+// Rotate one of the reference points by the origin.
+// Apply the spherical law of sines to compute gamma rotation.
+function twoPoint(raw, p0, p1) {
+ var i = d3Geo.geoInterpolate(p0, p1),
+ o = i(0.5),
+ a = d3Geo.geoRotation([-o[0], -o[1]])(p0),
+ b = i.distance / 2,
+ y = -asin(sin(a[1] * radians) / sin(b)),
+ R = [-o[0], -o[1], -(a[0] > 0 ? pi - y : y) * degrees],
+ p = d3Geo.geoProjection(raw(b)).rotate(R),
+ r = d3Geo.geoRotation(R),
+ center = p.center;
+
+ delete p.rotate;
+
+ p.center = function(_) {
+ return arguments.length ? center(r(_)) : r.invert(center());
+ };
+
+ return p
+ .clipAngle(90);
+}
+
+function twoPointAzimuthalRaw(d) {
+ var cosd = cos(d);
+
+ function forward(lambda, phi) {
+ var coordinates = d3Geo.geoGnomonicRaw(lambda, phi);
+ coordinates[0] *= cosd;
+ return coordinates;
+ }
+
+ forward.invert = function(x, y) {
+ return d3Geo.geoGnomonicRaw.invert(x / cosd, y);
+ };
+
+ return forward;
+}
+
+function twoPointAzimuthalUsa() {
+ return twoPointAzimuthal([-158, 21.5], [-77, 39])
+ .clipAngle(60)
+ .scale(400);
+}
+
+function twoPointAzimuthal(p0, p1) {
+ return twoPoint(twoPointAzimuthalRaw, p0, p1);
+}
+
+function twoPointEquidistantRaw(z0) {
+ if (!(z0 *= 2)) return d3Geo.geoAzimuthalEquidistantRaw;
+ var lambdaa = -z0 / 2,
+ lambdab = -lambdaa,
+ z02 = z0 * z0,
+ tanLambda0 = tan(lambdab),
+ S = 0.5 / sin(lambdab);
+
+ function forward(lambda, phi) {
+ var za = acos(cos(phi) * cos(lambda - lambdaa)),
+ zb = acos(cos(phi) * cos(lambda - lambdab)),
+ ys = phi < 0 ? -1 : 1;
+ za *= za, zb *= zb;
+ return [
+ (za - zb) / (2 * z0),
+ ys * sqrt(4 * z02 * zb - (z02 - za + zb) * (z02 - za + zb)) / (2 * z0)
+ ];
+ }
+
+ forward.invert = function(x, y) {
+ var y2 = y * y,
+ cosza = cos(sqrt(y2 + (t = x + lambdaa) * t)),
+ coszb = cos(sqrt(y2 + (t = x + lambdab) * t)),
+ t,
+ d;
+ return [
+ atan2(d = cosza - coszb, t = (cosza + coszb) * tanLambda0),
+ (y < 0 ? -1 : 1) * acos(sqrt(t * t + d * d) * S)
+ ];
+ };
+
+ return forward;
+}
+
+function twoPointEquidistantUsa() {
+ return twoPointEquidistant([-158, 21.5], [-77, 39])
+ .clipAngle(130)
+ .scale(122.571);
+}
+
+function twoPointEquidistant(p0, p1) {
+ return twoPoint(twoPointEquidistantRaw, p0, p1);
+}
+
+function vanDerGrintenRaw(lambda, phi) {
+ if (abs(phi) < epsilon$1) return [lambda, 0];
+ var sinTheta = abs(phi / halfPi),
+ theta = asin(sinTheta);
+ if (abs(lambda) < epsilon$1 || abs(abs(phi) - halfPi) < epsilon$1) return [0, sign(phi) * pi * tan(theta / 2)];
+ var cosTheta = cos(theta),
+ A = abs(pi / lambda - lambda / pi) / 2,
+ A2 = A * A,
+ G = cosTheta / (sinTheta + cosTheta - 1),
+ P = G * (2 / sinTheta - 1),
+ P2 = P * P,
+ P2_A2 = P2 + A2,
+ G_P2 = G - P2,
+ Q = A2 + G;
+ return [
+ sign(lambda) * pi * (A * G_P2 + sqrt(A2 * G_P2 * G_P2 - P2_A2 * (G * G - P2))) / P2_A2,
+ sign(phi) * pi * (P * Q - A * sqrt((A2 + 1) * P2_A2 - Q * Q)) / P2_A2
+ ];
+}
+
+vanDerGrintenRaw.invert = function(x, y) {
+ if (abs(y) < epsilon$1) return [x, 0];
+ if (abs(x) < epsilon$1) return [0, halfPi * sin(2 * atan(y / pi))];
+ var x2 = (x /= pi) * x,
+ y2 = (y /= pi) * y,
+ x2_y2 = x2 + y2,
+ z = x2_y2 * x2_y2,
+ c1 = -abs(y) * (1 + x2_y2),
+ c2 = c1 - 2 * y2 + x2,
+ c3 = -2 * c1 + 1 + 2 * y2 + z,
+ d = y2 / c3 + (2 * c2 * c2 * c2 / (c3 * c3 * c3) - 9 * c1 * c2 / (c3 * c3)) / 27,
+ a1 = (c1 - c2 * c2 / (3 * c3)) / c3,
+ m1 = 2 * sqrt(-a1 / 3),
+ theta1 = acos(3 * d / (a1 * m1)) / 3;
+ return [
+ pi * (x2_y2 - 1 + sqrt(1 + 2 * (x2 - y2) + z)) / (2 * x),
+ sign(y) * pi * (-m1 * cos(theta1 + pi / 3) - c2 / (3 * c3))
+ ];
+};
+
+function vanDerGrinten() {
+ return d3Geo.geoProjection(vanDerGrintenRaw)
+ .scale(79.4183);
+}
+
+function vanDerGrinten2Raw(lambda, phi) {
+ if (abs(phi) < epsilon$1) return [lambda, 0];
+ var sinTheta = abs(phi / halfPi),
+ theta = asin(sinTheta);
+ if (abs(lambda) < epsilon$1 || abs(abs(phi) - halfPi) < epsilon$1) return [0, sign(phi) * pi * tan(theta / 2)];
+ var cosTheta = cos(theta),
+ A = abs(pi / lambda - lambda / pi) / 2,
+ A2 = A * A,
+ x1 = cosTheta * (sqrt(1 + A2) - A * cosTheta) / (1 + A2 * sinTheta * sinTheta);
+ return [
+ sign(lambda) * pi * x1,
+ sign(phi) * pi * sqrt(1 - x1 * (2 * A + x1))
+ ];
+}
+
+vanDerGrinten2Raw.invert = function(x, y) {
+ if (!x) return [0, halfPi * sin(2 * atan(y / pi))];
+ var x1 = abs(x / pi),
+ A = (1 - x1 * x1 - (y /= pi) * y) / (2 * x1),
+ A2 = A * A,
+ B = sqrt(A2 + 1);
+ return [
+ sign(x) * pi * (B - A),
+ sign(y) * halfPi * sin(2 * atan2(sqrt((1 - 2 * A * x1) * (A + B) - x1), sqrt(B + A + x1)))
+ ];
+};
+
+function vanDerGrinten2() {
+ return d3Geo.geoProjection(vanDerGrinten2Raw)
+ .scale(79.4183);
+}
+
+function vanDerGrinten3Raw(lambda, phi) {
+ if (abs(phi) < epsilon$1) return [lambda, 0];
+ var sinTheta = phi / halfPi,
+ theta = asin(sinTheta);
+ if (abs(lambda) < epsilon$1 || abs(abs(phi) - halfPi) < epsilon$1) return [0, pi * tan(theta / 2)];
+ var A = (pi / lambda - lambda / pi) / 2,
+ y1 = sinTheta / (1 + cos(theta));
+ return [
+ pi * (sign(lambda) * sqrt(A * A + 1 - y1 * y1) - A),
+ pi * y1
+ ];
+}
+
+vanDerGrinten3Raw.invert = function(x, y) {
+ if (!y) return [x, 0];
+ var y1 = y / pi,
+ A = (pi * pi * (1 - y1 * y1) - x * x) / (2 * pi * x);
+ return [
+ x ? pi * (sign(x) * sqrt(A * A + 1) - A) : 0,
+ halfPi * sin(2 * atan(y1))
+ ];
+};
+
+function vanDerGrinten3() {
+ return d3Geo.geoProjection(vanDerGrinten3Raw)
+ .scale(79.4183);
+}
+
+function vanDerGrinten4Raw(lambda, phi) {
+ if (!phi) return [lambda, 0];
+ var phi0 = abs(phi);
+ if (!lambda || phi0 === halfPi) return [0, phi];
+ var B = phi0 / halfPi,
+ B2 = B * B,
+ C = (8 * B - B2 * (B2 + 2) - 5) / (2 * B2 * (B - 1)),
+ C2 = C * C,
+ BC = B * C,
+ B_C2 = B2 + C2 + 2 * BC,
+ B_3C = B + 3 * C,
+ lambda0 = lambda / halfPi,
+ lambda1 = lambda0 + 1 / lambda0,
+ D = sign(abs(lambda) - halfPi) * sqrt(lambda1 * lambda1 - 4),
+ D2 = D * D,
+ F = B_C2 * (B2 + C2 * D2 - 1) + (1 - B2) * (B2 * (B_3C * B_3C + 4 * C2) + 12 * BC * C2 + 4 * C2 * C2),
+ x1 = (D * (B_C2 + C2 - 1) + 2 * sqrt(F)) / (4 * B_C2 + D2);
+ return [
+ sign(lambda) * halfPi * x1,
+ sign(phi) * halfPi * sqrt(1 + D * abs(x1) - x1 * x1)
+ ];
+}
+
+vanDerGrinten4Raw.invert = function(x, y) {
+ var delta;
+ if (!x || !y) return [x, y];
+ var sy = sign(y);
+ y = abs(y) / pi;
+ var x1 = sign(x) * x / halfPi,
+ D = (x1 * x1 - 1 + 4 * y * y) / abs(x1),
+ D2 = D * D,
+ B = y * (2 - (y > 0.5 ? min(y, abs(x)) : 0)),
+ r = x * x + y * y,
+ i = 50;
+ do {
+ var B2 = B * B,
+ C = (8 * B - B2 * (B2 + 2) - 5) / (2 * B2 * (B - 1)),
+ C_ = (3 * B - B2 * B - 10) / (2 * B2 * B),
+ C2 = C * C,
+ BC = B * C,
+ B_C = B + C,
+ B_C2 = B_C * B_C,
+ B_3C = B + 3 * C,
+ F = B_C2 * (B2 + C2 * D2 - 1) + (1 - B2) * (B2 * (B_3C * B_3C + 4 * C2) + C2 * (12 * BC + 4 * C2)),
+ F_ = -2 * B_C * (4 * BC * C2 + (1 - 4 * B2 + 3 * B2 * B2) * (1 + C_) + C2 * (-6 + 14 * B2 - D2 + (-8 + 8 * B2 - 2 * D2) * C_) + BC * (-8 + 12 * B2 + (-10 + 10 * B2 - D2) * C_)),
+ sqrtF = sqrt(F),
+ f = D * (B_C2 + C2 - 1) + 2 * sqrtF - x1 * (4 * B_C2 + D2),
+ f_ = D * (2 * C * C_ + 2 * B_C * (1 + C_)) + F_ / sqrtF - 8 * B_C * (D * (-1 + C2 + B_C2) + 2 * sqrtF) * (1 + C_) / (D2 + 4 * B_C2);
+ B -= delta = f / f_;
+ } while (delta * r * r > epsilon$1 && --i > 0);
+ return [
+ sign(x) * (sqrt(D * D + 4) + D) * pi / 4,
+ sy * halfPi * B
+ ];
+};
+
+function vanDerGrinten4() {
+ return d3Geo.geoProjection(vanDerGrinten4Raw)
+ .scale(127.16);
+}
+
+function wagnerFormula(cx, cy, m1, m2, n) {
+ function forward(lambda, phi) {
+ var s = m1 * sin(m2 * phi),
+ c0 = sqrt(1 - s * s),
+ c1 = sqrt(2 / (1 + c0 * cos(lambda *= n)));
+ return [
+ cx * c0 * c1 * sin(lambda),
+ cy * s * c1
+ ];
+ }
+
+ forward.invert = function(x, y) {
+ var t1 = x / cx,
+ t2 = y / cy,
+ p = sqrt(t1 * t1 + t2 * t2),
+ c = 2 * asin(p / 2);
+ return [
+ atan2(x * tan(c), cx * p) / n,
+ p && asin(y * sin(c) / (cy * m1 * p)) / m2
+ ];
+ };
+
+ return forward;
+}
+
+function wagnerRaw(poleline, parallels, inflation, ratio) {
+ // 60 is always used as reference parallel
+ var phi1 = pi / 3;
+
+ // sanitizing the input values
+ // poleline and parallels may approximate but never equal 0
+ poleline = max(poleline, epsilon$1);
+ parallels = max(parallels, epsilon$1);
+ // poleline must be <= 90; parallels may approximate but never equal 180
+ poleline = min(poleline, halfPi);
+ parallels = min(parallels, pi - epsilon$1);
+ // 0 <= inflation <= 99.999
+ inflation = max(inflation, 0);
+ inflation = min(inflation, 100 - epsilon$1);
+ // ratio > 0.
+ // sensible values, i.e. something that renders a map which still can be
+ // recognized as world map, are e.g. 20 <= ratio <= 1000.
+ ratio = max(ratio, epsilon$1);
+
+ // convert values from boehm notation
+ // areal inflation e.g. from 0 to 1 or 20 to 1.2:
+ var vinflation = inflation/100 + 1;
+ // axial ratio e.g. from 200 to 2:
+ var vratio = ratio / 100;
+ // the other ones are a bit more complicated...
+ var m2 = acos(vinflation * cos(phi1)) / phi1,
+ m1 = sin(poleline) / sin(m2 * halfPi),
+ n = parallels / pi,
+ k = sqrt(vratio * sin(poleline / 2) / sin(parallels / 2)),
+ cx = k / sqrt(n * m1 * m2),
+ cy = 1 / (k * sqrt(n * m1 * m2));
+
+ return wagnerFormula(cx, cy, m1, m2, n);
+}
+
+function wagner() {
+ // default values generate wagner8
+ var poleline = 65 * radians,
+ parallels = 60 * radians,
+ inflation = 20,
+ ratio = 200,
+ mutate = d3Geo.geoProjectionMutator(wagnerRaw),
+ projection = mutate(poleline, parallels, inflation, ratio);
+
+ projection.poleline = function(_) {
+ return arguments.length ? mutate(poleline = +_ * radians, parallels, inflation, ratio) : poleline * degrees;
+ };
+
+ projection.parallels = function(_) {
+ return arguments.length ? mutate(poleline, parallels = +_ * radians, inflation, ratio) : parallels * degrees;
+ };
+ projection.inflation = function(_) {
+ return arguments.length ? mutate(poleline, parallels, inflation = +_, ratio) : inflation;
+ };
+ projection.ratio = function(_) {
+ return arguments.length ? mutate(poleline, parallels, inflation, ratio = +_) : ratio;
+ };
+
+ return projection
+ .scale(163.775);
+}
+
+function wagner7() {
+ return wagner()
+ .poleline(65)
+ .parallels(60)
+ .inflation(0)
+ .ratio(200)
+ .scale(172.633);
+}
+
+var A = 4 * pi + 3 * sqrt(3),
+ B = 2 * sqrt(2 * pi * sqrt(3) / A);
+
+var wagner4Raw = mollweideBromleyRaw(B * sqrt(3) / pi, B, A / 6);
+
+function wagner4() {
+ return d3Geo.geoProjection(wagner4Raw)
+ .scale(176.84);
+}
+
+function wagner6Raw(lambda, phi) {
+ return [lambda * sqrt(1 - 3 * phi * phi / (pi * pi)), phi];
+}
+
+wagner6Raw.invert = function(x, y) {
+ return [x / sqrt(1 - 3 * y * y / (pi * pi)), y];
+};
+
+function wagner6() {
+ return d3Geo.geoProjection(wagner6Raw)
+ .scale(152.63);
+}
+
+function wiechelRaw(lambda, phi) {
+ var cosPhi = cos(phi),
+ sinPhi = cos(lambda) * cosPhi,
+ sin1_Phi = 1 - sinPhi,
+ cosLambda = cos(lambda = atan2(sin(lambda) * cosPhi, -sin(phi))),
+ sinLambda = sin(lambda);
+ cosPhi = sqrt(1 - sinPhi * sinPhi);
+ return [
+ sinLambda * cosPhi - cosLambda * sin1_Phi,
+ -cosLambda * cosPhi - sinLambda * sin1_Phi
+ ];
+}
+
+wiechelRaw.invert = function(x, y) {
+ var w = (x * x + y * y) / -2,
+ k = sqrt(-w * (2 + w)),
+ b = y * w + x * k,
+ a = x * w - y * k,
+ D = sqrt(a * a + b * b);
+ return [
+ atan2(k * b, D * (1 + w)),
+ D ? -asin(k * a / D) : 0
+ ];
+};
+
+function wiechel() {
+ return d3Geo.geoProjection(wiechelRaw)
+ .rotate([0, -90, 45])
+ .scale(124.75)
+ .clipAngle(180 - 1e-3);
+}
+
+function winkel3Raw(lambda, phi) {
+ var coordinates = aitoffRaw(lambda, phi);
+ return [
+ (coordinates[0] + lambda / halfPi) / 2,
+ (coordinates[1] + phi) / 2
+ ];
+}
+
+winkel3Raw.invert = function(x, y) {
+ var lambda = x, phi = y, i = 25;
+ do {
+ var cosphi = cos(phi),
+ sinphi = sin(phi),
+ sin_2phi = sin(2 * phi),
+ sin2phi = sinphi * sinphi,
+ cos2phi = cosphi * cosphi,
+ sinlambda = sin(lambda),
+ coslambda_2 = cos(lambda / 2),
+ sinlambda_2 = sin(lambda / 2),
+ sin2lambda_2 = sinlambda_2 * sinlambda_2,
+ C = 1 - cos2phi * coslambda_2 * coslambda_2,
+ E = C ? acos(cosphi * coslambda_2) * sqrt(F = 1 / C) : F = 0,
+ F,
+ fx = 0.5 * (2 * E * cosphi * sinlambda_2 + lambda / halfPi) - x,
+ fy = 0.5 * (E * sinphi + phi) - y,
+ dxdlambda = 0.5 * F * (cos2phi * sin2lambda_2 + E * cosphi * coslambda_2 * sin2phi) + 0.5 / halfPi,
+ dxdphi = F * (sinlambda * sin_2phi / 4 - E * sinphi * sinlambda_2),
+ dydlambda = 0.125 * F * (sin_2phi * sinlambda_2 - E * sinphi * cos2phi * sinlambda),
+ dydphi = 0.5 * F * (sin2phi * coslambda_2 + E * sin2lambda_2 * cosphi) + 0.5,
+ denominator = dxdphi * dydlambda - dydphi * dxdlambda,
+ dlambda = (fy * dxdphi - fx * dydphi) / denominator,
+ dphi = (fx * dydlambda - fy * dxdlambda) / denominator;
+ lambda -= dlambda, phi -= dphi;
+ } while ((abs(dlambda) > epsilon$1 || abs(dphi) > epsilon$1) && --i > 0);
+ return [lambda, phi];
+};
+
+function winkel3() {
+ return d3Geo.geoProjection(winkel3Raw)
+ .scale(158.837);
+}
+
+exports.geoAiry = airy;
+exports.geoAiryRaw = airyRaw;
+exports.geoAitoff = aitoff;
+exports.geoAitoffRaw = aitoffRaw;
+exports.geoArmadillo = armadillo;
+exports.geoArmadilloRaw = armadilloRaw;
+exports.geoAugust = august;
+exports.geoAugustRaw = augustRaw;
+exports.geoBaker = baker;
+exports.geoBakerRaw = bakerRaw;
+exports.geoBerghaus = berghaus;
+exports.geoBerghausRaw = berghausRaw;
+exports.geoBertin1953 = bertin;
+exports.geoBertin1953Raw = bertin1953Raw;
+exports.geoBoggs = boggs$1;
+exports.geoBoggsRaw = boggsRaw;
+exports.geoBonne = bonne;
+exports.geoBonneRaw = bonneRaw;
+exports.geoBottomley = bottomley;
+exports.geoBottomleyRaw = bottomleyRaw;
+exports.geoBromley = bromley;
+exports.geoBromleyRaw = bromleyRaw;
+exports.geoChamberlin = chamberlin;
+exports.geoChamberlinAfrica = chamberlinAfrica;
+exports.geoChamberlinRaw = chamberlinRaw;
+exports.geoCollignon = collignon$1;
+exports.geoCollignonRaw = collignonRaw;
+exports.geoCraig = craig;
+exports.geoCraigRaw = craigRaw;
+exports.geoCraster = craster;
+exports.geoCrasterRaw = crasterRaw;
+exports.geoCylindricalEqualArea = cylindricalEqualArea;
+exports.geoCylindricalEqualAreaRaw = cylindricalEqualAreaRaw;
+exports.geoCylindricalStereographic = cylindricalStereographic;
+exports.geoCylindricalStereographicRaw = cylindricalStereographicRaw;
+exports.geoEckert1 = eckert1;
+exports.geoEckert1Raw = eckert1Raw;
+exports.geoEckert2 = eckert2;
+exports.geoEckert2Raw = eckert2Raw;
+exports.geoEckert3 = eckert3;
+exports.geoEckert3Raw = eckert3Raw;
+exports.geoEckert4 = eckert4;
+exports.geoEckert4Raw = eckert4Raw;
+exports.geoEckert5 = eckert5;
+exports.geoEckert5Raw = eckert5Raw;
+exports.geoEckert6 = eckert6;
+exports.geoEckert6Raw = eckert6Raw;
+exports.geoEisenlohr = eisenlohr;
+exports.geoEisenlohrRaw = eisenlohrRaw;
+exports.geoFahey = fahey;
+exports.geoFaheyRaw = faheyRaw;
+exports.geoFoucaut = foucaut;
+exports.geoFoucautRaw = foucautRaw;
+exports.geoFoucautSinusoidal = foucautSinusoidal;
+exports.geoFoucautSinusoidalRaw = foucautSinusoidalRaw;
+exports.geoGilbert = gilbert;
+exports.geoGingery = gingery;
+exports.geoGingeryRaw = gingeryRaw;
+exports.geoGinzburg4 = ginzburg4;
+exports.geoGinzburg4Raw = ginzburg4Raw;
+exports.geoGinzburg5 = ginzburg5;
+exports.geoGinzburg5Raw = ginzburg5Raw;
+exports.geoGinzburg6 = ginzburg6;
+exports.geoGinzburg6Raw = ginzburg6Raw;
+exports.geoGinzburg8 = ginzburg8;
+exports.geoGinzburg8Raw = ginzburg8Raw;
+exports.geoGinzburg9 = ginzburg9;
+exports.geoGinzburg9Raw = ginzburg9Raw;
+exports.geoGringorten = gringorten$1;
+exports.geoGringortenQuincuncial = gringorten;
+exports.geoGringortenRaw = gringortenRaw;
+exports.geoGuyou = guyou;
+exports.geoGuyouRaw = guyouRaw;
+exports.geoHammer = hammer;
+exports.geoHammerRaw = hammerRaw;
+exports.geoHammerRetroazimuthal = hammerRetroazimuthal;
+exports.geoHammerRetroazimuthalRaw = hammerRetroazimuthalRaw;
+exports.geoHealpix = healpix;
+exports.geoHealpixRaw = healpixRaw;
+exports.geoHill = hill;
+exports.geoHillRaw = hillRaw;
+exports.geoHomolosine = homolosine$1;
+exports.geoHomolosineRaw = homolosineRaw;
+exports.geoHufnagel = hufnagel;
+exports.geoHufnagelRaw = hufnagelRaw;
+exports.geoHyperelliptical = hyperelliptical;
+exports.geoHyperellipticalRaw = hyperellipticalRaw;
+exports.geoInterrupt = interrupt;
+exports.geoInterruptedBoggs = boggs;
+exports.geoInterruptedHomolosine = homolosine;
+exports.geoInterruptedMollweide = mollweide;
+exports.geoInterruptedMollweideHemispheres = mollweideHemispheres;
+exports.geoInterruptedQuarticAuthalic = quarticAuthalic;
+exports.geoInterruptedSinuMollweide = sinuMollweide;
+exports.geoInterruptedSinusoidal = sinusoidal;
+exports.geoKavrayskiy7 = kavrayskiy7;
+exports.geoKavrayskiy7Raw = kavrayskiy7Raw;
+exports.geoLagrange = lagrange;
+exports.geoLagrangeRaw = lagrangeRaw;
+exports.geoLarrivee = larrivee;
+exports.geoLarriveeRaw = larriveeRaw;
+exports.geoLaskowski = laskowski;
+exports.geoLaskowskiRaw = laskowskiRaw;
+exports.geoLittrow = littrow;
+exports.geoLittrowRaw = littrowRaw;
+exports.geoLoximuthal = loximuthal;
+exports.geoLoximuthalRaw = loximuthalRaw;
+exports.geoMiller = miller$1;
+exports.geoMillerRaw = millerRaw;
+exports.geoModifiedStereographic = modifiedStereographic;
+exports.geoModifiedStereographicAlaska = modifiedStereographicAlaska;
+exports.geoModifiedStereographicGs48 = modifiedStereographicGs48;
+exports.geoModifiedStereographicGs50 = modifiedStereographicGs50;
+exports.geoModifiedStereographicLee = modifiedStereographicLee;
+exports.geoModifiedStereographicMiller = modifiedStereographicMiller;
+exports.geoModifiedStereographicRaw = modifiedStereographicRaw;
+exports.geoMollweide = mollweide$1;
+exports.geoMollweideRaw = mollweideRaw;
+exports.geoMtFlatPolarParabolic = mtFlatPolarParabolic;
+exports.geoMtFlatPolarParabolicRaw = mtFlatPolarParabolicRaw;
+exports.geoMtFlatPolarQuartic = mtFlatPolarQuartic;
+exports.geoMtFlatPolarQuarticRaw = mtFlatPolarQuarticRaw;
+exports.geoMtFlatPolarSinusoidal = mtFlatPolarSinusoidal;
+exports.geoMtFlatPolarSinusoidalRaw = mtFlatPolarSinusoidalRaw;
+exports.geoNaturalEarth2 = naturalEarth2;
+exports.geoNaturalEarth2Raw = naturalEarth2Raw;
+exports.geoNellHammer = nellHammer;
+exports.geoNellHammerRaw = nellHammerRaw;
+exports.geoNicolosi = nicolosi;
+exports.geoNicolosiRaw = nicolosiRaw;
+exports.geoPatterson = patterson;
+exports.geoPattersonRaw = pattersonRaw;
+exports.geoPeirceQuincuncial = peirce;
+exports.geoPolyconic = polyconic;
+exports.geoPolyconicRaw = polyconicRaw;
+exports.geoPolyhedral = polyhedral;
+exports.geoPolyhedralButterfly = butterfly;
+exports.geoPolyhedralCollignon = collignon;
+exports.geoPolyhedralWaterman = waterman;
+exports.geoProject = index;
+exports.geoQuantize = quantize$1;
+exports.geoQuincuncial = quincuncial;
+exports.geoRectangularPolyconic = rectangularPolyconic;
+exports.geoRectangularPolyconicRaw = rectangularPolyconicRaw;
+exports.geoRobinson = robinson;
+exports.geoRobinsonRaw = robinsonRaw;
+exports.geoSatellite = satellite;
+exports.geoSatelliteRaw = satelliteRaw;
+exports.geoSinuMollweide = sinuMollweide$1;
+exports.geoSinuMollweideRaw = sinuMollweideRaw;
+exports.geoSinusoidal = sinusoidal$1;
+exports.geoSinusoidalRaw = sinusoidalRaw;
+exports.geoStitch = stitch;
+exports.geoTimes = times;
+exports.geoTimesRaw = timesRaw;
+exports.geoTwoPointAzimuthal = twoPointAzimuthal;
+exports.geoTwoPointAzimuthalRaw = twoPointAzimuthalRaw;
+exports.geoTwoPointAzimuthalUsa = twoPointAzimuthalUsa;
+exports.geoTwoPointEquidistant = twoPointEquidistant;
+exports.geoTwoPointEquidistantRaw = twoPointEquidistantRaw;
+exports.geoTwoPointEquidistantUsa = twoPointEquidistantUsa;
+exports.geoVanDerGrinten = vanDerGrinten;
+exports.geoVanDerGrinten2 = vanDerGrinten2;
+exports.geoVanDerGrinten2Raw = vanDerGrinten2Raw;
+exports.geoVanDerGrinten3 = vanDerGrinten3;
+exports.geoVanDerGrinten3Raw = vanDerGrinten3Raw;
+exports.geoVanDerGrinten4 = vanDerGrinten4;
+exports.geoVanDerGrinten4Raw = vanDerGrinten4Raw;
+exports.geoVanDerGrintenRaw = vanDerGrintenRaw;
+exports.geoWagner = wagner;
+exports.geoWagner4 = wagner4;
+exports.geoWagner4Raw = wagner4Raw;
+exports.geoWagner6 = wagner6;
+exports.geoWagner6Raw = wagner6Raw;
+exports.geoWagner7 = wagner7;
+exports.geoWagnerRaw = wagnerRaw;
+exports.geoWiechel = wiechel;
+exports.geoWiechelRaw = wiechelRaw;
+exports.geoWinkel3 = winkel3;
+exports.geoWinkel3Raw = winkel3Raw;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/node_modules/d3-geo-projection/dist/d3-geo-projection.min.js b/node_modules/d3-geo-projection/dist/d3-geo-projection.min.js
new file mode 100644
index 000000000..1238fb995
--- /dev/null
+++ b/node_modules/d3-geo-projection/dist/d3-geo-projection.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org/d3-geo-projection/ v4.0.0 Copyright 2013-2021 Mike Bostock, 2015 Ricky Reusser
+!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("d3-geo"),require("d3-array")):"function"==typeof define&&define.amd?define(["exports","d3-geo","d3-array"],r):r((n="undefined"!=typeof globalThis?globalThis:n||self).d3=n.d3||{},n.d3,n.d3)}(this,(function(n,r,e){"use strict";var t=Math.abs,o=Math.atan,i=Math.atan2,u=Math.cos,a=Math.exp,c=Math.floor,f=Math.log,l=Math.max,g=Math.min,v=Math.pow,s=Math.round,p=Math.sign||function(n){return n>0?1:n<0?-1:0},h=Math.sin,d=Math.tan,w=1e-6,y=1e-12,m=Math.PI,P=m/2,R=m/4,b=Math.SQRT1_2,j=G(2),M=G(m),E=2*m,S=180/m,k=m/180;function A(n){return n>1?P:n<-1?-P:Math.asin(n)}function x(n){return n>1?0:n<-1?m:Math.acos(n)}function G(n){return n>0?Math.sqrt(n):0}function C(n){return(a(n)-a(-n))/2}function F(n){return(a(n)+a(-n))/2}function z(n){var r=d(n/2),e=2*f(u(n/2))/(r*r);function o(n,r){var t=u(n),o=u(r),i=h(r),a=o*t,c=-((1-a?f((1+a)/2)/(1-a):-.5)+e/(1+a));return[c*o*h(n),c*i]}return o.invert=function(r,o){var a,c=G(r*r+o*o),l=-n/2,g=50;if(!c)return[0,0];do{var v=l/2,s=u(v),p=h(v),d=p/s,y=-f(t(s));l-=a=(2/d*y-e*d-c)/(-y/(p*p)+1-e/(2*s*s))*(s<0?.7:1)}while(t(a)>w&&--g>0);var m=h(l);return[i(r*m,c*u(l)),A(o*m/c)]},o}function N(n,r){var e=u(r),t=function(n){return n?n/Math.sin(n):1}(x(e*u(n/=2)));return[2*e*h(n)*t,h(r)*t]}function L(n){var r=h(n),e=u(n),o=n>=0?1:-1,a=d(o*n),c=(1+r-e)/2;function f(n,t){var f=u(t),l=u(n/=2);return[(1+f)*h(n),(o*t>-i(l,a)-.001?0:10*-o)+c+h(t)*e-(1+f)*r*l]}return f.invert=function(n,f){var l=0,g=0,v=50;do{var s=u(l),p=h(l),d=u(g),y=h(g),m=1+d,P=m*p-n,R=c+y*e-m*r*s-f,b=m*s/2,j=-p*y,M=r*m*p/2,E=e*d+r*s*y,S=j*M-E*b,k=(R*j-P*E)/S/2,A=(P*M-R*b)/S;t(A)>2&&(A/=2),l-=k,g-=A}while((t(k)>w||t(A)>w)&&--v>0);return o*g>-i(u(l),a)-.001?[2*l,g]:null},f}function H(n,r){var e=d(r/2),t=G(1-e*e),o=1+t*u(n/=2),i=h(n)*t/o,a=e/o,c=i*i,f=a*a;return[4/3*i*(3+c-3*f),4/3*a*(3+3*c-f)]}N.invert=function(n,r){if(!(n*n+4*r*r>m*m+w)){var e=n,o=r,i=25;do{var a,c=h(e),f=h(e/2),l=u(e/2),g=h(o),v=u(o),s=h(2*o),p=g*g,d=v*v,y=f*f,P=1-d*l*l,R=P?x(v*l)*G(a=1/P):a=0,b=2*R*v*f-n,j=R*g-r,M=a*(d*y+R*v*l*p),E=a*(.5*c*s-2*R*g*f),S=.25*a*(s*f-R*g*d*c),k=a*(p*l+R*y*v),A=E*S-k*M;if(!A)break;var C=(j*E-b*k)/A,F=(b*S-j*M)/A;e-=C,o-=F}while((t(C)>w||t(F)>w)&&--i>0);return[e,o]}},H.invert=function(n,r){if(r*=3/8,!(n*=3/8)&&t(r)>1)return null;var e=1+n*n+r*r,o=G((e-G(e*e-4*r*r))/2),a=A(o)/3,c=o?function(n){return f(n+G(n*n-1))}(t(r/o))/3:function(n){return f(n+G(n*n+1))}(t(n))/3,l=u(a),g=F(c),v=g*g-l*l;return[2*p(n)*i(C(c)*l,.25-v),2*p(r)*i(g*h(a),.25+v)]};var q=G(8),B=f(1+j);function W(n,r){var e=t(r);return eP){var c=i(a[1],a[0]),f=G(a[0]*a[0]+a[1]*a[1]),l=e*s((c-P)/e)+P,g=i(h(c-=l),2-u(c));c=l+A(m/f*h(g))-g,a[0]=f*u(c),a[1]=f*h(c)}return a}return a.invert=function(n,t){var a=G(n*n+t*t);if(a>P){var c=i(t,n),f=e*s((c-P)/e)+P,l=c>f?-1:1,g=a*u(f-c),v=1/d(l*x((g-m)/G(m*(m-2*g)+a*a)));c=f+2*o((v+l*G(v*v-3))/3),n=a*u(c),t=a*h(c)}return r.geoAzimuthalEquidistantRaw.invert(n,t)},a}function T(n,e){if(arguments.length<2&&(e=n),1===e)return r.geoAzimuthalEqualAreaRaw;if(e===1/0)return D;function t(t,o){var i=r.geoAzimuthalEqualAreaRaw(t/e,o);return i[0]*=n,i}return t.invert=function(t,o){var i=r.geoAzimuthalEqualAreaRaw.invert(t/n,o);return i[0]*=e,i},t}function D(n,r){return[n*u(r)/u(r/=2),2*h(r)]}function Q(n,r,e){var o,i,u,a=100;e=void 0===e?0:+e,r=+r;do{(i=n(e))===(u=n(e+w))&&(u=i+w),e-=o=-1e-6*(i-r)/(i-u)}while(a-- >0&&t(o)>w);return a<0?NaN:e}function V(n,r,e){return void 0===r&&(r=40),void 0===e&&(e=y),function(o,i,u,a){var c,f,l;u=void 0===u?0:+u,a=void 0===a?0:+a;for(var g=0;gc)u-=f/=2,a-=l/=2;else{c=h;var d=(u>0?-1:1)*e,w=(a>0?-1:1)*e,y=n(u+d,a),m=n(u,a+w),P=(y[0]-v[0])/d,R=(y[1]-v[1])/d,b=(m[0]-v[0])/w,j=(m[1]-v[1])/w,M=j*P-R*b,E=(t(M)<.5?.5:1)/M;if(u+=f=(p*b-s*j)*E,a+=l=(s*R-p*P)*E,t(f)0&&(o[1]*=1+i/1.5*o[0]*o[0]),o}return r.invert=V(r),r}function K(n,r){var e,o=n*h(r),i=30;do{r-=e=(r+h(r)-o)/(1+u(r))}while(t(e)>w&&--i>0);return r/2}function O(n,r,e){function t(t,o){return[n*t*u(o=K(e,o)),r*h(o)]}return t.invert=function(t,o){return o=A(o/r),[t/(n*u(o)),A((2*o+h(2*o))/e)]},t}W.invert=function(n,r){if((i=t(r))y&&--l>0);return[n/(u(c)*(q-1/h(c))),p(r)*c]},D.invert=function(n,r){var e=2*A(r/2);return[n*u(e/2)/u(e),e]};var U=O(j/P,j,m);var J=2.00276,X=1.11072;function Y(n,r){var e=K(m,r);return[J*n/(1/u(r)+X/u(e)),(r+j*h(e))/J]}function Z(n){var e=0,t=r.geoProjectionMutator(n),o=t(e);return o.parallel=function(n){return arguments.length?t(e=n*k):e*S},o}function $(n,r){return[n*u(r),r]}function nn(n){if(!n)return $;var r=1/d(n);function e(e,t){var o=r+n-t,i=o?e*u(t)/o:o;return[o*h(i),r-o*u(i)]}return e.invert=function(e,t){var o=G(e*e+(t=r-t)*t),a=r+n-o;return[o/u(a)*i(e,t),a]},e}function rn(n){function r(r,e){var t=P-e,o=t?r*n*h(t)/t:t;return[t*h(o)/n,P-t*u(o)]}return r.invert=function(r,e){var t=r*n,o=P-e,u=G(t*t+o*o),a=i(t,o);return[(u?u/h(u):1)*a/n,P-u]},r}Y.invert=function(n,r){var e,o,i=J*r,a=r<0?-R:R,c=25;do{o=i-j*h(a),a-=e=(h(2*a)+2*a-m*h(o))/(2*u(2*a)+2+m*u(o)*j*u(a))}while(t(e)>w&&--c>0);return o=i-j*h(a),[n*(1/u(o)+X/u(a))/J,o]},$.invert=function(n,r){return[n/u(r),r]};var en=O(1,4/m,m);function tn(n,r,e,o,a,c){var f,l=u(c);if(t(n)>1||t(c)>1)f=x(e*a+r*o*l);else{var g=h(n/2),v=h(c/2);f=2*A(G(g*g+r*o*v*v))}return t(f)>w?[f,i(o*h(c),r*a-e*o*l)]:[0,0]}function on(n,r,e){return x((n*n+r*r-e*e)/(2*n*r))}function un(n){return n-2*m*c((n+m)/(2*m))}function an(n,r,e){for(var t,o=[[n[0],n[1],h(n[1]),u(n[1])],[r[0],r[1],h(r[1]),u(r[1])],[e[0],e[1],h(e[1]),u(e[1])]],i=o[2],a=0;a<3;++a,i=t)t=o[a],i.v=tn(t[1]-i[1],i[3],i[2],t[3],t[2],t[0]-i[0]),i.point=[0,0];var c=on(o[0].v[0],o[2].v[0],o[1].v[0]),f=on(o[0].v[0],o[1].v[0],o[2].v[0]),l=m-c;o[2].point[1]=0,o[0].point[0]=-(o[1].point[0]=o[0].v[0]/2);var g=[o[2].point[0]=o[0].point[0]+o[2].v[0]*u(c),2*(o[0].point[1]=o[1].point[1]=o[2].v[0]*h(c))];return function(n,r){var e,t=h(r),i=u(r),a=new Array(3);for(e=0;e<3;++e){var c=o[e];if(a[e]=tn(r-c[1],c[3],c[2],i,t,n-c[0]),!a[e][0])return c.point;a[e][1]=un(a[e][1]-c.v[1])}var v=g.slice();for(e=0;e<3;++e){var s=2==e?0:e+1,p=on(o[e].v[0],a[e][0],a[s][0]);a[e][1]<0&&(p=-p),e?1==e?(p=f-p,v[0]-=a[e][0]*u(p),v[1]-=a[e][0]*h(p)):(p=l-p,v[0]+=a[e][0]*u(p),v[1]+=a[e][0]*h(p)):(v[0]+=a[e][0]*u(p),v[1]-=a[e][0]*h(p))}return v[0]/=3,v[1]/=3,v}}function cn(n){return n[0]*=k,n[1]*=k,n}function fn(n,e,t){var o=r.geoCentroid({type:"MultiPoint",coordinates:[n,e,t]}),i=[-o[0],-o[1]],u=r.geoRotation(i),a=an(cn(u(n)),cn(u(e)),cn(u(t)));a.invert=V(a);var c=r.geoProjection(a).rotate(i),f=c.center;return delete c.rotate,c.center=function(n){return arguments.length?f(u(n)):u.invert(f())},c.clipAngle(90)}function ln(n,r){var e=G(1-h(r));return[2/M*n*e,M*(1-e)]}function gn(n){var r=d(n);function e(n,e){return[n,(n?n/h(n):1)*(h(e)*u(n)-r*u(e))]}return e.invert=r?function(n,e){n&&(e*=h(n)/n);var t=u(n);return[n,2*i(G(t*t+r*r-e*e)-t,r-e)]}:function(n,r){return[n,A(n?r*d(n)/n:r)]},e}ln.invert=function(n,r){var e=(e=r/M-1)*e;return[e>0?n*G(m/e)/2:0,A(1-e)]};var vn=G(3);function sn(n,r){return[vn*n*(2*u(2*r/3)-1)/M,vn*M*h(r/3)]}function pn(n){var r=u(n);function e(n,e){return[n*r,h(e)/r]}return e.invert=function(n,e){return[n/r,A(e*r)]},e}function hn(n){var r=u(n);function e(n,e){return[n*r,(1+r)*d(e/2)]}return e.invert=function(n,e){return[n/r,2*o(e/(1+r))]},e}function dn(n,r){var e=G(8/(3*m));return[e*n*(1-t(r)/m),e*r]}function wn(n,r){var e=G(4-3*h(t(r)));return[2/G(6*m)*n*e,p(r)*G(2*m/3)*(2-e)]}function yn(n,r){var e=G(m*(4+m));return[2/e*n*(1+G(1-4*r*r/(m*m))),4/e*r]}function mn(n,r){var e=(2+P)*h(r);r/=2;for(var o=0,i=1/0;o<10&&t(i)>w;o++){var a=u(r);r-=i=(r+h(r)*(a+2)-e)/(2*a*(1+a))}return[2/G(m*(4+m))*n*(1+u(r)),2*G(m/(4+m))*h(r)]}function Pn(n,r){return[n*(1+u(r))/G(2+m),2*r/G(2+m)]}function Rn(n,r){for(var e=(1+P)*h(r),o=0,i=1/0;o<10&&t(i)>w;o++)r-=i=(r+h(r)-e)/(1+u(r));return e=G(2+m),[n*(1+u(r))/e,2*r/e]}sn.invert=function(n,r){var e=3*A(r/(vn*M));return[M*n/(vn*(2*u(2*e/3)-1)),e]},dn.invert=function(n,r){var e=G(8/(3*m)),o=r/e;return[n/(e*(1-t(o)/m)),o]},wn.invert=function(n,r){var e=2-t(r)/G(2*m/3);return[n*G(6*m)/(2*e),p(r)*A((4-e*e)/3)]},yn.invert=function(n,r){var e=G(m*(4+m))/2;return[n*e/(1+G(1-r*r*(4+m)/(4*m))),r*e/2]},mn.invert=function(n,r){var e=r*G((4+m)/m)/2,t=A(e),o=u(t);return[n/(2/G(m*(4+m))*(1+o)),A((t+e*(o+2))/(2+P))]},Pn.invert=function(n,r){var e=G(2+m),t=r*e/2;return[e*n/(1+u(t)),t]},Rn.invert=function(n,r){var e=1+P,t=G(e/2);return[2*n*t/(1+u(r*=t)),A((r+h(r))/e)]};var bn=3+2*j;function jn(n,r){var e=h(n/=2),t=u(n),i=G(u(r)),a=u(r/=2),c=h(r)/(a+j*t*i),l=G(2/(1+c*c)),g=G((j*a+(t+e)*i)/(j*a+(t-e)*i));return[bn*(l*(g-1/g)-2*f(g)),bn*(l*c*(g+1/g)-2*o(c))]}jn.invert=function(n,r){if(!(e=H.invert(n/1.2,1.065*r)))return null;var e,i=e[0],a=e[1],c=20;n/=bn,r/=bn;do{var v=i/2,s=a/2,p=h(v),d=u(v),y=h(s),m=u(s),R=u(a),M=G(R),E=y/(m+j*d*M),S=E*E,k=G(2/(1+S)),A=(j*m+(d+p)*M)/(j*m+(d-p)*M),x=G(A),C=x-1/x,F=x+1/x,z=k*C-2*f(x)-n,N=k*E*F-2*o(E)-r,L=y&&b*M*p*S/y,q=(j*d*m+M)/(2*(m+j*d*M)*(m+j*d*M)*M),B=-.5*E*k*k*k,W=B*L,I=B*q,T=(T=2*m+j*M*(d-p))*T*x,D=(j*d*m*M+R)/T,Q=-j*p*y/(M*T),V=C*W-2*D/x+k*(D+D/A),_=C*I-2*Q/x+k*(Q+Q/A),K=E*F*W-2*L/(1+S)+k*F*L+k*E*(D-D/A),O=E*F*I-2*q/(1+S)+k*F*q+k*E*(Q-Q/A),U=_*K-O*V;if(!U)break;var J=(N*_-z*O)/U,X=(z*K-N*V)/U;i-=J,a=l(-P,g(P,a-X))}while((t(J)>w||t(X)>w)&&--c>0);return t(t(a)-P)a){var p=G(v),d=i(g,l),y=o*s(d/o),R=d-y,b=n*u(R),j=(n*h(R)-R*h(b))/(P-b),M=Cn(R,j),E=(m-n)/Fn(M,b,m);l=p;var S,k=50;do{l-=S=(n+Fn(M,b,l)*E-p)/(M(l)*E)}while(t(S)>w&&--k>0);g=R*h(l),l