]> git.openstreetmap.org Git - rails.git/blobdiff - vendor/assets/iD/iD.js
Merge remote-tracking branch 'upstream/pull/5284'
[rails.git] / vendor / assets / iD / iD.js
index 6d457ec6f2f9bd4dd03f19e1ca3144a360325bc7..99da55a78cade58c292321df249b99133d9018a0 100644 (file)
@@ -9,8 +9,7 @@
   var __require = /* @__PURE__ */ ((x2) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x2, {
     get: (a2, b2) => (typeof require !== "undefined" ? require : a2)[b2]
   }) : x2)(function(x2) {
-    if (typeof require !== "undefined")
-      return require.apply(this, arguments);
+    if (typeof require !== "undefined") return require.apply(this, arguments);
     throw Error('Dynamic require of "' + x2 + '" is not supported');
   });
   var __commonJS = (cb, mod) => function __require2() {
     isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
     mod
   ));
-  var __publicField = (obj, key, value) => {
-    __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
-    return value;
-  };
-  var __accessCheck = (obj, member, msg) => {
-    if (!member.has(obj))
-      throw TypeError("Cannot " + msg);
-  };
-  var __privateAdd = (obj, member, value) => {
-    if (member.has(obj))
-      throw TypeError("Cannot add the same private member more than once");
-    member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
-  };
-  var __privateMethod = (obj, member, method) => {
-    __accessCheck(obj, member, "access private method");
-    return method;
-  };
+  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
 
   // node_modules/diacritics/index.js
   var require_diacritics = __commonJS({
     "node_modules/alif-toolkit/lib/isArabic.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.isArabic = isArabic;
+      exports2.isMath = isMath;
       var arabicBlocks = [
         [1536, 1791],
+        // Arabic https://www.unicode.org/charts/PDF/U0600.pdf
         [1872, 1919],
+        // supplement https://www.unicode.org/charts/PDF/U0750.pdf
         [2208, 2303],
+        // Extended-A https://www.unicode.org/charts/PDF/U08A0.pdf
         [64336, 65023],
+        // Presentation Forms-A https://www.unicode.org/charts/PDF/UFB50.pdf
         [65136, 65279],
+        // Presentation Forms-B https://www.unicode.org/charts/PDF/UFE70.pdf
         [69216, 69247],
+        // Rumi numerals https://www.unicode.org/charts/PDF/U10E60.pdf
         [126064, 126143],
+        // Indic Siyaq numerals https://www.unicode.org/charts/PDF/U1EC70.pdf
         [126464, 126719]
         // Mathematical Alphabetic symbols https://www.unicode.org/charts/PDF/U1EE00.pdf
       ];
         }
         return false;
       }
-      exports2.isArabic = isArabic;
       function isMath(char) {
         if (char.length > 2) {
           throw new Error("isMath works on only one-character strings");
         let code = char.charCodeAt(0);
         return code >= 1632 && code <= 1644 || code >= 1776 && code <= 1785;
       }
-      exports2.isMath = isMath;
     }
   });
 
     "node_modules/alif-toolkit/lib/reference.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.ligatureWordList = exports2.ligatureList = exports2.letterList = exports2.alefs = exports2.lams = exports2.lineBreakers = exports2.tashkeel = void 0;
       var unicode_arabic_1 = require_unicode_arabic();
       var unicode_ligatures_1 = require_unicode_ligatures();
       var letterList = Object.keys(unicode_arabic_1.default);
     "node_modules/alif-toolkit/lib/GlyphSplitter.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.GlyphSplitter = GlyphSplitter;
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       function GlyphSplitter(word) {
         let letters = [];
         let lastLetter = "";
         word.split("").forEach((letter) => {
-          if (isArabic_1.isArabic(letter)) {
+          if ((0, isArabic_1.isArabic)(letter)) {
             if (reference_1.tashkeel.indexOf(letter) > -1) {
               letters[letters.length - 1] += letter;
             } else if (lastLetter.length && (reference_1.lams.indexOf(lastLetter) === 0 && reference_1.alefs.indexOf(letter) > -1 || reference_1.lams.indexOf(lastLetter) > 0 && reference_1.alefs.indexOf(letter) === 0)) {
         });
         return letters;
       }
-      exports2.GlyphSplitter = GlyphSplitter;
     }
   });
 
     "node_modules/alif-toolkit/lib/BaselineSplitter.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.BaselineSplitter = BaselineSplitter;
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       function BaselineSplitter(word) {
         let letters = [];
         let lastLetter = "";
         word.split("").forEach((letter) => {
-          if (isArabic_1.isArabic(letter) && isArabic_1.isArabic(lastLetter)) {
+          if ((0, isArabic_1.isArabic)(letter) && (0, isArabic_1.isArabic)(lastLetter)) {
             if (lastLetter.length && reference_1.tashkeel.indexOf(letter) > -1) {
               letters[letters.length - 1] += letter;
             } else if (reference_1.lineBreakers.indexOf(lastLetter) > -1) {
         });
         return letters;
       }
-      exports2.BaselineSplitter = BaselineSplitter;
     }
   });
 
     "node_modules/alif-toolkit/lib/Normalization.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.Normal = Normal;
       var unicode_arabic_1 = require_unicode_arabic();
       var unicode_ligatures_1 = require_unicode_ligatures();
       var isArabic_1 = require_isArabic();
         }
         let returnable = "";
         word.split("").forEach((letter) => {
-          if (!isArabic_1.isArabic(letter)) {
+          if (!(0, isArabic_1.isArabic)(letter)) {
             returnable += letter;
             return;
           }
         });
         return returnable;
       }
-      exports2.Normal = Normal;
     }
   });
 
     "node_modules/alif-toolkit/lib/CharShaper.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.CharShaper = CharShaper;
       var unicode_arabic_1 = require_unicode_arabic();
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       function CharShaper(letter, form) {
-        if (!isArabic_1.isArabic(letter)) {
+        if (!(0, isArabic_1.isArabic)(letter)) {
           throw new Error("Not Arabic");
         }
         if (letter === "\u0621") {
           }
         }
       }
-      exports2.CharShaper = CharShaper;
     }
   });
 
     "node_modules/alif-toolkit/lib/WordShaper.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.WordShaper = WordShaper2;
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       var CharShaper_1 = require_CharShaper();
         for (let w2 = 0; w2 < word.length; w2++) {
           let nextLetter = " ";
           for (let nxw = w2 + 1; nxw < word.length; nxw++) {
-            if (!isArabic_1.isArabic(word[nxw])) {
+            if (!(0, isArabic_1.isArabic)(word[nxw])) {
               break;
             }
             if (reference_1.tashkeel.indexOf(word[nxw]) === -1) {
               break;
             }
           }
-          if (!isArabic_1.isArabic(word[w2]) || isArabic_1.isMath(word[w2])) {
+          if (!(0, isArabic_1.isArabic)(word[w2]) || (0, isArabic_1.isMath)(word[w2])) {
             output += word[w2];
             state = "initial";
           } else if (reference_1.tashkeel.indexOf(word[w2]) > -1) {
             output += word[w2];
           } else if (nextLetter === " " || reference_1.lineBreakers.indexOf(word[w2]) > -1) {
-            output += CharShaper_1.CharShaper(word[w2], state === "initial" ? "isolated" : "final");
+            output += (0, CharShaper_1.CharShaper)(word[w2], state === "initial" ? "isolated" : "final");
             state = "initial";
           } else if (reference_1.lams.indexOf(word[w2]) > -1 && reference_1.alefs.indexOf(nextLetter) > -1) {
             output += unicode_ligatures_1.default[word[w2] + nextLetter][state === "initial" ? "isolated" : "final"];
             }
             state = "initial";
           } else {
-            output += CharShaper_1.CharShaper(word[w2], state);
+            output += (0, CharShaper_1.CharShaper)(word[w2], state);
             state = "medial";
           }
         }
         return output;
       }
-      exports2.WordShaper = WordShaper2;
     }
   });
 
     "node_modules/alif-toolkit/lib/ParentLetter.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.ParentLetter = ParentLetter;
+      exports2.GrandparentLetter = GrandparentLetter;
       var unicode_arabic_1 = require_unicode_arabic();
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       function ParentLetter(letter) {
-        if (!isArabic_1.isArabic(letter)) {
+        if (!(0, isArabic_1.isArabic)(letter)) {
           throw new Error("Not an Arabic letter");
         }
         for (let w2 = 0; w2 < reference_1.letterList.length; w2++) {
           return null;
         }
       }
-      exports2.ParentLetter = ParentLetter;
       function GrandparentLetter(letter) {
-        if (!isArabic_1.isArabic(letter)) {
+        if (!(0, isArabic_1.isArabic)(letter)) {
           throw new Error("Not an Arabic letter");
         }
         for (let w2 = 0; w2 < reference_1.letterList.length; w2++) {
           return null;
         }
       }
-      exports2.GrandparentLetter = GrandparentLetter;
     }
   });
 
     "node_modules/alif-toolkit/lib/index.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.GrandparentLetter = exports2.ParentLetter = exports2.WordShaper = exports2.CharShaper = exports2.Normal = exports2.BaselineSplitter = exports2.GlyphSplitter = exports2.isArabic = void 0;
       var isArabic_1 = require_isArabic();
-      exports2.isArabic = isArabic_1.isArabic;
+      Object.defineProperty(exports2, "isArabic", { enumerable: true, get: function() {
+        return isArabic_1.isArabic;
+      } });
       var GlyphSplitter_1 = require_GlyphSplitter();
-      exports2.GlyphSplitter = GlyphSplitter_1.GlyphSplitter;
+      Object.defineProperty(exports2, "GlyphSplitter", { enumerable: true, get: function() {
+        return GlyphSplitter_1.GlyphSplitter;
+      } });
       var BaselineSplitter_1 = require_BaselineSplitter();
-      exports2.BaselineSplitter = BaselineSplitter_1.BaselineSplitter;
+      Object.defineProperty(exports2, "BaselineSplitter", { enumerable: true, get: function() {
+        return BaselineSplitter_1.BaselineSplitter;
+      } });
       var Normalization_1 = require_Normalization();
-      exports2.Normal = Normalization_1.Normal;
+      Object.defineProperty(exports2, "Normal", { enumerable: true, get: function() {
+        return Normalization_1.Normal;
+      } });
       var CharShaper_1 = require_CharShaper();
-      exports2.CharShaper = CharShaper_1.CharShaper;
+      Object.defineProperty(exports2, "CharShaper", { enumerable: true, get: function() {
+        return CharShaper_1.CharShaper;
+      } });
       var WordShaper_1 = require_WordShaper();
-      exports2.WordShaper = WordShaper_1.WordShaper;
+      Object.defineProperty(exports2, "WordShaper", { enumerable: true, get: function() {
+        return WordShaper_1.WordShaper;
+      } });
       var ParentLetter_1 = require_ParentLetter();
-      exports2.ParentLetter = ParentLetter_1.ParentLetter;
-      exports2.GrandparentLetter = ParentLetter_1.GrandparentLetter;
+      Object.defineProperty(exports2, "ParentLetter", { enumerable: true, get: function() {
+        return ParentLetter_1.ParentLetter;
+      } });
+      Object.defineProperty(exports2, "GrandparentLetter", { enumerable: true, get: function() {
+        return ParentLetter_1.GrandparentLetter;
+      } });
     }
   });
 
         typeof exports2 === "object" && typeof module2 !== "undefined" ? module2.exports = factory() : typeof define === "function" && define.amd ? define(factory) : global2.quickselect = factory();
       })(exports2, function() {
         "use strict";
-        function quickselect2(arr, k2, left, right, compare2) {
-          quickselectStep(arr, k2, left || 0, right || arr.length - 1, compare2 || defaultCompare);
+        function quickselect3(arr, k2, left, right, compare2) {
+          quickselectStep2(arr, k2, left || 0, right || arr.length - 1, compare2 || defaultCompare2);
         }
-        function quickselectStep(arr, k2, left, right, compare2) {
+        function quickselectStep2(arr, k2, left, right, compare2) {
           while (right > left) {
             if (right - left > 600) {
               var n3 = right - left + 1;
               var sd = 0.5 * Math.sqrt(z2 * s2 * (n3 - s2) / n3) * (m2 - n3 / 2 < 0 ? -1 : 1);
               var newLeft = Math.max(left, Math.floor(k2 - m2 * s2 / n3 + sd));
               var newRight = Math.min(right, Math.floor(k2 + (n3 - m2) * s2 / n3 + sd));
-              quickselectStep(arr, k2, newLeft, newRight, compare2);
+              quickselectStep2(arr, k2, newLeft, newRight, compare2);
             }
             var t2 = arr[k2];
             var i3 = left;
             var j2 = right;
-            swap2(arr, left, k2);
-            if (compare2(arr[right], t2) > 0)
-              swap2(arr, left, right);
+            swap3(arr, left, k2);
+            if (compare2(arr[right], t2) > 0) swap3(arr, left, right);
             while (i3 < j2) {
-              swap2(arr, i3, j2);
+              swap3(arr, i3, j2);
               i3++;
               j2--;
-              while (compare2(arr[i3], t2) < 0)
-                i3++;
-              while (compare2(arr[j2], t2) > 0)
-                j2--;
+              while (compare2(arr[i3], t2) < 0) i3++;
+              while (compare2(arr[j2], t2) > 0) j2--;
             }
-            if (compare2(arr[left], t2) === 0)
-              swap2(arr, left, j2);
+            if (compare2(arr[left], t2) === 0) swap3(arr, left, j2);
             else {
               j2++;
-              swap2(arr, j2, right);
+              swap3(arr, j2, right);
             }
-            if (j2 <= k2)
-              left = j2 + 1;
-            if (k2 <= j2)
-              right = j2 - 1;
+            if (j2 <= k2) left = j2 + 1;
+            if (k2 <= j2) right = j2 - 1;
           }
         }
-        function swap2(arr, i3, j2) {
+        function swap3(arr, i3, j2) {
           var tmp = arr[i3];
           arr[i3] = arr[j2];
           arr[j2] = tmp;
         }
-        function defaultCompare(a2, b2) {
+        function defaultCompare2(a2, b2) {
           return a2 < b2 ? -1 : a2 > b2 ? 1 : 0;
         }
-        return quickselect2;
+        return quickselect3;
       });
     }
   });
       "use strict";
       module2.exports = rbush;
       module2.exports.default = rbush;
-      var quickselect2 = require_quickselect();
+      var quickselect3 = require_quickselect();
       function rbush(maxEntries, format2) {
-        if (!(this instanceof rbush))
-          return new rbush(maxEntries, format2);
+        if (!(this instanceof rbush)) return new rbush(maxEntries, format2);
         this._maxEntries = Math.max(4, maxEntries || 9);
         this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
         if (format2) {
         },
         search: function(bbox2) {
           var node = this.data, result = [], toBBox = this.toBBox;
-          if (!intersects(bbox2, node))
-            return result;
+          if (!intersects2(bbox2, node)) return result;
           var nodesToSearch = [], i3, len, child, childBBox;
           while (node) {
             for (i3 = 0, len = node.children.length; i3 < len; i3++) {
               child = node.children[i3];
               childBBox = node.leaf ? toBBox(child) : child;
-              if (intersects(bbox2, childBBox)) {
-                if (node.leaf)
-                  result.push(child);
-                else if (contains(bbox2, childBBox))
-                  this._all(child, result);
-                else
-                  nodesToSearch.push(child);
+              if (intersects2(bbox2, childBBox)) {
+                if (node.leaf) result.push(child);
+                else if (contains2(bbox2, childBBox)) this._all(child, result);
+                else nodesToSearch.push(child);
               }
             }
             node = nodesToSearch.pop();
         },
         collides: function(bbox2) {
           var node = this.data, toBBox = this.toBBox;
-          if (!intersects(bbox2, node))
-            return false;
+          if (!intersects2(bbox2, node)) return false;
           var nodesToSearch = [], i3, len, child, childBBox;
           while (node) {
             for (i3 = 0, len = node.children.length; i3 < len; i3++) {
               child = node.children[i3];
               childBBox = node.leaf ? toBBox(child) : child;
-              if (intersects(bbox2, childBBox)) {
-                if (node.leaf || contains(bbox2, childBBox))
-                  return true;
+              if (intersects2(bbox2, childBBox)) {
+                if (node.leaf || contains2(bbox2, childBBox)) return true;
                 nodesToSearch.push(child);
               }
             }
           return false;
         },
         load: function(data) {
-          if (!(data && data.length))
-            return this;
+          if (!(data && data.length)) return this;
           if (data.length < this._minEntries) {
             for (var i3 = 0, len = data.length; i3 < len; i3++) {
               this.insert(data[i3]);
           return this;
         },
         insert: function(item) {
-          if (item)
-            this._insert(item, this.data.height - 1);
+          if (item) this._insert(item, this.data.height - 1);
           return this;
         },
         clear: function() {
-          this.data = createNode([]);
+          this.data = createNode2([]);
           return this;
         },
         remove: function(item, equalsFn) {
-          if (!item)
-            return this;
+          if (!item) return this;
           var node = this.data, bbox2 = this.toBBox(item), path = [], indexes = [], i3, parent, index, goingUp;
           while (node || path.length) {
             if (!node) {
               goingUp = true;
             }
             if (node.leaf) {
-              index = findItem(item, node.children, equalsFn);
+              index = findItem2(item, node.children, equalsFn);
               if (index !== -1) {
                 node.children.splice(index, 1);
                 path.push(node);
                 return this;
               }
             }
-            if (!goingUp && !node.leaf && contains(node, bbox2)) {
+            if (!goingUp && !node.leaf && contains2(node, bbox2)) {
               path.push(node);
               indexes.push(i3);
               i3 = 0;
               i3++;
               node = parent.children[i3];
               goingUp = false;
-            } else
-              node = null;
+            } else node = null;
           }
           return this;
         },
         toBBox: function(item) {
           return item;
         },
-        compareMinX: compareNodeMinX,
-        compareMinY: compareNodeMinY,
+        compareMinX: compareNodeMinX2,
+        compareMinY: compareNodeMinY2,
         toJSON: function() {
           return this.data;
         },
         _all: function(node, result) {
           var nodesToSearch = [];
           while (node) {
-            if (node.leaf)
-              result.push.apply(result, node.children);
-            else
-              nodesToSearch.push.apply(nodesToSearch, node.children);
+            if (node.leaf) result.push.apply(result, node.children);
+            else nodesToSearch.push.apply(nodesToSearch, node.children);
             node = nodesToSearch.pop();
           }
           return result;
         _build: function(items, left, right, height) {
           var N2 = right - left + 1, M2 = this._maxEntries, node;
           if (N2 <= M2) {
-            node = createNode(items.slice(left, right + 1));
-            calcBBox(node, this.toBBox);
+            node = createNode2(items.slice(left, right + 1));
+            calcBBox2(node, this.toBBox);
             return node;
           }
           if (!height) {
             height = Math.ceil(Math.log(N2) / Math.log(M2));
             M2 = Math.ceil(N2 / Math.pow(M2, height - 1));
           }
-          node = createNode([]);
+          node = createNode2([]);
           node.leaf = false;
           node.height = height;
           var N22 = Math.ceil(N2 / M2), N1 = N22 * Math.ceil(Math.sqrt(M2)), i3, j2, right2, right3;
-          multiSelect(items, left, right, N1, this.compareMinX);
+          multiSelect2(items, left, right, N1, this.compareMinX);
           for (i3 = left; i3 <= right; i3 += N1) {
             right2 = Math.min(i3 + N1 - 1, right);
-            multiSelect(items, i3, right2, N22, this.compareMinY);
+            multiSelect2(items, i3, right2, N22, this.compareMinY);
             for (j2 = i3; j2 <= right2; j2 += N22) {
               right3 = Math.min(j2 + N22 - 1, right2);
               node.children.push(this._build(items, j2, right3, height - 1));
             }
           }
-          calcBBox(node, this.toBBox);
+          calcBBox2(node, this.toBBox);
           return node;
         },
         _chooseSubtree: function(bbox2, node, level, path) {
           var i3, len, child, targetNode, area, enlargement, minArea, minEnlargement;
           while (true) {
             path.push(node);
-            if (node.leaf || path.length - 1 === level)
-              break;
+            if (node.leaf || path.length - 1 === level) break;
             minArea = minEnlargement = Infinity;
             for (i3 = 0, len = node.children.length; i3 < len; i3++) {
               child = node.children[i3];
-              area = bboxArea(child);
-              enlargement = enlargedArea(bbox2, child) - area;
+              area = bboxArea2(child);
+              enlargement = enlargedArea2(bbox2, child) - area;
               if (enlargement < minEnlargement) {
                 minEnlargement = enlargement;
                 minArea = area < minArea ? area : minArea;
           var toBBox = this.toBBox, bbox2 = isNode ? item : toBBox(item), insertPath = [];
           var node = this._chooseSubtree(bbox2, this.data, level, insertPath);
           node.children.push(item);
-          extend2(node, bbox2);
+          extend3(node, bbox2);
           while (level >= 0) {
             if (insertPath[level].children.length > this._maxEntries) {
               this._split(insertPath, level);
               level--;
-            } else
-              break;
+            } else break;
           }
           this._adjustParentBBoxes(bbox2, insertPath, level);
         },
           var node = insertPath[level], M2 = node.children.length, m2 = this._minEntries;
           this._chooseSplitAxis(node, m2, M2);
           var splitIndex = this._chooseSplitIndex(node, m2, M2);
-          var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
+          var newNode = createNode2(node.children.splice(splitIndex, node.children.length - splitIndex));
           newNode.height = node.height;
           newNode.leaf = node.leaf;
-          calcBBox(node, this.toBBox);
-          calcBBox(newNode, this.toBBox);
-          if (level)
-            insertPath[level - 1].children.push(newNode);
-          else
-            this._splitRoot(node, newNode);
+          calcBBox2(node, this.toBBox);
+          calcBBox2(newNode, this.toBBox);
+          if (level) insertPath[level - 1].children.push(newNode);
+          else this._splitRoot(node, newNode);
         },
         _splitRoot: function(node, newNode) {
-          this.data = createNode([node, newNode]);
+          this.data = createNode2([node, newNode]);
           this.data.height = node.height + 1;
           this.data.leaf = false;
-          calcBBox(this.data, this.toBBox);
+          calcBBox2(this.data, this.toBBox);
         },
         _chooseSplitIndex: function(node, m2, M2) {
           var i3, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
           minOverlap = minArea = Infinity;
           for (i3 = m2; i3 <= M2 - m2; i3++) {
-            bbox1 = distBBox(node, 0, i3, this.toBBox);
-            bbox2 = distBBox(node, i3, M2, this.toBBox);
-            overlap = intersectionArea(bbox1, bbox2);
-            area = bboxArea(bbox1) + bboxArea(bbox2);
+            bbox1 = distBBox2(node, 0, i3, this.toBBox);
+            bbox2 = distBBox2(node, i3, M2, this.toBBox);
+            overlap = intersectionArea2(bbox1, bbox2);
+            area = bboxArea2(bbox1) + bboxArea2(bbox2);
             if (overlap < minOverlap) {
               minOverlap = overlap;
               index = i3;
         },
         // sorts node children by the best axis for split
         _chooseSplitAxis: function(node, m2, M2) {
-          var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX, compareMinY = node.leaf ? this.compareMinY : compareNodeMinY, xMargin = this._allDistMargin(node, m2, M2, compareMinX), yMargin = this._allDistMargin(node, m2, M2, compareMinY);
-          if (xMargin < yMargin)
-            node.children.sort(compareMinX);
+          var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX2, compareMinY = node.leaf ? this.compareMinY : compareNodeMinY2, xMargin = this._allDistMargin(node, m2, M2, compareMinX), yMargin = this._allDistMargin(node, m2, M2, compareMinY);
+          if (xMargin < yMargin) node.children.sort(compareMinX);
         },
         // total margin of all possible split distributions where each node is at least m full
         _allDistMargin: function(node, m2, M2, compare2) {
           node.children.sort(compare2);
-          var toBBox = this.toBBox, leftBBox = distBBox(node, 0, m2, toBBox), rightBBox = distBBox(node, M2 - m2, M2, toBBox), margin = bboxMargin(leftBBox) + bboxMargin(rightBBox), i3, child;
+          var toBBox = this.toBBox, leftBBox = distBBox2(node, 0, m2, toBBox), rightBBox = distBBox2(node, M2 - m2, M2, toBBox), margin = bboxMargin2(leftBBox) + bboxMargin2(rightBBox), i3, child;
           for (i3 = m2; i3 < M2 - m2; i3++) {
             child = node.children[i3];
-            extend2(leftBBox, node.leaf ? toBBox(child) : child);
-            margin += bboxMargin(leftBBox);
+            extend3(leftBBox, node.leaf ? toBBox(child) : child);
+            margin += bboxMargin2(leftBBox);
           }
           for (i3 = M2 - m2 - 1; i3 >= m2; i3--) {
             child = node.children[i3];
-            extend2(rightBBox, node.leaf ? toBBox(child) : child);
-            margin += bboxMargin(rightBBox);
+            extend3(rightBBox, node.leaf ? toBBox(child) : child);
+            margin += bboxMargin2(rightBBox);
           }
           return margin;
         },
         _adjustParentBBoxes: function(bbox2, path, level) {
           for (var i3 = level; i3 >= 0; i3--) {
-            extend2(path[i3], bbox2);
+            extend3(path[i3], bbox2);
           }
         },
         _condense: function(path) {
               if (i3 > 0) {
                 siblings = path[i3 - 1].children;
                 siblings.splice(siblings.indexOf(path[i3]), 1);
-              } else
-                this.clear();
-            } else
-              calcBBox(path[i3], this.toBBox);
+              } else this.clear();
+            } else calcBBox2(path[i3], this.toBBox);
           }
         },
         _initFormat: function(format2) {
           );
         }
       };
-      function findItem(item, items, equalsFn) {
-        if (!equalsFn)
-          return items.indexOf(item);
+      function findItem2(item, items, equalsFn) {
+        if (!equalsFn) return items.indexOf(item);
         for (var i3 = 0; i3 < items.length; i3++) {
-          if (equalsFn(item, items[i3]))
-            return i3;
+          if (equalsFn(item, items[i3])) return i3;
         }
         return -1;
       }
-      function calcBBox(node, toBBox) {
-        distBBox(node, 0, node.children.length, toBBox, node);
+      function calcBBox2(node, toBBox) {
+        distBBox2(node, 0, node.children.length, toBBox, node);
       }
-      function distBBox(node, k2, p2, toBBox, destNode) {
-        if (!destNode)
-          destNode = createNode(null);
+      function distBBox2(node, k2, p2, toBBox, destNode) {
+        if (!destNode) destNode = createNode2(null);
         destNode.minX = Infinity;
         destNode.minY = Infinity;
         destNode.maxX = -Infinity;
         destNode.maxY = -Infinity;
         for (var i3 = k2, child; i3 < p2; i3++) {
           child = node.children[i3];
-          extend2(destNode, node.leaf ? toBBox(child) : child);
+          extend3(destNode, node.leaf ? toBBox(child) : child);
         }
         return destNode;
       }
-      function extend2(a2, b2) {
+      function extend3(a2, b2) {
         a2.minX = Math.min(a2.minX, b2.minX);
         a2.minY = Math.min(a2.minY, b2.minY);
         a2.maxX = Math.max(a2.maxX, b2.maxX);
         a2.maxY = Math.max(a2.maxY, b2.maxY);
         return a2;
       }
-      function compareNodeMinX(a2, b2) {
+      function compareNodeMinX2(a2, b2) {
         return a2.minX - b2.minX;
       }
-      function compareNodeMinY(a2, b2) {
+      function compareNodeMinY2(a2, b2) {
         return a2.minY - b2.minY;
       }
-      function bboxArea(a2) {
+      function bboxArea2(a2) {
         return (a2.maxX - a2.minX) * (a2.maxY - a2.minY);
       }
-      function bboxMargin(a2) {
+      function bboxMargin2(a2) {
         return a2.maxX - a2.minX + (a2.maxY - a2.minY);
       }
-      function enlargedArea(a2, b2) {
+      function enlargedArea2(a2, b2) {
         return (Math.max(b2.maxX, a2.maxX) - Math.min(b2.minX, a2.minX)) * (Math.max(b2.maxY, a2.maxY) - Math.min(b2.minY, a2.minY));
       }
-      function intersectionArea(a2, b2) {
+      function intersectionArea2(a2, b2) {
         var minX = Math.max(a2.minX, b2.minX), minY = Math.max(a2.minY, b2.minY), maxX = Math.min(a2.maxX, b2.maxX), maxY = Math.min(a2.maxY, b2.maxY);
         return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
       }
-      function contains(a2, b2) {
+      function contains2(a2, b2) {
         return a2.minX <= b2.minX && a2.minY <= b2.minY && b2.maxX <= a2.maxX && b2.maxY <= a2.maxY;
       }
-      function intersects(a2, b2) {
+      function intersects2(a2, b2) {
         return b2.minX <= a2.maxX && b2.minY <= a2.maxY && b2.maxX >= a2.minX && b2.maxY >= a2.minY;
       }
-      function createNode(children2) {
+      function createNode2(children2) {
         return {
           children: children2,
           height: 1,
           maxY: -Infinity
         };
       }
-      function multiSelect(arr, left, right, n3, compare2) {
+      function multiSelect2(arr, left, right, n3, compare2) {
         var stack = [left, right], mid;
         while (stack.length) {
           right = stack.pop();
           left = stack.pop();
-          if (right - left <= n3)
-            continue;
+          if (right - left <= n3) continue;
           mid = left + Math.ceil((right - left) / n3 / 2) * n3;
-          quickselect2(arr, mid, left, right, compare2);
+          quickselect3(arr, mid, left, right, compare2);
           stack.push(left, mid, mid, right);
         }
       }
       lineclip2.polygon = polygonclip2;
       function lineclip2(points, bbox2, result) {
         var len = points.length, codeA = bitCode2(points[0], bbox2), part = [], i3, a2, b2, codeB, lastCode;
-        if (!result)
-          result = [];
+        if (!result) result = [];
         for (i3 = 1; i3 < len; i3++) {
           a2 = points[i3 - 1];
           b2 = points[i3];
           }
           codeA = lastCode;
         }
-        if (part.length)
-          result.push(part);
+        if (part.length) result.push(part);
         return result;
       }
       function polygonclip2(points, bbox2) {
           for (i3 = 0; i3 < points.length; i3++) {
             p2 = points[i3];
             inside = !(bitCode2(p2, bbox2) & edge);
-            if (inside !== prevInside)
-              result.push(intersect2(prev, p2, edge, bbox2));
-            if (inside)
-              result.push(p2);
+            if (inside !== prevInside) result.push(intersect2(prev, p2, edge, bbox2));
+            if (inside) result.push(p2);
             prev = p2;
             prevInside = inside;
           }
           points = result;
-          if (!points.length)
-            break;
+          if (!points.length) break;
         }
         return result;
       }
       }
       function bitCode2(p2, bbox2) {
         var code = 0;
-        if (p2[0] < bbox2[0])
-          code |= 1;
-        else if (p2[0] > bbox2[2])
-          code |= 2;
-        if (p2[1] < bbox2[1])
-          code |= 4;
-        else if (p2[1] > bbox2[3])
-          code |= 8;
+        if (p2[0] < bbox2[0]) code |= 1;
+        else if (p2[0] > bbox2[2]) code |= 2;
+        if (p2[1] < bbox2[1]) code |= 4;
+        else if (p2[1] > bbox2[3]) code |= 8;
         return code;
       }
     }
         var bboxes = [];
         for (var i3 = 0; i3 < data.features.length; i3++) {
           var feature3 = data.features[i3];
-          if (!feature3.geometry)
-            continue;
+          if (!feature3.geometry) continue;
           var coords = feature3.geometry.coordinates;
           if (feature3.geometry.type === "Polygon") {
             bboxes.push(treeItem(coords, feature3.properties));
           (bbox2[0] + bbox2[2]) / 2,
           (bbox2[1] + bbox2[3]) / 2
         ];
-        if (insidePolygon(polygon2, bboxCenter))
-          return true;
+        if (insidePolygon(polygon2, bboxCenter)) return true;
         for (var i3 = 0; i3 < polygon2.length; i3++) {
-          if (lineclip2(polygon2[i3], bbox2).length > 0)
-            return true;
+          if (lineclip2(polygon2[i3], bbox2).length > 0) return true;
         }
         return false;
       }
         for (var i3 = 0, len = rings.length; i3 < len; i3++) {
           var ring = rings[i3];
           for (var j2 = 0, len2 = ring.length, k2 = len2 - 1; j2 < len2; k2 = j2++) {
-            if (rayIntersect(p2, ring[j2], ring[k2]))
-              inside = !inside;
+            if (rayIntersect(p2, ring[j2], ring[k2])) inside = !inside;
           }
         }
         return inside;
     "node_modules/geojson-precision/index.js"(exports2, module2) {
       (function() {
         function parse(t2, coordinatePrecision, extrasPrecision) {
-          function point2(p2) {
+          function point(p2) {
             return p2.map(function(e3, index) {
               if (index < 2) {
                 return 1 * e3.toFixed(coordinatePrecision);
             });
           }
           function multi(l2) {
-            return l2.map(point2);
+            return l2.map(point);
           }
           function poly(p2) {
             return p2.map(multi);
             }
             switch (obj.type) {
               case "Point":
-                obj.coordinates = point2(obj.coordinates);
+                obj.coordinates = point(obj.coordinates);
                 return obj;
               case "LineString":
               case "MultiPoint":
   // node_modules/@aitodotai/json-stringify-pretty-compact/index.js
   var require_json_stringify_pretty_compact = __commonJS({
     "node_modules/@aitodotai/json-stringify-pretty-compact/index.js"(exports2, module2) {
-      function isObject3(obj) {
+      function isObject2(obj) {
         return typeof obj === "object" && obj !== null;
       }
       function forEach(obj, cb) {
         if (Array.isArray(obj)) {
           obj.forEach(cb);
-        } else if (isObject3(obj)) {
+        } else if (isObject2(obj)) {
           Object.keys(obj).forEach(function(key) {
             var val = obj[key];
             cb(val, key);
       }
       function getTreeDepth(obj) {
         var depth = 0;
-        if (Array.isArray(obj) || isObject3(obj)) {
+        if (Array.isArray(obj) || isObject2(obj)) {
           forEach(obj, function(val) {
-            if (Array.isArray(val) || isObject3(val)) {
+            if (Array.isArray(val) || isObject2(val)) {
               var tmpDepth = getTreeDepth(val);
               if (tmpDepth > depth) {
                 depth = tmpDepth;
               return prettified;
             }
           }
-          if (isObject3(obj2)) {
+          if (isObject2(obj2)) {
             var nextIndent = currentIndent + indent;
             var items = [];
             var delimiters;
             function object() {
             }
             return function(proto) {
-              if (!isObject3(proto)) {
+              if (!isObject2(proto)) {
                 return {};
               }
               if (objectCreate) {
             if (result2 !== undefined2) {
               return result2;
             }
-            if (!isObject3(value)) {
+            if (!isObject2(value)) {
               return value;
             }
             var isArr = isArray2(value);
             return true;
           }
           function baseIsNative2(value) {
-            if (!isObject3(value) || isMasked2(value)) {
+            if (!isObject2(value) || isMasked2(value)) {
               return false;
             }
             var pattern = isFunction2(value) ? reIsNative2 : reIsHostCtor2;
             return result2;
           }
           function baseKeysIn(object) {
-            if (!isObject3(object)) {
+            if (!isObject2(object)) {
               return nativeKeysIn(object);
             }
             var isProto = isPrototype2(object), result2 = [];
             }
             baseFor(source, function(srcValue, key) {
               stack || (stack = new Stack2());
-              if (isObject3(srcValue)) {
+              if (isObject2(srcValue)) {
                 baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
               } else {
                 var newValue = customizer ? customizer(safeGet(object, key), srcValue, key + "", object, source, stack) : undefined2;
                 newValue = objValue;
                 if (isArguments2(objValue)) {
                   newValue = toPlainObject(objValue);
-                } else if (!isObject3(objValue) || isFunction2(objValue)) {
+                } else if (!isObject2(objValue) || isFunction2(objValue)) {
                   newValue = initCloneObject(srcValue);
                 }
               } else {
             return shuffleSelf(array2, baseClamp(n3, 0, array2.length));
           }
           function baseSet(object, path, value, customizer) {
-            if (!isObject3(object)) {
+            if (!isObject2(object)) {
               return object;
             }
             path = castPath(path, object);
                 var objValue = nested[key];
                 newValue = customizer ? customizer(objValue, key, nested) : undefined2;
                 if (newValue === undefined2) {
-                  newValue = isObject3(objValue) ? objValue : isIndex2(path[index + 1]) ? [] : {};
+                  newValue = isObject2(objValue) ? objValue : isIndex2(path[index + 1]) ? [] : {};
                 }
               }
               assignValue(nested, key, newValue);
                   return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
               }
               var thisBinding = baseCreate(Ctor.prototype), result2 = Ctor.apply(thisBinding, args);
-              return isObject3(result2) ? result2 : thisBinding;
+              return isObject2(result2) ? result2 : thisBinding;
             };
           }
           function createCurry(func, bitmask, arity) {
             return objValue;
           }
           function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
-            if (isObject3(objValue) && isObject3(srcValue)) {
+            if (isObject2(objValue) && isObject2(srcValue)) {
               stack.set(srcValue, objValue);
               baseMerge(objValue, srcValue, undefined2, customDefaultsMerge, stack);
               stack["delete"](srcValue);
             return !!length2 && (type2 == "number" || type2 != "symbol" && reIsUint2.test(value)) && (value > -1 && value % 1 == 0 && value < length2);
           }
           function isIterateeCall(value, index, object) {
-            if (!isObject3(object)) {
+            if (!isObject2(object)) {
               return false;
             }
             var type2 = typeof index;
             return value === proto;
           }
           function isStrictComparable(value) {
-            return value === value && !isObject3(value);
+            return value === value && !isObject2(value);
           }
           function matchesStrictComparable(key, srcValue) {
             return function(object) {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             }
             wait = toNumber3(wait) || 0;
-            if (isObject3(options2)) {
+            if (isObject2(options2)) {
               leading = !!options2.leading;
               maxing = "maxWait" in options2;
               maxWait = maxing ? nativeMax2(toNumber3(options2.maxWait) || 0, wait) : maxWait;
             if (typeof func != "function") {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             }
-            if (isObject3(options2)) {
+            if (isObject2(options2)) {
               leading = "leading" in options2 ? !!options2.leading : leading;
               trailing = "trailing" in options2 ? !!options2.trailing : trailing;
             }
             return typeof value == "number" && nativeIsFinite(value);
           }
           function isFunction2(value) {
-            if (!isObject3(value)) {
+            if (!isObject2(value)) {
               return false;
             }
             var tag2 = baseGetTag2(value);
           function isLength2(value) {
             return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER4;
           }
-          function isObject3(value) {
+          function isObject2(value) {
             var type2 = typeof value;
             return value != null && (type2 == "object" || type2 == "function");
           }
             return baseIsMatch(object, source, getMatchData(source), customizer);
           }
           function isNaN2(value) {
-            return isNumber3(value) && value != +value;
+            return isNumber2(value) && value != +value;
           }
           function isNative(value) {
             if (isMaskable(value)) {
           function isNil(value) {
             return value == null;
           }
-          function isNumber3(value) {
+          function isNumber2(value) {
             return typeof value == "number" || isObjectLike2(value) && baseGetTag2(value) == numberTag4;
           }
           function isPlainObject(value) {
             if (isSymbol2(value)) {
               return NAN2;
             }
-            if (isObject3(value)) {
+            if (isObject2(value)) {
               var other = typeof value.valueOf == "function" ? value.valueOf() : value;
-              value = isObject3(other) ? other + "" : other;
+              value = isObject2(other) ? other + "" : other;
             }
             if (typeof value != "string") {
               return value === 0 ? value : +value;
               var Ctor = object && object.constructor;
               if (isArrLike) {
                 accumulator = isArr ? new Ctor() : [];
-              } else if (isObject3(object)) {
+              } else if (isObject2(object)) {
                 accumulator = isFunction2(Ctor) ? baseCreate(getPrototype(object)) : {};
               } else {
                 accumulator = {};
           }
           function truncate(string, options2) {
             var length2 = DEFAULT_TRUNC_LENGTH, omission = DEFAULT_TRUNC_OMISSION;
-            if (isObject3(options2)) {
+            if (isObject2(options2)) {
               var separator = "separator" in options2 ? options2.separator : separator;
               length2 = "length" in options2 ? toInteger(options2.length) : length2;
               omission = "omission" in options2 ? baseToString2(options2.omission) : omission;
             }
             return result2 + omission;
           }
-          function unescape3(string) {
+          function unescape2(string) {
             string = toString2(string);
             return string && reHasEscapedHtml2.test(string) ? string.replace(reEscapedHtml2, unescapeHtmlChar2) : string;
           }
           });
           function mixin(object, source, options2) {
             var props = keys2(source), methodNames = baseFunctions(source, props);
-            if (options2 == null && !(isObject3(source) && (methodNames.length || !props.length))) {
+            if (options2 == null && !(isObject2(source) && (methodNames.length || !props.length))) {
               options2 = source;
               source = object;
               object = this;
               methodNames = baseFunctions(source, keys2(source));
             }
-            var chain2 = !(isObject3(options2) && "chain" in options2) || !!options2.chain, isFunc = isFunction2(object);
+            var chain2 = !(isObject2(options2) && "chain" in options2) || !!options2.chain, isFunc = isFunction2(object);
             arrayEach(methodNames, function(methodName) {
               var func = source[methodName];
               object[methodName] = func;
           lodash.isNative = isNative;
           lodash.isNil = isNil;
           lodash.isNull = isNull;
-          lodash.isNumber = isNumber3;
-          lodash.isObject = isObject3;
+          lodash.isNumber = isNumber2;
+          lodash.isObject = isObject2;
           lodash.isObjectLike = isObjectLike2;
           lodash.isPlainObject = isPlainObject;
           lodash.isRegExp = isRegExp;
           lodash.trimEnd = trimEnd;
           lodash.trimStart = trimStart;
           lodash.truncate = truncate;
-          lodash.unescape = unescape3;
+          lodash.unescape = unescape2;
           lodash.uniqueId = uniqueId;
           lodash.upperCase = upperCase;
           lodash.upperFirst = upperFirst;
     "node_modules/fast-deep-equal/index.js"(exports2, module2) {
       "use strict";
       module2.exports = function equal(a2, b2) {
-        if (a2 === b2)
-          return true;
+        if (a2 === b2) return true;
         if (a2 && b2 && typeof a2 == "object" && typeof b2 == "object") {
-          if (a2.constructor !== b2.constructor)
-            return false;
+          if (a2.constructor !== b2.constructor) return false;
           var length2, i3, keys2;
           if (Array.isArray(a2)) {
             length2 = a2.length;
-            if (length2 != b2.length)
-              return false;
+            if (length2 != b2.length) return false;
             for (i3 = length2; i3-- !== 0; )
-              if (!equal(a2[i3], b2[i3]))
-                return false;
+              if (!equal(a2[i3], b2[i3])) return false;
             return true;
           }
-          if (a2.constructor === RegExp)
-            return a2.source === b2.source && a2.flags === b2.flags;
-          if (a2.valueOf !== Object.prototype.valueOf)
-            return a2.valueOf() === b2.valueOf();
-          if (a2.toString !== Object.prototype.toString)
-            return a2.toString() === b2.toString();
+          if (a2.constructor === RegExp) return a2.source === b2.source && a2.flags === b2.flags;
+          if (a2.valueOf !== Object.prototype.valueOf) return a2.valueOf() === b2.valueOf();
+          if (a2.toString !== Object.prototype.toString) return a2.toString() === b2.toString();
           keys2 = Object.keys(a2);
           length2 = keys2.length;
-          if (length2 !== Object.keys(b2).length)
-            return false;
+          if (length2 !== Object.keys(b2).length) return false;
           for (i3 = length2; i3-- !== 0; )
-            if (!Object.prototype.hasOwnProperty.call(b2, keys2[i3]))
-              return false;
+            if (!Object.prototype.hasOwnProperty.call(b2, keys2[i3])) return false;
           for (i3 = length2; i3-- !== 0; ) {
             var key = keys2[i3];
-            if (!equal(a2[key], b2[key]))
-              return false;
+            if (!equal(a2[key], b2[key])) return false;
           }
           return true;
         }
     }
   });
 
-  // node_modules/rbush/rbush.min.js
-  var require_rbush_min = __commonJS({
-    "node_modules/rbush/rbush.min.js"(exports2, module2) {
-      !function(t2, i3) {
-        "object" == typeof exports2 && "undefined" != typeof module2 ? module2.exports = i3() : "function" == typeof define && define.amd ? define(i3) : (t2 = t2 || self).RBush = i3();
-      }(exports2, function() {
-        "use strict";
-        function t2(t3, r3, e4, a3, h3) {
-          !function t4(n4, r4, e6, a4, h4) {
-            for (; a4 > e6; ) {
-              if (a4 - e6 > 600) {
-                var o3 = a4 - e6 + 1, s3 = r4 - e6 + 1, l3 = Math.log(o3), f3 = 0.5 * Math.exp(2 * l3 / 3), u3 = 0.5 * Math.sqrt(l3 * f3 * (o3 - f3) / o3) * (s3 - o3 / 2 < 0 ? -1 : 1), m3 = Math.max(e6, Math.floor(r4 - s3 * f3 / o3 + u3)), c3 = Math.min(a4, Math.floor(r4 + (o3 - s3) * f3 / o3 + u3));
-                t4(n4, r4, m3, c3, h4);
-              }
-              var p3 = n4[r4], d4 = e6, x2 = a4;
-              for (i3(n4, e6, r4), h4(n4[a4], p3) > 0 && i3(n4, e6, a4); d4 < x2; ) {
-                for (i3(n4, d4, x2), d4++, x2--; h4(n4[d4], p3) < 0; )
-                  d4++;
-                for (; h4(n4[x2], p3) > 0; )
-                  x2--;
-              }
-              0 === h4(n4[e6], p3) ? i3(n4, e6, x2) : i3(n4, ++x2, a4), x2 <= r4 && (e6 = x2 + 1), r4 <= x2 && (a4 = x2 - 1);
-            }
-          }(t3, r3, e4 || 0, a3 || t3.length - 1, h3 || n3);
-        }
-        function i3(t3, i4, n4) {
-          var r3 = t3[i4];
-          t3[i4] = t3[n4], t3[n4] = r3;
-        }
-        function n3(t3, i4) {
-          return t3 < i4 ? -1 : t3 > i4 ? 1 : 0;
-        }
-        var r2 = function(t3) {
-          void 0 === t3 && (t3 = 9), this._maxEntries = Math.max(4, t3), this._minEntries = Math.max(2, Math.ceil(0.4 * this._maxEntries)), this.clear();
-        };
-        function e3(t3, i4, n4) {
-          if (!n4)
-            return i4.indexOf(t3);
-          for (var r3 = 0; r3 < i4.length; r3++)
-            if (n4(t3, i4[r3]))
-              return r3;
-          return -1;
-        }
-        function a2(t3, i4) {
-          h2(t3, 0, t3.children.length, i4, t3);
-        }
-        function h2(t3, i4, n4, r3, e4) {
-          e4 || (e4 = p2(null)), e4.minX = 1 / 0, e4.minY = 1 / 0, e4.maxX = -1 / 0, e4.maxY = -1 / 0;
-          for (var a3 = i4; a3 < n4; a3++) {
-            var h3 = t3.children[a3];
-            o2(e4, t3.leaf ? r3(h3) : h3);
-          }
-          return e4;
-        }
-        function o2(t3, i4) {
-          return t3.minX = Math.min(t3.minX, i4.minX), t3.minY = Math.min(t3.minY, i4.minY), t3.maxX = Math.max(t3.maxX, i4.maxX), t3.maxY = Math.max(t3.maxY, i4.maxY), t3;
-        }
-        function s2(t3, i4) {
-          return t3.minX - i4.minX;
-        }
-        function l2(t3, i4) {
-          return t3.minY - i4.minY;
-        }
-        function f2(t3) {
-          return (t3.maxX - t3.minX) * (t3.maxY - t3.minY);
-        }
-        function u2(t3) {
-          return t3.maxX - t3.minX + (t3.maxY - t3.minY);
-        }
-        function m2(t3, i4) {
-          return t3.minX <= i4.minX && t3.minY <= i4.minY && i4.maxX <= t3.maxX && i4.maxY <= t3.maxY;
-        }
-        function c2(t3, i4) {
-          return i4.minX <= t3.maxX && i4.minY <= t3.maxY && i4.maxX >= t3.minX && i4.maxY >= t3.minY;
-        }
-        function p2(t3) {
-          return { children: t3, height: 1, leaf: true, minX: 1 / 0, minY: 1 / 0, maxX: -1 / 0, maxY: -1 / 0 };
-        }
-        function d2(i4, n4, r3, e4, a3) {
-          for (var h3 = [n4, r3]; h3.length; )
-            if (!((r3 = h3.pop()) - (n4 = h3.pop()) <= e4)) {
-              var o3 = n4 + Math.ceil((r3 - n4) / e4 / 2) * e4;
-              t2(i4, o3, n4, r3, a3), h3.push(n4, o3, o3, r3);
-            }
-        }
-        return r2.prototype.all = function() {
-          return this._all(this.data, []);
-        }, r2.prototype.search = function(t3) {
-          var i4 = this.data, n4 = [];
-          if (!c2(t3, i4))
-            return n4;
-          for (var r3 = this.toBBox, e4 = []; i4; ) {
-            for (var a3 = 0; a3 < i4.children.length; a3++) {
-              var h3 = i4.children[a3], o3 = i4.leaf ? r3(h3) : h3;
-              c2(t3, o3) && (i4.leaf ? n4.push(h3) : m2(t3, o3) ? this._all(h3, n4) : e4.push(h3));
-            }
-            i4 = e4.pop();
-          }
-          return n4;
-        }, r2.prototype.collides = function(t3) {
-          var i4 = this.data;
-          if (!c2(t3, i4))
-            return false;
-          for (var n4 = []; i4; ) {
-            for (var r3 = 0; r3 < i4.children.length; r3++) {
-              var e4 = i4.children[r3], a3 = i4.leaf ? this.toBBox(e4) : e4;
-              if (c2(t3, a3)) {
-                if (i4.leaf || m2(t3, a3))
-                  return true;
-                n4.push(e4);
-              }
-            }
-            i4 = n4.pop();
-          }
-          return false;
-        }, r2.prototype.load = function(t3) {
-          if (!t3 || !t3.length)
-            return this;
-          if (t3.length < this._minEntries) {
-            for (var i4 = 0; i4 < t3.length; i4++)
-              this.insert(t3[i4]);
-            return this;
-          }
-          var n4 = this._build(t3.slice(), 0, t3.length - 1, 0);
-          if (this.data.children.length)
-            if (this.data.height === n4.height)
-              this._splitRoot(this.data, n4);
-            else {
-              if (this.data.height < n4.height) {
-                var r3 = this.data;
-                this.data = n4, n4 = r3;
-              }
-              this._insert(n4, this.data.height - n4.height - 1, true);
-            }
-          else
-            this.data = n4;
-          return this;
-        }, r2.prototype.insert = function(t3) {
-          return t3 && this._insert(t3, this.data.height - 1), this;
-        }, r2.prototype.clear = function() {
-          return this.data = p2([]), this;
-        }, r2.prototype.remove = function(t3, i4) {
-          if (!t3)
-            return this;
-          for (var n4, r3, a3, h3 = this.data, o3 = this.toBBox(t3), s3 = [], l3 = []; h3 || s3.length; ) {
-            if (h3 || (h3 = s3.pop(), r3 = s3[s3.length - 1], n4 = l3.pop(), a3 = true), h3.leaf) {
-              var f3 = e3(t3, h3.children, i4);
-              if (-1 !== f3)
-                return h3.children.splice(f3, 1), s3.push(h3), this._condense(s3), this;
-            }
-            a3 || h3.leaf || !m2(h3, o3) ? r3 ? (n4++, h3 = r3.children[n4], a3 = false) : h3 = null : (s3.push(h3), l3.push(n4), n4 = 0, r3 = h3, h3 = h3.children[0]);
-          }
-          return this;
-        }, r2.prototype.toBBox = function(t3) {
-          return t3;
-        }, r2.prototype.compareMinX = function(t3, i4) {
-          return t3.minX - i4.minX;
-        }, r2.prototype.compareMinY = function(t3, i4) {
-          return t3.minY - i4.minY;
-        }, r2.prototype.toJSON = function() {
-          return this.data;
-        }, r2.prototype.fromJSON = function(t3) {
-          return this.data = t3, this;
-        }, r2.prototype._all = function(t3, i4) {
-          for (var n4 = []; t3; )
-            t3.leaf ? i4.push.apply(i4, t3.children) : n4.push.apply(n4, t3.children), t3 = n4.pop();
-          return i4;
-        }, r2.prototype._build = function(t3, i4, n4, r3) {
-          var e4, h3 = n4 - i4 + 1, o3 = this._maxEntries;
-          if (h3 <= o3)
-            return a2(e4 = p2(t3.slice(i4, n4 + 1)), this.toBBox), e4;
-          r3 || (r3 = Math.ceil(Math.log(h3) / Math.log(o3)), o3 = Math.ceil(h3 / Math.pow(o3, r3 - 1))), (e4 = p2([])).leaf = false, e4.height = r3;
-          var s3 = Math.ceil(h3 / o3), l3 = s3 * Math.ceil(Math.sqrt(o3));
-          d2(t3, i4, n4, l3, this.compareMinX);
-          for (var f3 = i4; f3 <= n4; f3 += l3) {
-            var u3 = Math.min(f3 + l3 - 1, n4);
-            d2(t3, f3, u3, s3, this.compareMinY);
-            for (var m3 = f3; m3 <= u3; m3 += s3) {
-              var c3 = Math.min(m3 + s3 - 1, u3);
-              e4.children.push(this._build(t3, m3, c3, r3 - 1));
-            }
-          }
-          return a2(e4, this.toBBox), e4;
-        }, r2.prototype._chooseSubtree = function(t3, i4, n4, r3) {
-          for (; r3.push(i4), !i4.leaf && r3.length - 1 !== n4; ) {
-            for (var e4 = 1 / 0, a3 = 1 / 0, h3 = void 0, o3 = 0; o3 < i4.children.length; o3++) {
-              var s3 = i4.children[o3], l3 = f2(s3), u3 = (m3 = t3, c3 = s3, (Math.max(c3.maxX, m3.maxX) - Math.min(c3.minX, m3.minX)) * (Math.max(c3.maxY, m3.maxY) - Math.min(c3.minY, m3.minY)) - l3);
-              u3 < a3 ? (a3 = u3, e4 = l3 < e4 ? l3 : e4, h3 = s3) : u3 === a3 && l3 < e4 && (e4 = l3, h3 = s3);
-            }
-            i4 = h3 || i4.children[0];
-          }
-          var m3, c3;
-          return i4;
-        }, r2.prototype._insert = function(t3, i4, n4) {
-          var r3 = n4 ? t3 : this.toBBox(t3), e4 = [], a3 = this._chooseSubtree(r3, this.data, i4, e4);
-          for (a3.children.push(t3), o2(a3, r3); i4 >= 0 && e4[i4].children.length > this._maxEntries; )
-            this._split(e4, i4), i4--;
-          this._adjustParentBBoxes(r3, e4, i4);
-        }, r2.prototype._split = function(t3, i4) {
-          var n4 = t3[i4], r3 = n4.children.length, e4 = this._minEntries;
-          this._chooseSplitAxis(n4, e4, r3);
-          var h3 = this._chooseSplitIndex(n4, e4, r3), o3 = p2(n4.children.splice(h3, n4.children.length - h3));
-          o3.height = n4.height, o3.leaf = n4.leaf, a2(n4, this.toBBox), a2(o3, this.toBBox), i4 ? t3[i4 - 1].children.push(o3) : this._splitRoot(n4, o3);
-        }, r2.prototype._splitRoot = function(t3, i4) {
-          this.data = p2([t3, i4]), this.data.height = t3.height + 1, this.data.leaf = false, a2(this.data, this.toBBox);
-        }, r2.prototype._chooseSplitIndex = function(t3, i4, n4) {
-          for (var r3, e4, a3, o3, s3, l3, u3, m3 = 1 / 0, c3 = 1 / 0, p3 = i4; p3 <= n4 - i4; p3++) {
-            var d4 = h2(t3, 0, p3, this.toBBox), x2 = h2(t3, p3, n4, this.toBBox), v2 = (e4 = d4, a3 = x2, o3 = void 0, s3 = void 0, l3 = void 0, u3 = void 0, o3 = Math.max(e4.minX, a3.minX), s3 = Math.max(e4.minY, a3.minY), l3 = Math.min(e4.maxX, a3.maxX), u3 = Math.min(e4.maxY, a3.maxY), Math.max(0, l3 - o3) * Math.max(0, u3 - s3)), M2 = f2(d4) + f2(x2);
-            v2 < m3 ? (m3 = v2, r3 = p3, c3 = M2 < c3 ? M2 : c3) : v2 === m3 && M2 < c3 && (c3 = M2, r3 = p3);
-          }
-          return r3 || n4 - i4;
-        }, r2.prototype._chooseSplitAxis = function(t3, i4, n4) {
-          var r3 = t3.leaf ? this.compareMinX : s2, e4 = t3.leaf ? this.compareMinY : l2;
-          this._allDistMargin(t3, i4, n4, r3) < this._allDistMargin(t3, i4, n4, e4) && t3.children.sort(r3);
-        }, r2.prototype._allDistMargin = function(t3, i4, n4, r3) {
-          t3.children.sort(r3);
-          for (var e4 = this.toBBox, a3 = h2(t3, 0, i4, e4), s3 = h2(t3, n4 - i4, n4, e4), l3 = u2(a3) + u2(s3), f3 = i4; f3 < n4 - i4; f3++) {
-            var m3 = t3.children[f3];
-            o2(a3, t3.leaf ? e4(m3) : m3), l3 += u2(a3);
-          }
-          for (var c3 = n4 - i4 - 1; c3 >= i4; c3--) {
-            var p3 = t3.children[c3];
-            o2(s3, t3.leaf ? e4(p3) : p3), l3 += u2(s3);
-          }
-          return l3;
-        }, r2.prototype._adjustParentBBoxes = function(t3, i4, n4) {
-          for (var r3 = n4; r3 >= 0; r3--)
-            o2(i4[r3], t3);
-        }, r2.prototype._condense = function(t3) {
-          for (var i4 = t3.length - 1, n4 = void 0; i4 >= 0; i4--)
-            0 === t3[i4].children.length ? i4 > 0 ? (n4 = t3[i4 - 1].children).splice(n4.indexOf(t3[i4]), 1) : this.clear() : a2(t3[i4], this.toBBox);
-        }, r2;
-      });
-    }
-  });
-
-  // node_modules/ieee754/index.js
-  var require_ieee754 = __commonJS({
-    "node_modules/ieee754/index.js"(exports2) {
-      exports2.read = function(buffer, offset, isLE, mLen, nBytes) {
-        var e3, m2;
-        var eLen = nBytes * 8 - mLen - 1;
-        var eMax = (1 << eLen) - 1;
-        var eBias = eMax >> 1;
-        var nBits = -7;
-        var i3 = isLE ? nBytes - 1 : 0;
-        var d2 = isLE ? -1 : 1;
-        var s2 = buffer[offset + i3];
-        i3 += d2;
-        e3 = s2 & (1 << -nBits) - 1;
-        s2 >>= -nBits;
-        nBits += eLen;
-        for (; nBits > 0; e3 = e3 * 256 + buffer[offset + i3], i3 += d2, nBits -= 8) {
-        }
-        m2 = e3 & (1 << -nBits) - 1;
-        e3 >>= -nBits;
-        nBits += mLen;
-        for (; nBits > 0; m2 = m2 * 256 + buffer[offset + i3], i3 += d2, nBits -= 8) {
-        }
-        if (e3 === 0) {
-          e3 = 1 - eBias;
-        } else if (e3 === eMax) {
-          return m2 ? NaN : (s2 ? -1 : 1) * Infinity;
-        } else {
-          m2 = m2 + Math.pow(2, mLen);
-          e3 = e3 - eBias;
-        }
-        return (s2 ? -1 : 1) * m2 * Math.pow(2, e3 - mLen);
-      };
-      exports2.write = function(buffer, value, offset, isLE, mLen, nBytes) {
-        var e3, m2, c2;
-        var eLen = nBytes * 8 - mLen - 1;
-        var eMax = (1 << eLen) - 1;
-        var eBias = eMax >> 1;
-        var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
-        var i3 = isLE ? 0 : nBytes - 1;
-        var d2 = isLE ? 1 : -1;
-        var s2 = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
-        value = Math.abs(value);
-        if (isNaN(value) || value === Infinity) {
-          m2 = isNaN(value) ? 1 : 0;
-          e3 = eMax;
-        } else {
-          e3 = Math.floor(Math.log(value) / Math.LN2);
-          if (value * (c2 = Math.pow(2, -e3)) < 1) {
-            e3--;
-            c2 *= 2;
-          }
-          if (e3 + eBias >= 1) {
-            value += rt / c2;
-          } else {
-            value += rt * Math.pow(2, 1 - eBias);
-          }
-          if (value * c2 >= 2) {
-            e3++;
-            c2 /= 2;
-          }
-          if (e3 + eBias >= eMax) {
-            m2 = 0;
-            e3 = eMax;
-          } else if (e3 + eBias >= 1) {
-            m2 = (value * c2 - 1) * Math.pow(2, mLen);
-            e3 = e3 + eBias;
-          } else {
-            m2 = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
-            e3 = 0;
-          }
-        }
-        for (; mLen >= 8; buffer[offset + i3] = m2 & 255, i3 += d2, m2 /= 256, mLen -= 8) {
-        }
-        e3 = e3 << mLen | m2;
-        eLen += mLen;
-        for (; eLen > 0; buffer[offset + i3] = e3 & 255, i3 += d2, e3 /= 256, eLen -= 8) {
-        }
-        buffer[offset + i3 - d2] |= s2 * 128;
-      };
-    }
-  });
-
-  // node_modules/pbf/index.js
-  var require_pbf = __commonJS({
-    "node_modules/pbf/index.js"(exports2, module2) {
-      "use strict";
-      module2.exports = Pbf;
-      var ieee754 = require_ieee754();
-      function Pbf(buf) {
-        this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
-        this.pos = 0;
-        this.type = 0;
-        this.length = this.buf.length;
-      }
-      Pbf.Varint = 0;
-      Pbf.Fixed64 = 1;
-      Pbf.Bytes = 2;
-      Pbf.Fixed32 = 5;
-      var SHIFT_LEFT_32 = (1 << 16) * (1 << 16);
-      var SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
-      var TEXT_DECODER_MIN_LENGTH = 12;
-      var utf8TextDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder("utf8");
-      Pbf.prototype = {
-        destroy: function() {
-          this.buf = null;
-        },
-        // === READING =================================================================
-        readFields: function(readField, result, end) {
-          end = end || this.length;
-          while (this.pos < end) {
-            var val = this.readVarint(), tag2 = val >> 3, startPos = this.pos;
-            this.type = val & 7;
-            readField(tag2, result, this);
-            if (this.pos === startPos)
-              this.skip(val);
-          }
-          return result;
-        },
-        readMessage: function(readField, result) {
-          return this.readFields(readField, result, this.readVarint() + this.pos);
-        },
-        readFixed32: function() {
-          var val = readUInt32(this.buf, this.pos);
-          this.pos += 4;
-          return val;
-        },
-        readSFixed32: function() {
-          var val = readInt32(this.buf, this.pos);
-          this.pos += 4;
-          return val;
-        },
-        // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
-        readFixed64: function() {
-          var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
-          this.pos += 8;
-          return val;
-        },
-        readSFixed64: function() {
-          var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
-          this.pos += 8;
-          return val;
-        },
-        readFloat: function() {
-          var val = ieee754.read(this.buf, this.pos, true, 23, 4);
-          this.pos += 4;
-          return val;
-        },
-        readDouble: function() {
-          var val = ieee754.read(this.buf, this.pos, true, 52, 8);
-          this.pos += 8;
-          return val;
-        },
-        readVarint: function(isSigned) {
-          var buf = this.buf, val, b2;
-          b2 = buf[this.pos++];
-          val = b2 & 127;
-          if (b2 < 128)
-            return val;
-          b2 = buf[this.pos++];
-          val |= (b2 & 127) << 7;
-          if (b2 < 128)
-            return val;
-          b2 = buf[this.pos++];
-          val |= (b2 & 127) << 14;
-          if (b2 < 128)
-            return val;
-          b2 = buf[this.pos++];
-          val |= (b2 & 127) << 21;
-          if (b2 < 128)
-            return val;
-          b2 = buf[this.pos];
-          val |= (b2 & 15) << 28;
-          return readVarintRemainder(val, isSigned, this);
-        },
-        readVarint64: function() {
-          return this.readVarint(true);
-        },
-        readSVarint: function() {
-          var num = this.readVarint();
-          return num % 2 === 1 ? (num + 1) / -2 : num / 2;
-        },
-        readBoolean: function() {
-          return Boolean(this.readVarint());
-        },
-        readString: function() {
-          var end = this.readVarint() + this.pos;
-          var pos = this.pos;
-          this.pos = end;
-          if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
-            return readUtf8TextDecoder(this.buf, pos, end);
-          }
-          return readUtf8(this.buf, pos, end);
-        },
-        readBytes: function() {
-          var end = this.readVarint() + this.pos, buffer = this.buf.subarray(this.pos, end);
-          this.pos = end;
-          return buffer;
-        },
-        // verbose for performance reasons; doesn't affect gzipped size
-        readPackedVarint: function(arr, isSigned) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readVarint(isSigned));
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readVarint(isSigned));
-          return arr;
-        },
-        readPackedSVarint: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readSVarint());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readSVarint());
-          return arr;
-        },
-        readPackedBoolean: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readBoolean());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readBoolean());
-          return arr;
-        },
-        readPackedFloat: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readFloat());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readFloat());
-          return arr;
-        },
-        readPackedDouble: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readDouble());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readDouble());
-          return arr;
-        },
-        readPackedFixed32: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readFixed32());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readFixed32());
-          return arr;
-        },
-        readPackedSFixed32: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readSFixed32());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readSFixed32());
-          return arr;
-        },
-        readPackedFixed64: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readFixed64());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readFixed64());
-          return arr;
-        },
-        readPackedSFixed64: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readSFixed64());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readSFixed64());
-          return arr;
-        },
-        skip: function(val) {
-          var type2 = val & 7;
-          if (type2 === Pbf.Varint)
-            while (this.buf[this.pos++] > 127) {
-            }
-          else if (type2 === Pbf.Bytes)
-            this.pos = this.readVarint() + this.pos;
-          else if (type2 === Pbf.Fixed32)
-            this.pos += 4;
-          else if (type2 === Pbf.Fixed64)
-            this.pos += 8;
-          else
-            throw new Error("Unimplemented type: " + type2);
-        },
-        // === WRITING =================================================================
-        writeTag: function(tag2, type2) {
-          this.writeVarint(tag2 << 3 | type2);
-        },
-        realloc: function(min3) {
-          var length2 = this.length || 16;
-          while (length2 < this.pos + min3)
-            length2 *= 2;
-          if (length2 !== this.length) {
-            var buf = new Uint8Array(length2);
-            buf.set(this.buf);
-            this.buf = buf;
-            this.length = length2;
-          }
-        },
-        finish: function() {
-          this.length = this.pos;
-          this.pos = 0;
-          return this.buf.subarray(0, this.length);
-        },
-        writeFixed32: function(val) {
-          this.realloc(4);
-          writeInt32(this.buf, val, this.pos);
-          this.pos += 4;
-        },
-        writeSFixed32: function(val) {
-          this.realloc(4);
-          writeInt32(this.buf, val, this.pos);
-          this.pos += 4;
-        },
-        writeFixed64: function(val) {
-          this.realloc(8);
-          writeInt32(this.buf, val & -1, this.pos);
-          writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
-          this.pos += 8;
-        },
-        writeSFixed64: function(val) {
-          this.realloc(8);
-          writeInt32(this.buf, val & -1, this.pos);
-          writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
-          this.pos += 8;
-        },
-        writeVarint: function(val) {
-          val = +val || 0;
-          if (val > 268435455 || val < 0) {
-            writeBigVarint(val, this);
-            return;
-          }
-          this.realloc(4);
-          this.buf[this.pos++] = val & 127 | (val > 127 ? 128 : 0);
-          if (val <= 127)
-            return;
-          this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
-          if (val <= 127)
-            return;
-          this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
-          if (val <= 127)
-            return;
-          this.buf[this.pos++] = val >>> 7 & 127;
-        },
-        writeSVarint: function(val) {
-          this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
-        },
-        writeBoolean: function(val) {
-          this.writeVarint(Boolean(val));
-        },
-        writeString: function(str) {
-          str = String(str);
-          this.realloc(str.length * 4);
-          this.pos++;
-          var startPos = this.pos;
-          this.pos = writeUtf8(this.buf, str, this.pos);
-          var len = this.pos - startPos;
-          if (len >= 128)
-            makeRoomForExtraLength(startPos, len, this);
-          this.pos = startPos - 1;
-          this.writeVarint(len);
-          this.pos += len;
-        },
-        writeFloat: function(val) {
-          this.realloc(4);
-          ieee754.write(this.buf, val, this.pos, true, 23, 4);
-          this.pos += 4;
-        },
-        writeDouble: function(val) {
-          this.realloc(8);
-          ieee754.write(this.buf, val, this.pos, true, 52, 8);
-          this.pos += 8;
-        },
-        writeBytes: function(buffer) {
-          var len = buffer.length;
-          this.writeVarint(len);
-          this.realloc(len);
-          for (var i3 = 0; i3 < len; i3++)
-            this.buf[this.pos++] = buffer[i3];
-        },
-        writeRawMessage: function(fn, obj) {
-          this.pos++;
-          var startPos = this.pos;
-          fn(obj, this);
-          var len = this.pos - startPos;
-          if (len >= 128)
-            makeRoomForExtraLength(startPos, len, this);
-          this.pos = startPos - 1;
-          this.writeVarint(len);
-          this.pos += len;
-        },
-        writeMessage: function(tag2, fn, obj) {
-          this.writeTag(tag2, Pbf.Bytes);
-          this.writeRawMessage(fn, obj);
-        },
-        writePackedVarint: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedVarint, arr);
-        },
-        writePackedSVarint: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedSVarint, arr);
-        },
-        writePackedBoolean: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedBoolean, arr);
-        },
-        writePackedFloat: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedFloat, arr);
-        },
-        writePackedDouble: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedDouble, arr);
-        },
-        writePackedFixed32: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedFixed32, arr);
-        },
-        writePackedSFixed32: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedSFixed32, arr);
-        },
-        writePackedFixed64: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedFixed64, arr);
-        },
-        writePackedSFixed64: function(tag2, arr) {
-          if (arr.length)
-            this.writeMessage(tag2, writePackedSFixed64, arr);
-        },
-        writeBytesField: function(tag2, buffer) {
-          this.writeTag(tag2, Pbf.Bytes);
-          this.writeBytes(buffer);
-        },
-        writeFixed32Field: function(tag2, val) {
-          this.writeTag(tag2, Pbf.Fixed32);
-          this.writeFixed32(val);
-        },
-        writeSFixed32Field: function(tag2, val) {
-          this.writeTag(tag2, Pbf.Fixed32);
-          this.writeSFixed32(val);
-        },
-        writeFixed64Field: function(tag2, val) {
-          this.writeTag(tag2, Pbf.Fixed64);
-          this.writeFixed64(val);
-        },
-        writeSFixed64Field: function(tag2, val) {
-          this.writeTag(tag2, Pbf.Fixed64);
-          this.writeSFixed64(val);
-        },
-        writeVarintField: function(tag2, val) {
-          this.writeTag(tag2, Pbf.Varint);
-          this.writeVarint(val);
-        },
-        writeSVarintField: function(tag2, val) {
-          this.writeTag(tag2, Pbf.Varint);
-          this.writeSVarint(val);
-        },
-        writeStringField: function(tag2, str) {
-          this.writeTag(tag2, Pbf.Bytes);
-          this.writeString(str);
-        },
-        writeFloatField: function(tag2, val) {
-          this.writeTag(tag2, Pbf.Fixed32);
-          this.writeFloat(val);
-        },
-        writeDoubleField: function(tag2, val) {
-          this.writeTag(tag2, Pbf.Fixed64);
-          this.writeDouble(val);
-        },
-        writeBooleanField: function(tag2, val) {
-          this.writeVarintField(tag2, Boolean(val));
-        }
-      };
-      function readVarintRemainder(l2, s2, p2) {
-        var buf = p2.buf, h2, b2;
-        b2 = buf[p2.pos++];
-        h2 = (b2 & 112) >> 4;
-        if (b2 < 128)
-          return toNum(l2, h2, s2);
-        b2 = buf[p2.pos++];
-        h2 |= (b2 & 127) << 3;
-        if (b2 < 128)
-          return toNum(l2, h2, s2);
-        b2 = buf[p2.pos++];
-        h2 |= (b2 & 127) << 10;
-        if (b2 < 128)
-          return toNum(l2, h2, s2);
-        b2 = buf[p2.pos++];
-        h2 |= (b2 & 127) << 17;
-        if (b2 < 128)
-          return toNum(l2, h2, s2);
-        b2 = buf[p2.pos++];
-        h2 |= (b2 & 127) << 24;
-        if (b2 < 128)
-          return toNum(l2, h2, s2);
-        b2 = buf[p2.pos++];
-        h2 |= (b2 & 1) << 31;
-        if (b2 < 128)
-          return toNum(l2, h2, s2);
-        throw new Error("Expected varint not more than 10 bytes");
-      }
-      function readPackedEnd(pbf) {
-        return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
-      }
-      function toNum(low, high, isSigned) {
-        if (isSigned) {
-          return high * 4294967296 + (low >>> 0);
-        }
-        return (high >>> 0) * 4294967296 + (low >>> 0);
-      }
-      function writeBigVarint(val, pbf) {
-        var low, high;
-        if (val >= 0) {
-          low = val % 4294967296 | 0;
-          high = val / 4294967296 | 0;
-        } else {
-          low = ~(-val % 4294967296);
-          high = ~(-val / 4294967296);
-          if (low ^ 4294967295) {
-            low = low + 1 | 0;
-          } else {
-            low = 0;
-            high = high + 1 | 0;
-          }
-        }
-        if (val >= 18446744073709552e3 || val < -18446744073709552e3) {
-          throw new Error("Given varint doesn't fit into 10 bytes");
-        }
-        pbf.realloc(10);
-        writeBigVarintLow(low, high, pbf);
-        writeBigVarintHigh(high, pbf);
-      }
-      function writeBigVarintLow(low, high, pbf) {
-        pbf.buf[pbf.pos++] = low & 127 | 128;
-        low >>>= 7;
-        pbf.buf[pbf.pos++] = low & 127 | 128;
-        low >>>= 7;
-        pbf.buf[pbf.pos++] = low & 127 | 128;
-        low >>>= 7;
-        pbf.buf[pbf.pos++] = low & 127 | 128;
-        low >>>= 7;
-        pbf.buf[pbf.pos] = low & 127;
-      }
-      function writeBigVarintHigh(high, pbf) {
-        var lsb = (high & 7) << 4;
-        pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127;
-      }
-      function makeRoomForExtraLength(startPos, len, pbf) {
-        var extraLen = len <= 16383 ? 1 : len <= 2097151 ? 2 : len <= 268435455 ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
-        pbf.realloc(extraLen);
-        for (var i3 = pbf.pos - 1; i3 >= startPos; i3--)
-          pbf.buf[i3 + extraLen] = pbf.buf[i3];
-      }
-      function writePackedVarint(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeVarint(arr[i3]);
-      }
-      function writePackedSVarint(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeSVarint(arr[i3]);
-      }
-      function writePackedFloat(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeFloat(arr[i3]);
-      }
-      function writePackedDouble(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeDouble(arr[i3]);
-      }
-      function writePackedBoolean(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeBoolean(arr[i3]);
-      }
-      function writePackedFixed32(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeFixed32(arr[i3]);
-      }
-      function writePackedSFixed32(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeSFixed32(arr[i3]);
-      }
-      function writePackedFixed64(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeFixed64(arr[i3]);
-      }
-      function writePackedSFixed64(arr, pbf) {
-        for (var i3 = 0; i3 < arr.length; i3++)
-          pbf.writeSFixed64(arr[i3]);
-      }
-      function readUInt32(buf, pos) {
-        return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 16777216;
-      }
-      function writeInt32(buf, val, pos) {
-        buf[pos] = val;
-        buf[pos + 1] = val >>> 8;
-        buf[pos + 2] = val >>> 16;
-        buf[pos + 3] = val >>> 24;
-      }
-      function readInt32(buf, pos) {
-        return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
-      }
-      function readUtf8(buf, pos, end) {
-        var str = "";
-        var i3 = pos;
-        while (i3 < end) {
-          var b0 = buf[i3];
-          var c2 = null;
-          var bytesPerSequence = b0 > 239 ? 4 : b0 > 223 ? 3 : b0 > 191 ? 2 : 1;
-          if (i3 + bytesPerSequence > end)
-            break;
-          var b1, b2, b3;
-          if (bytesPerSequence === 1) {
-            if (b0 < 128) {
-              c2 = b0;
-            }
-          } else if (bytesPerSequence === 2) {
-            b1 = buf[i3 + 1];
-            if ((b1 & 192) === 128) {
-              c2 = (b0 & 31) << 6 | b1 & 63;
-              if (c2 <= 127) {
-                c2 = null;
-              }
-            }
-          } else if (bytesPerSequence === 3) {
-            b1 = buf[i3 + 1];
-            b2 = buf[i3 + 2];
-            if ((b1 & 192) === 128 && (b2 & 192) === 128) {
-              c2 = (b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63;
-              if (c2 <= 2047 || c2 >= 55296 && c2 <= 57343) {
-                c2 = null;
-              }
-            }
-          } else if (bytesPerSequence === 4) {
-            b1 = buf[i3 + 1];
-            b2 = buf[i3 + 2];
-            b3 = buf[i3 + 3];
-            if ((b1 & 192) === 128 && (b2 & 192) === 128 && (b3 & 192) === 128) {
-              c2 = (b0 & 15) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63;
-              if (c2 <= 65535 || c2 >= 1114112) {
-                c2 = null;
-              }
-            }
-          }
-          if (c2 === null) {
-            c2 = 65533;
-            bytesPerSequence = 1;
-          } else if (c2 > 65535) {
-            c2 -= 65536;
-            str += String.fromCharCode(c2 >>> 10 & 1023 | 55296);
-            c2 = 56320 | c2 & 1023;
-          }
-          str += String.fromCharCode(c2);
-          i3 += bytesPerSequence;
-        }
-        return str;
-      }
-      function readUtf8TextDecoder(buf, pos, end) {
-        return utf8TextDecoder.decode(buf.subarray(pos, end));
-      }
-      function writeUtf8(buf, str, pos) {
-        for (var i3 = 0, c2, lead; i3 < str.length; i3++) {
-          c2 = str.charCodeAt(i3);
-          if (c2 > 55295 && c2 < 57344) {
-            if (lead) {
-              if (c2 < 56320) {
-                buf[pos++] = 239;
-                buf[pos++] = 191;
-                buf[pos++] = 189;
-                lead = c2;
-                continue;
-              } else {
-                c2 = lead - 55296 << 10 | c2 - 56320 | 65536;
-                lead = null;
-              }
-            } else {
-              if (c2 > 56319 || i3 + 1 === str.length) {
-                buf[pos++] = 239;
-                buf[pos++] = 191;
-                buf[pos++] = 189;
-              } else {
-                lead = c2;
-              }
-              continue;
-            }
-          } else if (lead) {
-            buf[pos++] = 239;
-            buf[pos++] = 191;
-            buf[pos++] = 189;
-            lead = null;
-          }
-          if (c2 < 128) {
-            buf[pos++] = c2;
-          } else {
-            if (c2 < 2048) {
-              buf[pos++] = c2 >> 6 | 192;
-            } else {
-              if (c2 < 65536) {
-                buf[pos++] = c2 >> 12 | 224;
-              } else {
-                buf[pos++] = c2 >> 18 | 240;
-                buf[pos++] = c2 >> 12 & 63 | 128;
-              }
-              buf[pos++] = c2 >> 6 & 63 | 128;
-            }
-            buf[pos++] = c2 & 63 | 128;
-          }
-        }
-        return pos;
-      }
-    }
-  });
-
-  // node_modules/@mapbox/point-geometry/index.js
-  var require_point_geometry = __commonJS({
-    "node_modules/@mapbox/point-geometry/index.js"(exports2, module2) {
-      "use strict";
-      module2.exports = Point;
-      function Point(x2, y2) {
-        this.x = x2;
-        this.y = y2;
-      }
-      Point.prototype = {
-        /**
-         * Clone this point, returning a new point that can be modified
-         * without affecting the old one.
-         * @return {Point} the clone
-         */
-        clone: function() {
-          return new Point(this.x, this.y);
-        },
-        /**
-         * Add this point's x & y coordinates to another point,
-         * yielding a new point.
-         * @param {Point} p the other point
-         * @return {Point} output point
-         */
-        add: function(p2) {
-          return this.clone()._add(p2);
-        },
-        /**
-         * Subtract this point's x & y coordinates to from point,
-         * yielding a new point.
-         * @param {Point} p the other point
-         * @return {Point} output point
-         */
-        sub: function(p2) {
-          return this.clone()._sub(p2);
-        },
-        /**
-         * Multiply this point's x & y coordinates by point,
-         * yielding a new point.
-         * @param {Point} p the other point
-         * @return {Point} output point
-         */
-        multByPoint: function(p2) {
-          return this.clone()._multByPoint(p2);
-        },
-        /**
-         * Divide this point's x & y coordinates by point,
-         * yielding a new point.
-         * @param {Point} p the other point
-         * @return {Point} output point
-         */
-        divByPoint: function(p2) {
-          return this.clone()._divByPoint(p2);
-        },
-        /**
-         * Multiply this point's x & y coordinates by a factor,
-         * yielding a new point.
-         * @param {Point} k factor
-         * @return {Point} output point
-         */
-        mult: function(k2) {
-          return this.clone()._mult(k2);
-        },
-        /**
-         * Divide this point's x & y coordinates by a factor,
-         * yielding a new point.
-         * @param {Point} k factor
-         * @return {Point} output point
-         */
-        div: function(k2) {
-          return this.clone()._div(k2);
-        },
-        /**
-         * Rotate this point around the 0, 0 origin by an angle a,
-         * given in radians
-         * @param {Number} a angle to rotate around, in radians
-         * @return {Point} output point
-         */
-        rotate: function(a2) {
-          return this.clone()._rotate(a2);
-        },
-        /**
-         * Rotate this point around p point by an angle a,
-         * given in radians
-         * @param {Number} a angle to rotate around, in radians
-         * @param {Point} p Point to rotate around
-         * @return {Point} output point
-         */
-        rotateAround: function(a2, p2) {
-          return this.clone()._rotateAround(a2, p2);
-        },
-        /**
-         * Multiply this point by a 4x1 transformation matrix
-         * @param {Array<Number>} m transformation matrix
-         * @return {Point} output point
-         */
-        matMult: function(m2) {
-          return this.clone()._matMult(m2);
-        },
-        /**
-         * Calculate this point but as a unit vector from 0, 0, meaning
-         * that the distance from the resulting point to the 0, 0
-         * coordinate will be equal to 1 and the angle from the resulting
-         * point to the 0, 0 coordinate will be the same as before.
-         * @return {Point} unit vector point
-         */
-        unit: function() {
-          return this.clone()._unit();
-        },
-        /**
-         * Compute a perpendicular point, where the new y coordinate
-         * is the old x coordinate and the new x coordinate is the old y
-         * coordinate multiplied by -1
-         * @return {Point} perpendicular point
-         */
-        perp: function() {
-          return this.clone()._perp();
-        },
-        /**
-         * Return a version of this point with the x & y coordinates
-         * rounded to integers.
-         * @return {Point} rounded point
-         */
-        round: function() {
-          return this.clone()._round();
-        },
-        /**
-         * Return the magitude of this point: this is the Euclidean
-         * distance from the 0, 0 coordinate to this point's x and y
-         * coordinates.
-         * @return {Number} magnitude
-         */
-        mag: function() {
-          return Math.sqrt(this.x * this.x + this.y * this.y);
-        },
-        /**
-         * Judge whether this point is equal to another point, returning
-         * true or false.
-         * @param {Point} other the other point
-         * @return {boolean} whether the points are equal
-         */
-        equals: function(other) {
-          return this.x === other.x && this.y === other.y;
-        },
-        /**
-         * Calculate the distance from this point to another point
-         * @param {Point} p the other point
-         * @return {Number} distance
-         */
-        dist: function(p2) {
-          return Math.sqrt(this.distSqr(p2));
-        },
-        /**
-         * Calculate the distance from this point to another point,
-         * without the square root step. Useful if you're comparing
-         * relative distances.
-         * @param {Point} p the other point
-         * @return {Number} distance
-         */
-        distSqr: function(p2) {
-          var dx = p2.x - this.x, dy = p2.y - this.y;
-          return dx * dx + dy * dy;
-        },
-        /**
-         * Get the angle from the 0, 0 coordinate to this point, in radians
-         * coordinates.
-         * @return {Number} angle
-         */
-        angle: function() {
-          return Math.atan2(this.y, this.x);
-        },
-        /**
-         * Get the angle from this point to another point, in radians
-         * @param {Point} b the other point
-         * @return {Number} angle
-         */
-        angleTo: function(b2) {
-          return Math.atan2(this.y - b2.y, this.x - b2.x);
-        },
-        /**
-         * Get the angle between this point and another point, in radians
-         * @param {Point} b the other point
-         * @return {Number} angle
-         */
-        angleWith: function(b2) {
-          return this.angleWithSep(b2.x, b2.y);
-        },
-        /*
-         * Find the angle of the two vectors, solving the formula for
-         * the cross product a x b = |a||b|sin(θ) for θ.
-         * @param {Number} x the x-coordinate
-         * @param {Number} y the y-coordinate
-         * @return {Number} the angle in radians
-         */
-        angleWithSep: function(x2, y2) {
-          return Math.atan2(
-            this.x * y2 - this.y * x2,
-            this.x * x2 + this.y * y2
-          );
-        },
-        _matMult: function(m2) {
-          var x2 = m2[0] * this.x + m2[1] * this.y, y2 = m2[2] * this.x + m2[3] * this.y;
-          this.x = x2;
-          this.y = y2;
-          return this;
-        },
-        _add: function(p2) {
-          this.x += p2.x;
-          this.y += p2.y;
-          return this;
-        },
-        _sub: function(p2) {
-          this.x -= p2.x;
-          this.y -= p2.y;
-          return this;
-        },
-        _mult: function(k2) {
-          this.x *= k2;
-          this.y *= k2;
-          return this;
-        },
-        _div: function(k2) {
-          this.x /= k2;
-          this.y /= k2;
-          return this;
-        },
-        _multByPoint: function(p2) {
-          this.x *= p2.x;
-          this.y *= p2.y;
-          return this;
-        },
-        _divByPoint: function(p2) {
-          this.x /= p2.x;
-          this.y /= p2.y;
-          return this;
-        },
-        _unit: function() {
-          this._div(this.mag());
-          return this;
-        },
-        _perp: function() {
-          var y2 = this.y;
-          this.y = this.x;
-          this.x = -y2;
-          return this;
-        },
-        _rotate: function(angle2) {
-          var cos2 = Math.cos(angle2), sin2 = Math.sin(angle2), x2 = cos2 * this.x - sin2 * this.y, y2 = sin2 * this.x + cos2 * this.y;
-          this.x = x2;
-          this.y = y2;
-          return this;
-        },
-        _rotateAround: function(angle2, p2) {
-          var cos2 = Math.cos(angle2), sin2 = Math.sin(angle2), x2 = p2.x + cos2 * (this.x - p2.x) - sin2 * (this.y - p2.y), y2 = p2.y + sin2 * (this.x - p2.x) + cos2 * (this.y - p2.y);
-          this.x = x2;
-          this.y = y2;
-          return this;
-        },
-        _round: function() {
-          this.x = Math.round(this.x);
-          this.y = Math.round(this.y);
-          return this;
-        }
-      };
-      Point.convert = function(a2) {
-        if (a2 instanceof Point) {
-          return a2;
-        }
-        if (Array.isArray(a2)) {
-          return new Point(a2[0], a2[1]);
-        }
-        return a2;
-      };
-    }
-  });
-
-  // node_modules/@mapbox/vector-tile/lib/vectortilefeature.js
-  var require_vectortilefeature = __commonJS({
-    "node_modules/@mapbox/vector-tile/lib/vectortilefeature.js"(exports2, module2) {
-      "use strict";
-      var Point = require_point_geometry();
-      module2.exports = VectorTileFeature;
-      function VectorTileFeature(pbf, end, extent, keys2, values) {
-        this.properties = {};
-        this.extent = extent;
-        this.type = 0;
-        this._pbf = pbf;
-        this._geometry = -1;
-        this._keys = keys2;
-        this._values = values;
-        pbf.readFields(readFeature, this, end);
-      }
-      function readFeature(tag2, feature3, pbf) {
-        if (tag2 == 1)
-          feature3.id = pbf.readVarint();
-        else if (tag2 == 2)
-          readTag(pbf, feature3);
-        else if (tag2 == 3)
-          feature3.type = pbf.readVarint();
-        else if (tag2 == 4)
-          feature3._geometry = pbf.pos;
-      }
-      function readTag(pbf, feature3) {
-        var end = pbf.readVarint() + pbf.pos;
-        while (pbf.pos < end) {
-          var key = feature3._keys[pbf.readVarint()], value = feature3._values[pbf.readVarint()];
-          feature3.properties[key] = value;
-        }
-      }
-      VectorTileFeature.types = ["Unknown", "Point", "LineString", "Polygon"];
-      VectorTileFeature.prototype.loadGeometry = function() {
-        var pbf = this._pbf;
-        pbf.pos = this._geometry;
-        var end = pbf.readVarint() + pbf.pos, cmd = 1, length2 = 0, x2 = 0, y2 = 0, lines = [], line;
-        while (pbf.pos < end) {
-          if (length2 <= 0) {
-            var cmdLen = pbf.readVarint();
-            cmd = cmdLen & 7;
-            length2 = cmdLen >> 3;
-          }
-          length2--;
-          if (cmd === 1 || cmd === 2) {
-            x2 += pbf.readSVarint();
-            y2 += pbf.readSVarint();
-            if (cmd === 1) {
-              if (line)
-                lines.push(line);
-              line = [];
-            }
-            line.push(new Point(x2, y2));
-          } else if (cmd === 7) {
-            if (line) {
-              line.push(line[0].clone());
-            }
-          } else {
-            throw new Error("unknown command " + cmd);
-          }
-        }
-        if (line)
-          lines.push(line);
-        return lines;
-      };
-      VectorTileFeature.prototype.bbox = function() {
-        var pbf = this._pbf;
-        pbf.pos = this._geometry;
-        var end = pbf.readVarint() + pbf.pos, cmd = 1, length2 = 0, x2 = 0, y2 = 0, x12 = Infinity, x22 = -Infinity, y12 = Infinity, y22 = -Infinity;
-        while (pbf.pos < end) {
-          if (length2 <= 0) {
-            var cmdLen = pbf.readVarint();
-            cmd = cmdLen & 7;
-            length2 = cmdLen >> 3;
-          }
-          length2--;
-          if (cmd === 1 || cmd === 2) {
-            x2 += pbf.readSVarint();
-            y2 += pbf.readSVarint();
-            if (x2 < x12)
-              x12 = x2;
-            if (x2 > x22)
-              x22 = x2;
-            if (y2 < y12)
-              y12 = y2;
-            if (y2 > y22)
-              y22 = y2;
-          } else if (cmd !== 7) {
-            throw new Error("unknown command " + cmd);
-          }
-        }
-        return [x12, y12, x22, y22];
-      };
-      VectorTileFeature.prototype.toGeoJSON = function(x2, y2, z2) {
-        var size = this.extent * Math.pow(2, z2), x05 = this.extent * x2, y05 = this.extent * y2, coords = this.loadGeometry(), type2 = VectorTileFeature.types[this.type], i3, j2;
-        function project(line) {
-          for (var j3 = 0; j3 < line.length; j3++) {
-            var p2 = line[j3], y22 = 180 - (p2.y + y05) * 360 / size;
-            line[j3] = [
-              (p2.x + x05) * 360 / size - 180,
-              360 / Math.PI * Math.atan(Math.exp(y22 * Math.PI / 180)) - 90
-            ];
-          }
-        }
-        switch (this.type) {
-          case 1:
-            var points = [];
-            for (i3 = 0; i3 < coords.length; i3++) {
-              points[i3] = coords[i3][0];
-            }
-            coords = points;
-            project(coords);
-            break;
-          case 2:
-            for (i3 = 0; i3 < coords.length; i3++) {
-              project(coords[i3]);
-            }
-            break;
-          case 3:
-            coords = classifyRings(coords);
-            for (i3 = 0; i3 < coords.length; i3++) {
-              for (j2 = 0; j2 < coords[i3].length; j2++) {
-                project(coords[i3][j2]);
-              }
-            }
-            break;
-        }
-        if (coords.length === 1) {
-          coords = coords[0];
-        } else {
-          type2 = "Multi" + type2;
-        }
-        var result = {
-          type: "Feature",
-          geometry: {
-            type: type2,
-            coordinates: coords
-          },
-          properties: this.properties
-        };
-        if ("id" in this) {
-          result.id = this.id;
-        }
-        return result;
-      };
-      function classifyRings(rings) {
-        var len = rings.length;
-        if (len <= 1)
-          return [rings];
-        var polygons = [], polygon2, ccw;
-        for (var i3 = 0; i3 < len; i3++) {
-          var area = signedArea(rings[i3]);
-          if (area === 0)
-            continue;
-          if (ccw === void 0)
-            ccw = area < 0;
-          if (ccw === area < 0) {
-            if (polygon2)
-              polygons.push(polygon2);
-            polygon2 = [rings[i3]];
-          } else {
-            polygon2.push(rings[i3]);
-          }
-        }
-        if (polygon2)
-          polygons.push(polygon2);
-        return polygons;
-      }
-      function signedArea(ring) {
-        var sum = 0;
-        for (var i3 = 0, len = ring.length, j2 = len - 1, p1, p2; i3 < len; j2 = i3++) {
-          p1 = ring[i3];
-          p2 = ring[j2];
-          sum += (p2.x - p1.x) * (p1.y + p2.y);
-        }
-        return sum;
-      }
-    }
-  });
-
-  // node_modules/@mapbox/vector-tile/lib/vectortilelayer.js
-  var require_vectortilelayer = __commonJS({
-    "node_modules/@mapbox/vector-tile/lib/vectortilelayer.js"(exports2, module2) {
-      "use strict";
-      var VectorTileFeature = require_vectortilefeature();
-      module2.exports = VectorTileLayer;
-      function VectorTileLayer(pbf, end) {
-        this.version = 1;
-        this.name = null;
-        this.extent = 4096;
-        this.length = 0;
-        this._pbf = pbf;
-        this._keys = [];
-        this._values = [];
-        this._features = [];
-        pbf.readFields(readLayer, this, end);
-        this.length = this._features.length;
-      }
-      function readLayer(tag2, layer, pbf) {
-        if (tag2 === 15)
-          layer.version = pbf.readVarint();
-        else if (tag2 === 1)
-          layer.name = pbf.readString();
-        else if (tag2 === 5)
-          layer.extent = pbf.readVarint();
-        else if (tag2 === 2)
-          layer._features.push(pbf.pos);
-        else if (tag2 === 3)
-          layer._keys.push(pbf.readString());
-        else if (tag2 === 4)
-          layer._values.push(readValueMessage(pbf));
-      }
-      function readValueMessage(pbf) {
-        var value = null, end = pbf.readVarint() + pbf.pos;
-        while (pbf.pos < end) {
-          var tag2 = pbf.readVarint() >> 3;
-          value = tag2 === 1 ? pbf.readString() : tag2 === 2 ? pbf.readFloat() : tag2 === 3 ? pbf.readDouble() : tag2 === 4 ? pbf.readVarint64() : tag2 === 5 ? pbf.readVarint() : tag2 === 6 ? pbf.readSVarint() : tag2 === 7 ? pbf.readBoolean() : null;
-        }
-        return value;
-      }
-      VectorTileLayer.prototype.feature = function(i3) {
-        if (i3 < 0 || i3 >= this._features.length)
-          throw new Error("feature index out of bounds");
-        this._pbf.pos = this._features[i3];
-        var end = this._pbf.readVarint() + this._pbf.pos;
-        return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
-      };
-    }
-  });
-
-  // node_modules/@mapbox/vector-tile/lib/vectortile.js
-  var require_vectortile = __commonJS({
-    "node_modules/@mapbox/vector-tile/lib/vectortile.js"(exports2, module2) {
-      "use strict";
-      var VectorTileLayer = require_vectortilelayer();
-      module2.exports = VectorTile3;
-      function VectorTile3(pbf, end) {
-        this.layers = pbf.readFields(readTile, {}, end);
-      }
-      function readTile(tag2, layers, pbf) {
-        if (tag2 === 3) {
-          var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
-          if (layer.length)
-            layers[layer.name] = layer;
-        }
-      }
-    }
-  });
-
-  // node_modules/@mapbox/vector-tile/index.js
-  var require_vector_tile = __commonJS({
-    "node_modules/@mapbox/vector-tile/index.js"(exports2, module2) {
-      module2.exports.VectorTile = require_vectortile();
-      module2.exports.VectorTileFeature = require_vectortilefeature();
-      module2.exports.VectorTileLayer = require_vectortilelayer();
-    }
-  });
-
   // node_modules/fast-json-stable-stringify/index.js
   var require_fast_json_stable_stringify = __commonJS({
     "node_modules/fast-json-stable-stringify/index.js"(exports2, module2) {
       "use strict";
       module2.exports = function(data, opts) {
-        if (!opts)
-          opts = {};
-        if (typeof opts === "function")
-          opts = { cmp: opts };
+        if (!opts) opts = {};
+        if (typeof opts === "function") opts = { cmp: opts };
         var cycles = typeof opts.cycles === "boolean" ? opts.cycles : false;
         var cmp = opts.cmp && /* @__PURE__ */ function(f2) {
           return function(node) {
           if (node && node.toJSON && typeof node.toJSON === "function") {
             node = node.toJSON();
           }
-          if (node === void 0)
-            return;
-          if (typeof node == "number")
-            return isFinite(node) ? "" + node : "null";
-          if (typeof node !== "object")
-            return JSON.stringify(node);
+          if (node === void 0) return;
+          if (typeof node == "number") return isFinite(node) ? "" + node : "null";
+          if (typeof node !== "object") return JSON.stringify(node);
           var i3, out;
           if (Array.isArray(node)) {
             out = "[";
             for (i3 = 0; i3 < node.length; i3++) {
-              if (i3)
-                out += ",";
+              if (i3) out += ",";
               out += stringify3(node[i3]) || "null";
             }
             return out + "]";
           }
-          if (node === null)
-            return "null";
+          if (node === null) return "null";
           if (seen.indexOf(node) !== -1) {
-            if (cycles)
-              return JSON.stringify("__cycle__");
+            if (cycles) return JSON.stringify("__cycle__");
             throw new TypeError("Converting circular structure to JSON");
           }
           var seenIndex = seen.push(node) - 1;
           for (i3 = 0; i3 < keys2.length; i3++) {
             var key = keys2[i3];
             var value = stringify3(node[key]);
-            if (!value)
-              continue;
-            if (out)
-              out += ",";
+            if (!value) continue;
+            if (out) out += ",";
             out += JSON.stringify(key) + ":" + value;
           }
           seen.splice(seenIndex, 1);
         };
       }
       function search(input, dims) {
-        if (!dims)
-          dims = "NSEW";
-        if (typeof input !== "string")
-          return null;
+        if (!dims) dims = "NSEW";
+        if (typeof input !== "string") return null;
         input = input.toUpperCase();
         var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
         var m2 = input.match(regex);
-        if (!m2)
-          return null;
+        if (!m2) return null;
         var matched = m2[0];
         var dim;
         if (m2[1] && m2[5]) {
         } else {
           dim = m2[1] || m2[5];
         }
-        if (dim && dims.indexOf(dim) === -1)
-          return null;
+        if (dim && dims.indexOf(dim) === -1) return null;
         var deg = m2[2] ? parseFloat(m2[2]) : 0;
         var min3 = m2[3] ? parseFloat(m2[3]) / 60 : 0;
         var sec = m2[4] ? parseFloat(m2[4]) / 3600 : 0;
         var sign2 = deg < 0 ? -1 : 1;
-        if (dim === "S" || dim === "W")
-          sign2 *= -1;
+        if (dim === "S" || dim === "W") sign2 *= -1;
         return {
           val: (Math.abs(deg) + min3 + sec) * sign2,
           dim,
       function pair3(input, dims) {
         input = input.trim();
         var one2 = search(input, dims);
-        if (!one2)
-          return null;
+        if (!one2) return null;
         input = one2.remain.trim();
         var two = search(input, dims);
-        if (!two || two.remain)
-          return null;
+        if (!two || two.remain) return null;
         if (one2.dim) {
           return swapdim(one2.val, two.val, one2.dim);
         } else {
         }
       }
       function swapdim(a2, b2, dim) {
-        if (dim === "N" || dim === "S")
-          return [a2, b2];
-        if (dim === "W" || dim === "E")
-          return [b2, a2];
+        if (dim === "N" || dim === "S") return [a2, b2];
+        if (dim === "W" || dim === "E") return [b2, a2];
       }
     }
   });
           var _2 = {
             label: 0,
             sent: function() {
-              if (t2[0] & 1)
-                throw t2[1];
+              if (t2[0] & 1) throw t2[1];
               return t2[1];
             },
             trys: [],
             };
           }
           function step(op) {
-            if (f2)
-              throw new TypeError("Generator is already executing.");
-            while (_2)
-              try {
-                if (f2 = 1, y2 && (t2 = op[0] & 2 ? y2["return"] : op[0] ? y2["throw"] || ((t2 = y2["return"]) && t2.call(y2), 0) : y2.next) && !(t2 = t2.call(y2, op[1])).done)
-                  return t2;
-                if (y2 = 0, t2)
-                  op = [op[0] & 2, t2.value];
-                switch (op[0]) {
-                  case 0:
-                  case 1:
+            if (f2) throw new TypeError("Generator is already executing.");
+            while (_2) try {
+              if (f2 = 1, y2 && (t2 = op[0] & 2 ? y2["return"] : op[0] ? y2["throw"] || ((t2 = y2["return"]) && t2.call(y2), 0) : y2.next) && !(t2 = t2.call(y2, op[1])).done) return t2;
+              if (y2 = 0, t2) op = [op[0] & 2, t2.value];
+              switch (op[0]) {
+                case 0:
+                case 1:
+                  t2 = op;
+                  break;
+                case 4:
+                  _2.label++;
+                  return {
+                    value: op[1],
+                    done: false
+                  };
+                case 5:
+                  _2.label++;
+                  y2 = op[1];
+                  op = [0];
+                  continue;
+                case 7:
+                  op = _2.ops.pop();
+                  _2.trys.pop();
+                  continue;
+                default:
+                  if (!(t2 = _2.trys, t2 = t2.length > 0 && t2[t2.length - 1]) && (op[0] === 6 || op[0] === 2)) {
+                    _2 = 0;
+                    continue;
+                  }
+                  if (op[0] === 3 && (!t2 || op[1] > t2[0] && op[1] < t2[3])) {
+                    _2.label = op[1];
+                    break;
+                  }
+                  if (op[0] === 6 && _2.label < t2[1]) {
+                    _2.label = t2[1];
                     t2 = op;
                     break;
-                  case 4:
-                    _2.label++;
-                    return {
-                      value: op[1],
-                      done: false
-                    };
-                  case 5:
-                    _2.label++;
-                    y2 = op[1];
-                    op = [0];
-                    continue;
-                  case 7:
-                    op = _2.ops.pop();
-                    _2.trys.pop();
-                    continue;
-                  default:
-                    if (!(t2 = _2.trys, t2 = t2.length > 0 && t2[t2.length - 1]) && (op[0] === 6 || op[0] === 2)) {
-                      _2 = 0;
-                      continue;
-                    }
-                    if (op[0] === 3 && (!t2 || op[1] > t2[0] && op[1] < t2[3])) {
-                      _2.label = op[1];
-                      break;
-                    }
-                    if (op[0] === 6 && _2.label < t2[1]) {
-                      _2.label = t2[1];
-                      t2 = op;
-                      break;
-                    }
-                    if (t2 && _2.label < t2[2]) {
-                      _2.label = t2[2];
-                      _2.ops.push(op);
-                      break;
-                    }
-                    if (t2[2])
-                      _2.ops.pop();
-                    _2.trys.pop();
-                    continue;
-                }
-                op = body.call(thisArg, _2);
-              } catch (e3) {
-                op = [6, e3];
-                y2 = 0;
-              } finally {
-                f2 = t2 = 0;
+                  }
+                  if (t2 && _2.label < t2[2]) {
+                    _2.label = t2[2];
+                    _2.ops.push(op);
+                    break;
+                  }
+                  if (t2[2]) _2.ops.pop();
+                  _2.trys.pop();
+                  continue;
               }
-            if (op[0] & 5)
-              throw op[1];
+              op = body.call(thisArg, _2);
+            } catch (e3) {
+              op = [6, e3];
+              y2 = 0;
+            } finally {
+              f2 = t2 = 0;
+            }
+            if (op[0] & 5) throw op[1];
             return {
               value: op[0] ? op[1] : void 0,
               done: true
           while (true) {
             var cmp2 = comparator(i3, t2.key);
             if (cmp2 < 0) {
-              if (t2.left === null)
-                break;
+              if (t2.left === null) break;
               if (comparator(i3, t2.left.key) < 0) {
                 var y2 = t2.left;
                 t2.left = y2.right;
                 y2.right = t2;
                 t2 = y2;
-                if (t2.left === null)
-                  break;
+                if (t2.left === null) break;
               }
               r2.left = t2;
               r2 = t2;
               t2 = t2.left;
             } else if (cmp2 > 0) {
-              if (t2.right === null)
-                break;
+              if (t2.right === null) break;
               if (comparator(i3, t2.right.key) > 0) {
                 var y2 = t2.right;
                 t2.right = y2.left;
                 y2.left = t2;
                 t2 = y2;
-                if (t2.right === null)
-                  break;
+                if (t2.right === null) break;
               }
               l2.right = t2;
               l2 = t2;
               t2 = t2.right;
-            } else
-              break;
+            } else break;
           }
           l2.right = t2.left;
           r2.left = t2.right;
           };
         }
         function merge2(left, right, comparator) {
-          if (right === null)
-            return left;
-          if (left === null)
-            return right;
+          if (right === null) return left;
+          if (left === null) return right;
           right = splay(left.key, right, comparator);
           right.left = left;
           return right;
           if (root3) {
             out("" + prefix + (isTail ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ") + printNode(root3) + "\n");
             var indent = prefix + (isTail ? "    " : "\u2502   ");
-            if (root3.left)
-              printRow(root3.left, indent, false, out, printNode);
-            if (root3.right)
-              printRow(root3.right, indent, true, out, printNode);
+            if (root3.left) printRow(root3.left, indent, false, out, printNode);
+            if (root3.right) printRow(root3.right, indent, true, out, printNode);
           }
         }
         var Tree = (
               var comparator = this._comparator;
               var t2 = splay(key, this._root, comparator);
               var cmp2 = comparator(key, t2.key);
-              if (cmp2 === 0)
-                this._root = t2;
+              if (cmp2 === 0) this._root = t2;
               else {
                 if (cmp2 < 0) {
                   node.left = t2.left;
             };
             Tree2.prototype._remove = function(i3, t2, comparator) {
               var x2;
-              if (t2 === null)
-                return null;
+              if (t2 === null) return null;
               t2 = splay(i3, t2, comparator);
               var cmp2 = comparator(i3, t2.key);
               if (cmp2 === 0) {
             Tree2.prototype.pop = function() {
               var node = this._root;
               if (node) {
-                while (node.left)
-                  node = node.left;
+                while (node.left) node = node.left;
                 this._root = splay(node.key, this._root, this._comparator);
                 this._root = this._remove(node.key, this._root, this._comparator);
                 return {
               var compare2 = this._comparator;
               while (current) {
                 var cmp2 = compare2(key, current.key);
-                if (cmp2 === 0)
-                  return current;
-                else if (cmp2 < 0)
-                  current = current.left;
-                else
-                  current = current.right;
+                if (cmp2 === 0) return current;
+                else if (cmp2 < 0) current = current.left;
+                else current = current.right;
               }
               return null;
             };
             Tree2.prototype.find = function(key) {
               if (this._root) {
                 this._root = splay(key, this._root, this._comparator);
-                if (this._comparator(key, this._root.key) !== 0)
-                  return null;
+                if (this._comparator(key, this._root.key) !== 0) return null;
               }
               return this._root;
             };
               var compare2 = this._comparator;
               while (current) {
                 var cmp2 = compare2(key, current.key);
-                if (cmp2 === 0)
-                  return true;
-                else if (cmp2 < 0)
-                  current = current.left;
-                else
-                  current = current.right;
+                if (cmp2 === 0) return true;
+                else if (cmp2 < 0) current = current.left;
+                else current = current.right;
               }
               return false;
             };
                     current = Q2.pop();
                     visitor.call(ctx, current);
                     current = current.right;
-                  } else
-                    done = true;
+                  } else done = true;
                 }
               }
               return this;
                   if (cmp2 > 0) {
                     break;
                   } else if (compare2(node.key, low) >= 0) {
-                    if (fn.call(ctx, node))
-                      return this;
+                    if (fn.call(ctx, node)) return this;
                   }
                   node = node.right;
                 }
             };
             Tree2.prototype.keys = function() {
               var keys2 = [];
-              this.forEach(function(_a2) {
-                var key = _a2.key;
+              this.forEach(function(_a3) {
+                var key = _a3.key;
                 return keys2.push(key);
               });
               return keys2;
             };
             Tree2.prototype.values = function() {
               var values = [];
-              this.forEach(function(_a2) {
-                var data = _a2.data;
+              this.forEach(function(_a3) {
+                var data = _a3.data;
                 return values.push(data);
               });
               return values;
             };
             Tree2.prototype.min = function() {
-              if (this._root)
-                return this.minNode(this._root).key;
+              if (this._root) return this.minNode(this._root).key;
               return null;
             };
             Tree2.prototype.max = function() {
-              if (this._root)
-                return this.maxNode(this._root).key;
+              if (this._root) return this.maxNode(this._root).key;
               return null;
             };
             Tree2.prototype.minNode = function(t2) {
               if (t2 === void 0) {
                 t2 = this._root;
               }
-              if (t2)
-                while (t2.left)
-                  t2 = t2.left;
+              if (t2) while (t2.left) t2 = t2.left;
               return t2;
             };
             Tree2.prototype.maxNode = function(t2) {
               if (t2 === void 0) {
                 t2 = this._root;
               }
-              if (t2)
-                while (t2.right)
-                  t2 = t2.right;
+              if (t2) while (t2.right) t2 = t2.right;
               return t2;
             };
             Tree2.prototype.at = function(index2) {
                 } else {
                   if (Q2.length > 0) {
                     current = Q2.pop();
-                    if (i3 === index2)
-                      return current;
+                    if (i3 === index2) return current;
                     i3++;
                     current = current.right;
-                  } else
-                    done = true;
+                  } else done = true;
                 }
               }
               return null;
               var successor = null;
               if (d2.right) {
                 successor = d2.right;
-                while (successor.left)
-                  successor = successor.left;
+                while (successor.left) successor = successor.left;
                 return successor;
               }
               var comparator = this._comparator;
               while (root3) {
                 var cmp2 = comparator(d2.key, root3.key);
-                if (cmp2 === 0)
-                  break;
+                if (cmp2 === 0) break;
                 else if (cmp2 < 0) {
                   successor = root3;
                   root3 = root3.left;
-                } else
-                  root3 = root3.right;
+                } else root3 = root3.right;
               }
               return successor;
             };
               var predecessor = null;
               if (d2.left !== null) {
                 predecessor = d2.left;
-                while (predecessor.right)
-                  predecessor = predecessor.right;
+                while (predecessor.right) predecessor = predecessor.right;
                 return predecessor;
               }
               var comparator = this._comparator;
               while (root3) {
                 var cmp2 = comparator(d2.key, root3.key);
-                if (cmp2 === 0)
-                  break;
-                else if (cmp2 < 0)
-                  root3 = root3.left;
+                if (cmp2 === 0) break;
+                else if (cmp2 < 0) root3 = root3.left;
                 else {
                   predecessor = root3;
                   root3 = root3.right;
               }
               var size = keys2.length;
               var comparator = this._comparator;
-              if (presort)
-                sort(keys2, values, 0, size - 1, comparator);
+              if (presort) sort(keys2, values, 0, size - 1, comparator);
               if (this._root === null) {
                 this._root = loadRecursive(keys2, values, 0, size);
                 this._size = size;
             };
             Tree2.prototype.update = function(key, newKey, newData) {
               var comparator = this._comparator;
-              var _a2 = split(key, this._root, comparator), left = _a2.left, right = _a2.right;
+              var _a3 = split(key, this._root, comparator), left = _a3.left, right = _a3.right;
               if (comparator(key, newKey) < 0) {
                 right = insert(newKey, newData, right, comparator);
               } else {
             };
             Tree2.prototype[Symbol.iterator] = function() {
               var current, Q2, done;
-              return __generator(this, function(_a2) {
-                switch (_a2.label) {
+              return __generator(this, function(_a3) {
+                switch (_a3.label) {
                   case 0:
                     current = this._root;
                     Q2 = [];
                     done = false;
-                    _a2.label = 1;
+                    _a3.label = 1;
                   case 1:
-                    if (!!done)
-                      return [3, 6];
-                    if (!(current !== null))
-                      return [3, 2];
+                    if (!!done) return [3, 6];
+                    if (!(current !== null)) return [3, 2];
                     Q2.push(current);
                     current = current.left;
                     return [3, 5];
                   case 2:
-                    if (!(Q2.length !== 0))
-                      return [3, 4];
+                    if (!(Q2.length !== 0)) return [3, 4];
                     current = Q2.pop();
                     return [4, current];
                   case 3:
-                    _a2.sent();
+                    _a3.sent();
                     current = current.right;
                     return [3, 5];
                   case 4:
                     done = true;
-                    _a2.label = 5;
+                    _a3.label = 5;
                   case 5:
                     return [3, 1];
                   case 6:
               if (Q2.length > 0) {
                 current = p2 = p2.next = Q2.pop();
                 current = current.right;
-              } else
-                done = true;
+              } else done = true;
             }
           }
           p2.next = null;
           return head.next;
         }
         function sort(keys2, values, left, right, compare2) {
-          if (left >= right)
-            return;
+          if (left >= right) return;
           var pivot = keys2[left + right >> 1];
           var i3 = left - 1;
           var j2 = right + 1;
             do
               j2--;
             while (compare2(keys2[j2], pivot) > 0);
-            if (i3 >= j2)
-              break;
+            if (i3 >= j2) break;
             var tmp = keys2[i3];
             keys2[i3] = keys2[j2];
             keys2[j2] = tmp;
           sort(keys2, values, left, j2, compare2);
           sort(keys2, values, j2 + 1, right, compare2);
         }
-        const isInBbox2 = (bbox2, point2) => {
-          return bbox2.ll.x <= point2.x && point2.x <= bbox2.ur.x && bbox2.ll.y <= point2.y && point2.y <= bbox2.ur.y;
+        const isInBbox2 = (bbox2, point) => {
+          return bbox2.ll.x <= point.x && point.x <= bbox2.ur.x && bbox2.ll.y <= point.y && point.y <= bbox2.ur.y;
         };
         const getBboxOverlap2 = (b1, b2) => {
-          if (b2.ur.x < b1.ll.x || b1.ur.x < b2.ll.x || b2.ur.y < b1.ll.y || b1.ur.y < b2.ll.y)
-            return null;
+          if (b2.ur.x < b1.ll.x || b1.ur.x < b2.ll.x || b2.ur.y < b1.ll.y || b1.ur.y < b2.ll.y) return null;
           const lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
           const upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x;
           const lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
           };
         };
         let epsilon$1 = Number.EPSILON;
-        if (epsilon$1 === void 0)
-          epsilon$1 = Math.pow(2, -52);
+        if (epsilon$1 === void 0) epsilon$1 = Math.pow(2, -52);
         const EPSILON_SQ = epsilon$1 * epsilon$1;
         const cmp = (a2, b2) => {
           if (-epsilon$1 < a2 && a2 < epsilon$1) {
         }
         function estimate(elen, e3) {
           let Q2 = e3[0];
-          for (let i3 = 1; i3 < elen; i3++)
-            Q2 += e3[i3];
+          for (let i3 = 1; i3 < elen; i3++) Q2 += e3[i3];
           return Q2;
         }
         function vec(n3) {
           }
           errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
           det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail);
-          if (det >= errbound || -det >= errbound)
-            return det;
+          if (det >= errbound || -det >= errbound) return det;
           s1 = acxtail * bcy;
           c2 = splitter * acxtail;
           ahi = c2 - (c2 - acxtail);
           const detright = (ax - cx) * (by - cy);
           const det = detleft - detright;
           const detsum = Math.abs(detleft + detright);
-          if (Math.abs(det) >= ccwerrboundA * detsum)
-            return det;
+          if (Math.abs(det) >= ccwerrboundA * detsum) return det;
           return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
         }
         const crossProduct2 = (a2, b2) => a2.x * b2.y - a2.y * b2.x;
         const dotProduct2 = (a2, b2) => a2.x * b2.x + a2.y * b2.y;
         const compareVectorAngles = (basePt, endPt1, endPt2) => {
           const res = orient2d(basePt.x, basePt.y, endPt1.x, endPt1.y, endPt2.x, endPt2.y);
-          if (res > 0)
-            return -1;
-          if (res < 0)
-            return 1;
+          if (res > 0) return -1;
+          if (res < 0) return 1;
           return 0;
         };
         const length2 = (v2) => Math.sqrt(dotProduct2(v2, v2));
           return dotProduct2(vAngle, vBase) / length2(vAngle) / length2(vBase);
         };
         const horizontalIntersection2 = (pt2, v2, y2) => {
-          if (v2.y === 0)
-            return null;
+          if (v2.y === 0) return null;
           return {
             x: pt2.x + v2.x / v2.y * (y2 - pt2.y),
             y: y2
           };
         };
         const verticalIntersection2 = (pt2, v2, x2) => {
-          if (v2.x === 0)
-            return null;
+          if (v2.x === 0) return null;
           return {
             x: x2,
             y: pt2.y + v2.y / v2.x * (x2 - pt2.x)
           };
         };
         const intersection$1 = (pt1, v1, pt2, v2) => {
-          if (v1.x === 0)
-            return verticalIntersection2(pt2, v2, pt1.x);
-          if (v2.x === 0)
-            return verticalIntersection2(pt1, v1, pt2.x);
-          if (v1.y === 0)
-            return horizontalIntersection2(pt2, v2, pt1.y);
-          if (v2.y === 0)
-            return horizontalIntersection2(pt1, v1, pt2.y);
+          if (v1.x === 0) return verticalIntersection2(pt2, v2, pt1.x);
+          if (v2.x === 0) return verticalIntersection2(pt1, v1, pt2.x);
+          if (v1.y === 0) return horizontalIntersection2(pt2, v2, pt1.y);
+          if (v2.y === 0) return horizontalIntersection2(pt1, v1, pt2.y);
           const kross = crossProduct2(v1, v2);
-          if (kross == 0)
-            return null;
+          if (kross == 0) return null;
           const ve2 = {
             x: pt2.x - pt1.x,
             y: pt2.y - pt1.y
           // for ordering sweep events in the sweep event queue
           static compare(a2, b2) {
             const ptCmp = SweepEvent2.comparePoints(a2.point, b2.point);
-            if (ptCmp !== 0)
-              return ptCmp;
-            if (a2.point !== b2.point)
-              a2.link(b2);
-            if (a2.isLeft !== b2.isLeft)
-              return a2.isLeft ? 1 : -1;
+            if (ptCmp !== 0) return ptCmp;
+            if (a2.point !== b2.point) a2.link(b2);
+            if (a2.isLeft !== b2.isLeft) return a2.isLeft ? 1 : -1;
             return Segment2.compare(a2.segment, b2.segment);
           }
           // for ordering points in sweep line order
           static comparePoints(aPt, bPt) {
-            if (aPt.x < bPt.x)
-              return -1;
-            if (aPt.x > bPt.x)
-              return 1;
-            if (aPt.y < bPt.y)
-              return -1;
-            if (aPt.y > bPt.y)
-              return 1;
+            if (aPt.x < bPt.x) return -1;
+            if (aPt.x > bPt.x) return 1;
+            if (aPt.y < bPt.y) return -1;
+            if (aPt.y > bPt.y) return 1;
             return 0;
           }
           // Warning: 'point' input will be modified and re-used (for performance)
-          constructor(point2, isLeft) {
-            if (point2.events === void 0)
-              point2.events = [this];
-            else
-              point2.events.push(this);
-            this.point = point2;
+          constructor(point, isLeft) {
+            if (point.events === void 0) point.events = [this];
+            else point.events.push(this);
+            this.point = point;
             this.isLeft = isLeft;
           }
           link(other) {
             const numEvents = this.point.events.length;
             for (let i3 = 0; i3 < numEvents; i3++) {
               const evt1 = this.point.events[i3];
-              if (evt1.segment.consumedBy !== void 0)
-                continue;
+              if (evt1.segment.consumedBy !== void 0) continue;
               for (let j2 = i3 + 1; j2 < numEvents; j2++) {
                 const evt2 = this.point.events[j2];
-                if (evt2.consumedBy !== void 0)
-                  continue;
-                if (evt1.otherSE.point.events !== evt2.otherSE.point.events)
-                  continue;
+                if (evt2.consumedBy !== void 0) continue;
+                if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
                 evt1.segment.consume(evt2.segment);
               }
             }
               });
             };
             return (a2, b2) => {
-              if (!cache.has(a2))
-                fillCache(a2);
-              if (!cache.has(b2))
-                fillCache(b2);
+              if (!cache.has(a2)) fillCache(a2);
+              if (!cache.has(b2)) fillCache(b2);
               const {
                 sine: asine,
                 cosine: acosine
                 cosine: bcosine
               } = cache.get(b2);
               if (asine >= 0 && bsine >= 0) {
-                if (acosine < bcosine)
-                  return 1;
-                if (acosine > bcosine)
-                  return -1;
+                if (acosine < bcosine) return 1;
+                if (acosine > bcosine) return -1;
                 return 0;
               }
               if (asine < 0 && bsine < 0) {
-                if (acosine < bcosine)
-                  return -1;
-                if (acosine > bcosine)
-                  return 1;
+                if (acosine < bcosine) return -1;
+                if (acosine > bcosine) return 1;
                 return 0;
               }
-              if (bsine < asine)
-                return -1;
-              if (bsine > asine)
-                return 1;
+              if (bsine < asine) return -1;
+              if (bsine > asine) return 1;
               return 0;
             };
           }
             const blx = b2.leftSE.point.x;
             const arx = a2.rightSE.point.x;
             const brx = b2.rightSE.point.x;
-            if (brx < alx)
-              return 1;
-            if (arx < blx)
-              return -1;
+            if (brx < alx) return 1;
+            if (arx < blx) return -1;
             const aly = a2.leftSE.point.y;
             const bly = b2.leftSE.point.y;
             const ary = a2.rightSE.point.y;
             const bry = b2.rightSE.point.y;
             if (alx < blx) {
-              if (bly < aly && bly < ary)
-                return 1;
-              if (bly > aly && bly > ary)
-                return -1;
+              if (bly < aly && bly < ary) return 1;
+              if (bly > aly && bly > ary) return -1;
               const aCmpBLeft = a2.comparePoint(b2.leftSE.point);
-              if (aCmpBLeft < 0)
-                return 1;
-              if (aCmpBLeft > 0)
-                return -1;
+              if (aCmpBLeft < 0) return 1;
+              if (aCmpBLeft > 0) return -1;
               const bCmpARight = b2.comparePoint(a2.rightSE.point);
-              if (bCmpARight !== 0)
-                return bCmpARight;
+              if (bCmpARight !== 0) return bCmpARight;
               return -1;
             }
             if (alx > blx) {
-              if (aly < bly && aly < bry)
-                return -1;
-              if (aly > bly && aly > bry)
-                return 1;
+              if (aly < bly && aly < bry) return -1;
+              if (aly > bly && aly > bry) return 1;
               const bCmpALeft = b2.comparePoint(a2.leftSE.point);
-              if (bCmpALeft !== 0)
-                return bCmpALeft;
+              if (bCmpALeft !== 0) return bCmpALeft;
               const aCmpBRight = a2.comparePoint(b2.rightSE.point);
-              if (aCmpBRight < 0)
-                return 1;
-              if (aCmpBRight > 0)
-                return -1;
+              if (aCmpBRight < 0) return 1;
+              if (aCmpBRight > 0) return -1;
               return 1;
             }
-            if (aly < bly)
-              return -1;
-            if (aly > bly)
-              return 1;
+            if (aly < bly) return -1;
+            if (aly > bly) return 1;
             if (arx < brx) {
               const bCmpARight = b2.comparePoint(a2.rightSE.point);
-              if (bCmpARight !== 0)
-                return bCmpARight;
+              if (bCmpARight !== 0) return bCmpARight;
             }
             if (arx > brx) {
               const aCmpBRight = a2.comparePoint(b2.rightSE.point);
-              if (aCmpBRight < 0)
-                return 1;
-              if (aCmpBRight > 0)
-                return -1;
+              if (aCmpBRight < 0) return 1;
+              if (aCmpBRight > 0) return -1;
             }
             if (arx !== brx) {
               const ay = ary - aly;
               const ax = arx - alx;
               const by = bry - bly;
               const bx = brx - blx;
-              if (ay > ax && by < bx)
-                return 1;
-              if (ay < ax && by > bx)
-                return -1;
-            }
-            if (arx > brx)
-              return 1;
-            if (arx < brx)
-              return -1;
-            if (ary < bry)
-              return -1;
-            if (ary > bry)
-              return 1;
-            if (a2.id < b2.id)
-              return -1;
-            if (a2.id > b2.id)
-              return 1;
+              if (ay > ax && by < bx) return 1;
+              if (ay < ax && by > bx) return -1;
+            }
+            if (arx > brx) return 1;
+            if (arx < brx) return -1;
+            if (ary < bry) return -1;
+            if (ary > bry) return 1;
+            if (a2.id < b2.id) return -1;
+            if (a2.id > b2.id) return 1;
             return 0;
           }
           /* Warning: a reference to ringWindings input will be stored,
               leftPt = pt2;
               rightPt = pt1;
               winding = -1;
-            } else
-              throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
+            } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
             const leftSE = new SweepEvent2(leftPt, true);
             const rightSE = new SweepEvent2(rightPt, false);
             return new Segment2(leftSE, rightSE, [ring], [winding]);
            *   0: point is colinear to segment
            *  -1: point lies below the segment (to the right of vertical)
            */
-          comparePoint(point2) {
-            if (this.isAnEndpoint(point2))
-              return 0;
+          comparePoint(point) {
+            if (this.isAnEndpoint(point)) return 0;
             const lPt = this.leftSE.point;
             const rPt = this.rightSE.point;
             const v2 = this.vector();
             if (lPt.x === rPt.x) {
-              if (point2.x === lPt.x)
-                return 0;
-              return point2.x < lPt.x ? 1 : -1;
+              if (point.x === lPt.x) return 0;
+              return point.x < lPt.x ? 1 : -1;
             }
-            const yDist = (point2.y - lPt.y) / v2.y;
+            const yDist = (point.y - lPt.y) / v2.y;
             const xFromYDist = lPt.x + yDist * v2.x;
-            if (point2.x === xFromYDist)
-              return 0;
-            const xDist = (point2.x - lPt.x) / v2.x;
+            if (point.x === xFromYDist) return 0;
+            const xDist = (point.x - lPt.x) / v2.x;
             const yFromXDist = lPt.y + xDist * v2.y;
-            if (point2.y === yFromXDist)
-              return 0;
-            return point2.y < yFromXDist ? -1 : 1;
+            if (point.y === yFromXDist) return 0;
+            return point.y < yFromXDist ? -1 : 1;
           }
           /**
            * Given another segment, returns the first non-trivial intersection
             const tBbox = this.bbox();
             const oBbox = other.bbox();
             const bboxOverlap = getBboxOverlap2(tBbox, oBbox);
-            if (bboxOverlap === null)
-              return null;
+            if (bboxOverlap === null) return null;
             const tlp = this.leftSE.point;
             const trp = this.rightSE.point;
             const olp = other.leftSE.point;
             const touchesOtherRSE = isInBbox2(tBbox, orp) && this.comparePoint(orp) === 0;
             const touchesThisRSE = isInBbox2(oBbox, trp) && other.comparePoint(trp) === 0;
             if (touchesThisLSE && touchesOtherLSE) {
-              if (touchesThisRSE && !touchesOtherRSE)
-                return trp;
-              if (!touchesThisRSE && touchesOtherRSE)
-                return orp;
+              if (touchesThisRSE && !touchesOtherRSE) return trp;
+              if (!touchesThisRSE && touchesOtherRSE) return orp;
               return null;
             }
             if (touchesThisLSE) {
               if (touchesOtherRSE) {
-                if (tlp.x === orp.x && tlp.y === orp.y)
-                  return null;
+                if (tlp.x === orp.x && tlp.y === orp.y) return null;
               }
               return tlp;
             }
             if (touchesOtherLSE) {
               if (touchesThisRSE) {
-                if (trp.x === olp.x && trp.y === olp.y)
-                  return null;
+                if (trp.x === olp.x && trp.y === olp.y) return null;
               }
               return olp;
             }
-            if (touchesThisRSE && touchesOtherRSE)
-              return null;
-            if (touchesThisRSE)
-              return trp;
-            if (touchesOtherRSE)
-              return orp;
+            if (touchesThisRSE && touchesOtherRSE) return null;
+            if (touchesThisRSE) return trp;
+            if (touchesOtherRSE) return orp;
             const pt2 = intersection$1(tlp, this.vector(), olp, other.vector());
-            if (pt2 === null)
-              return null;
-            if (!isInBbox2(bboxOverlap, pt2))
-              return null;
+            if (pt2 === null) return null;
+            if (!isInBbox2(bboxOverlap, pt2)) return null;
             return rounder.round(pt2.x, pt2.y);
           }
           /**
            *
            * Warning: input array of points is modified
            */
-          split(point2) {
+          split(point) {
             const newEvents = [];
-            const alreadyLinked = point2.events !== void 0;
-            const newLeftSE = new SweepEvent2(point2, true);
-            const newRightSE = new SweepEvent2(point2, false);
+            const alreadyLinked = point.events !== void 0;
+            const newLeftSE = new SweepEvent2(point, true);
+            const newRightSE = new SweepEvent2(point, false);
             const oldRightSE = this.rightSE;
             this.replaceRightSE(newRightSE);
             newEvents.push(newRightSE);
           consume(other) {
             let consumer = this;
             let consumee = other;
-            while (consumer.consumedBy)
-              consumer = consumer.consumedBy;
-            while (consumee.consumedBy)
-              consumee = consumee.consumedBy;
+            while (consumer.consumedBy) consumer = consumer.consumedBy;
+            while (consumee.consumedBy) consumee = consumee.consumedBy;
             const cmp2 = Segment2.compare(consumer, consumee);
-            if (cmp2 === 0)
-              return;
+            if (cmp2 === 0) return;
             if (cmp2 > 0) {
               const tmp = consumer;
               consumer = consumee;
               if (index2 === -1) {
                 consumer.rings.push(ring);
                 consumer.windings.push(winding);
-              } else
-                consumer.windings[index2] += winding;
+              } else consumer.windings[index2] += winding;
             }
             consumee.rings = null;
             consumee.windings = null;
           }
           /* The first segment previous segment chain that is in the result */
           prevInResult() {
-            if (this._prevInResult !== void 0)
-              return this._prevInResult;
-            if (!this.prev)
-              this._prevInResult = null;
-            else if (this.prev.isInResult())
-              this._prevInResult = this.prev;
-            else
-              this._prevInResult = this.prev.prevInResult();
+            if (this._prevInResult !== void 0) return this._prevInResult;
+            if (!this.prev) this._prevInResult = null;
+            else if (this.prev.isInResult()) this._prevInResult = this.prev;
+            else this._prevInResult = this.prev.prevInResult();
             return this._prevInResult;
           }
           beforeState() {
-            if (this._beforeState !== void 0)
-              return this._beforeState;
-            if (!this.prev)
-              this._beforeState = {
-                rings: [],
-                windings: [],
-                multiPolys: []
-              };
+            if (this._beforeState !== void 0) return this._beforeState;
+            if (!this.prev) this._beforeState = {
+              rings: [],
+              windings: [],
+              multiPolys: []
+            };
             else {
               const seg = this.prev.consumedBy || this.prev;
               this._beforeState = seg.afterState();
             return this._beforeState;
           }
           afterState() {
-            if (this._afterState !== void 0)
-              return this._afterState;
+            if (this._afterState !== void 0) return this._afterState;
             const beforeState = this.beforeState();
             this._afterState = {
               rings: beforeState.rings.slice(0),
               if (index2 === -1) {
                 ringsAfter.push(ring);
                 windingsAfter.push(winding);
-              } else
-                windingsAfter[index2] += winding;
+              } else windingsAfter[index2] += winding;
             }
             const polysAfter = [];
             const polysExclude = [];
             for (let i3 = 0, iMax = ringsAfter.length; i3 < iMax; i3++) {
-              if (windingsAfter[i3] === 0)
-                continue;
+              if (windingsAfter[i3] === 0) continue;
               const ring = ringsAfter[i3];
               const poly = ring.poly;
-              if (polysExclude.indexOf(poly) !== -1)
-                continue;
-              if (ring.isExterior)
-                polysAfter.push(poly);
+              if (polysExclude.indexOf(poly) !== -1) continue;
+              if (ring.isExterior) polysAfter.push(poly);
               else {
-                if (polysExclude.indexOf(poly) === -1)
-                  polysExclude.push(poly);
+                if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
                 const index2 = polysAfter.indexOf(ring.poly);
-                if (index2 !== -1)
-                  polysAfter.splice(index2, 1);
+                if (index2 !== -1) polysAfter.splice(index2, 1);
               }
             }
             for (let i3 = 0, iMax = polysAfter.length; i3 < iMax; i3++) {
               const mp = polysAfter[i3].multiPoly;
-              if (mpsAfter.indexOf(mp) === -1)
-                mpsAfter.push(mp);
+              if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
             }
             return this._afterState;
           }
           /* Is this segment part of the final result? */
           isInResult() {
-            if (this.consumedBy)
-              return false;
-            if (this._isInResult !== void 0)
-              return this._isInResult;
+            if (this.consumedBy) return false;
+            if (this._isInResult !== void 0) return this._isInResult;
             const mpsBefore = this.beforeState().multiPolys;
             const mpsAfter = this.afterState().multiPolys;
             switch (operation2.type) {
               if (typeof geomRing[i3][0] !== "number" || typeof geomRing[i3][1] !== "number") {
                 throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
               }
-              let point2 = rounder.round(geomRing[i3][0], geomRing[i3][1]);
-              if (point2.x === prevPoint.x && point2.y === prevPoint.y)
-                continue;
-              this.segments.push(Segment2.fromRing(prevPoint, point2, this));
-              if (point2.x < this.bbox.ll.x)
-                this.bbox.ll.x = point2.x;
-              if (point2.y < this.bbox.ll.y)
-                this.bbox.ll.y = point2.y;
-              if (point2.x > this.bbox.ur.x)
-                this.bbox.ur.x = point2.x;
-              if (point2.y > this.bbox.ur.y)
-                this.bbox.ur.y = point2.y;
-              prevPoint = point2;
+              let point = rounder.round(geomRing[i3][0], geomRing[i3][1]);
+              if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
+              this.segments.push(Segment2.fromRing(prevPoint, point, this));
+              if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
+              if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
+              if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
+              if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
+              prevPoint = point;
             }
             if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
               this.segments.push(Segment2.fromRing(prevPoint, firstPoint, this));
             this.interiorRings = [];
             for (let i3 = 1, iMax = geomPoly.length; i3 < iMax; i3++) {
               const ring = new RingIn2(geomPoly[i3], this, false);
-              if (ring.bbox.ll.x < this.bbox.ll.x)
-                this.bbox.ll.x = ring.bbox.ll.x;
-              if (ring.bbox.ll.y < this.bbox.ll.y)
-                this.bbox.ll.y = ring.bbox.ll.y;
-              if (ring.bbox.ur.x > this.bbox.ur.x)
-                this.bbox.ur.x = ring.bbox.ur.x;
-              if (ring.bbox.ur.y > this.bbox.ur.y)
-                this.bbox.ur.y = ring.bbox.ur.y;
+              if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
+              if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
+              if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
+              if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
               this.interiorRings.push(ring);
             }
             this.multiPoly = multiPoly;
               throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
             }
             try {
-              if (typeof geom[0][0][0] === "number")
-                geom = [geom];
+              if (typeof geom[0][0][0] === "number") geom = [geom];
             } catch (ex) {
             }
             this.polys = [];
             };
             for (let i3 = 0, iMax = geom.length; i3 < iMax; i3++) {
               const poly = new PolyIn2(geom[i3], this);
-              if (poly.bbox.ll.x < this.bbox.ll.x)
-                this.bbox.ll.x = poly.bbox.ll.x;
-              if (poly.bbox.ll.y < this.bbox.ll.y)
-                this.bbox.ll.y = poly.bbox.ll.y;
-              if (poly.bbox.ur.x > this.bbox.ur.x)
-                this.bbox.ur.x = poly.bbox.ur.x;
-              if (poly.bbox.ur.y > this.bbox.ur.y)
-                this.bbox.ur.y = poly.bbox.ur.y;
+              if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
+              if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
+              if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
+              if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
               this.polys.push(poly);
             }
             this.isSubject = isSubject;
             const ringsOut = [];
             for (let i3 = 0, iMax = allSegments.length; i3 < iMax; i3++) {
               const segment = allSegments[i3];
-              if (!segment.isInResult() || segment.ringOut)
-                continue;
+              if (!segment.isInResult() || segment.ringOut) continue;
               let prevEvent = null;
               let event = segment.leftSE;
               let nextEvent = segment.rightSE;
                 prevEvent = event;
                 event = nextEvent;
                 events.push(event);
-                if (event.point === startingPoint)
-                  break;
+                if (event.point === startingPoint) break;
                 while (true) {
                   const availableLEs = event.getAvailableLinkedEvents();
                   if (availableLEs.length === 0) {
             for (let i3 = 1, iMax = this.events.length - 1; i3 < iMax; i3++) {
               const pt3 = this.events[i3].point;
               const nextPt2 = this.events[i3 + 1].point;
-              if (compareVectorAngles(pt3, prevPt, nextPt2) === 0)
-                continue;
+              if (compareVectorAngles(pt3, prevPt, nextPt2) === 0) continue;
               points.push(pt3);
               prevPt = pt3;
             }
-            if (points.length === 1)
-              return null;
+            if (points.length === 1) return null;
             const pt2 = points[0];
             const nextPt = points[1];
-            if (compareVectorAngles(pt2, prevPt, nextPt) === 0)
-              points.shift();
+            if (compareVectorAngles(pt2, prevPt, nextPt) === 0) points.shift();
             points.push(points[0]);
             const step = this.isExteriorRing() ? 1 : -1;
             const iStart = this.isExteriorRing() ? 0 : points.length - 1;
             const iEnd = this.isExteriorRing() ? points.length : -1;
             const orderedPoints = [];
-            for (let i3 = iStart; i3 != iEnd; i3 += step)
-              orderedPoints.push([points[i3].x, points[i3].y]);
+            for (let i3 = iStart; i3 != iEnd; i3 += step) orderedPoints.push([points[i3].x, points[i3].y]);
             return orderedPoints;
           }
           isExteriorRing() {
             let leftMostEvt = this.events[0];
             for (let i3 = 1, iMax = this.events.length; i3 < iMax; i3++) {
               const evt = this.events[i3];
-              if (SweepEvent2.compare(leftMostEvt, evt) > 0)
-                leftMostEvt = evt;
+              if (SweepEvent2.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
             }
             let prevSeg = leftMostEvt.segment.prevInResult();
             let prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
             while (true) {
-              if (!prevSeg)
-                return null;
-              if (!prevPrevSeg)
-                return prevSeg.ringOut;
+              if (!prevSeg) return null;
+              if (!prevPrevSeg) return prevSeg.ringOut;
               if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
                 if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
                   return prevSeg.ringOut;
-                } else
-                  return prevSeg.ringOut.enclosingRing();
+                } else return prevSeg.ringOut.enclosingRing();
               }
               prevSeg = prevPrevSeg.prevInResult();
               prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
           }
           getGeom() {
             const geom = [this.exteriorRing.getGeom()];
-            if (geom[0] === null)
-              return null;
+            if (geom[0] === null) return null;
             for (let i3 = 0, iMax = this.interiorRings.length; i3 < iMax; i3++) {
               const ringGeom = this.interiorRings[i3].getGeom();
-              if (ringGeom === null)
-                continue;
+              if (ringGeom === null) continue;
               geom.push(ringGeom);
             }
             return geom;
             const geom = [];
             for (let i3 = 0, iMax = this.polys.length; i3 < iMax; i3++) {
               const polyGeom = this.polys[i3].getGeom();
-              if (polyGeom === null)
-                continue;
+              if (polyGeom === null) continue;
               geom.push(polyGeom);
             }
             return geom;
             const polys = [];
             for (let i3 = 0, iMax = rings.length; i3 < iMax; i3++) {
               const ring = rings[i3];
-              if (ring.poly)
-                continue;
-              if (ring.isExteriorRing())
-                polys.push(new PolyOut2(ring));
+              if (ring.poly) continue;
+              if (ring.isExteriorRing()) polys.push(new PolyOut2(ring));
               else {
                 const enclosingRing = ring.enclosingRing();
-                if (!enclosingRing.poly)
-                  polys.push(new PolyOut2(enclosingRing));
+                if (!enclosingRing.poly) polys.push(new PolyOut2(enclosingRing));
                 enclosingRing.poly.addInterior(ring);
               }
             }
             const segment = event.segment;
             const newEvents = [];
             if (event.consumedBy) {
-              if (event.isLeft)
-                this.queue.remove(event.otherSE);
-              else
-                this.tree.remove(segment);
+              if (event.isLeft) this.queue.remove(event.otherSE);
+              else this.tree.remove(segment);
               return newEvents;
             }
             const node = event.isLeft ? this.tree.add(segment) : this.tree.find(segment);
-            if (!node)
-              throw new Error("Unable to find segment #".concat(segment.id, " ") + "[".concat(segment.leftSE.point.x, ", ").concat(segment.leftSE.point.y, "] -> ") + "[".concat(segment.rightSE.point.x, ", ").concat(segment.rightSE.point.y, "] ") + "in SweepLine tree.");
+            if (!node) throw new Error("Unable to find segment #".concat(segment.id, " ") + "[".concat(segment.leftSE.point.x, ", ").concat(segment.leftSE.point.y, "] -> ") + "[".concat(segment.rightSE.point.x, ", ").concat(segment.rightSE.point.y, "] ") + "in SweepLine tree.");
             let prevNode = node;
             let nextNode = node;
             let prevSeg = void 0;
             let nextSeg = void 0;
             while (prevSeg === void 0) {
               prevNode = this.tree.prev(prevNode);
-              if (prevNode === null)
-                prevSeg = null;
-              else if (prevNode.key.consumedBy === void 0)
-                prevSeg = prevNode.key;
+              if (prevNode === null) prevSeg = null;
+              else if (prevNode.key.consumedBy === void 0) prevSeg = prevNode.key;
             }
             while (nextSeg === void 0) {
               nextNode = this.tree.next(nextNode);
-              if (nextNode === null)
-                nextSeg = null;
-              else if (nextNode.key.consumedBy === void 0)
-                nextSeg = nextNode.key;
+              if (nextNode === null) nextSeg = null;
+              else if (nextNode.key.consumedBy === void 0) nextSeg = nextNode.key;
             }
             if (event.isLeft) {
               let prevMySplitter = null;
               if (prevSeg) {
                 const prevInter = prevSeg.getIntersection(segment);
                 if (prevInter !== null) {
-                  if (!segment.isAnEndpoint(prevInter))
-                    prevMySplitter = prevInter;
+                  if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
                   if (!prevSeg.isAnEndpoint(prevInter)) {
                     const newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
                     for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
               if (nextSeg) {
                 const nextInter = nextSeg.getIntersection(segment);
                 if (nextInter !== null) {
-                  if (!segment.isAnEndpoint(nextInter))
-                    nextMySplitter = nextInter;
+                  if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
                   if (!nextSeg.isAnEndpoint(nextInter)) {
                     const newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
                     for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
               }
               if (prevMySplitter !== null || nextMySplitter !== null) {
                 let mySplitter = null;
-                if (prevMySplitter === null)
-                  mySplitter = nextMySplitter;
-                else if (nextMySplitter === null)
-                  mySplitter = prevMySplitter;
+                if (prevMySplitter === null) mySplitter = nextMySplitter;
+                else if (nextMySplitter === null) mySplitter = prevMySplitter;
                 else {
                   const cmpSplitters = SweepEvent2.comparePoints(prevMySplitter, nextMySplitter);
                   mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
             this.queue.remove(rightSE);
             const newEvents = seg.split(pt2);
             newEvents.push(rightSE);
-            if (seg.consumedBy === void 0)
-              this.tree.add(seg);
+            if (seg.consumedBy === void 0) this.tree.add(seg);
             return newEvents;
           }
         }
               const subject = multipolys[0];
               let i3 = 1;
               while (i3 < multipolys.length) {
-                if (getBboxOverlap2(multipolys[i3].bbox, subject.bbox) !== null)
-                  i3++;
-                else
-                  multipolys.splice(i3, 1);
+                if (getBboxOverlap2(multipolys[i3].bbox, subject.bbox) !== null) i3++;
+                else multipolys.splice(i3, 1);
               }
             }
             if (operation2.type === "intersection") {
               for (let i3 = 0, iMax = multipolys.length; i3 < iMax; i3++) {
                 const mpA = multipolys[i3];
                 for (let j2 = i3 + 1, jMax = multipolys.length; j2 < jMax; j2++) {
-                  if (getBboxOverlap2(mpA.bbox, multipolys[j2].bbox) === null)
-                    return [];
+                  if (getBboxOverlap2(mpA.bbox, multipolys[j2].bbox) === null) return [];
                 }
               }
             }
               const newEvents = sweepLine.process(evt);
               for (let i3 = 0, iMax = newEvents.length; i3 < iMax; i3++) {
                 const evt2 = newEvents[i3];
-                if (evt2.consumedBy === void 0)
-                  queue.insert(evt2);
+                if (evt2.consumedBy === void 0) queue.insert(evt2);
               }
               prevQueueSize = queue.size;
               node = queue.pop();
     Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
   }
   function consumed(body) {
-    if (body._noBody)
-      return;
+    if (body._noBody) return;
     if (body.bodyUsed) {
       return Promise.reject(new TypeError("Already read"));
     }
         var descriptor = props[i3];
         descriptor.enumerable = descriptor.enumerable || false;
         descriptor.configurable = true;
-        if ("value" in descriptor)
-          descriptor.writable = true;
+        if ("value" in descriptor) descriptor.writable = true;
         Object.defineProperty(target, descriptor.key, descriptor);
       }
     }
     function _createClass(Constructor, protoProps, staticProps) {
-      if (protoProps)
-        _defineProperties(Constructor.prototype, protoProps);
-      if (staticProps)
-        _defineProperties(Constructor, staticProps);
+      if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+      if (staticProps) _defineProperties(Constructor, staticProps);
       Object.defineProperty(Constructor, "prototype", {
         writable: false
       });
       Object.defineProperty(subClass, "prototype", {
         writable: false
       });
-      if (superClass)
-        _setPrototypeOf(subClass, superClass);
+      if (superClass) _setPrototypeOf(subClass, superClass);
     }
     function _getPrototypeOf(o2) {
       _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf2(o3) {
       return _setPrototypeOf(o2, p2);
     }
     function _isNativeReflectConstruct() {
-      if (typeof Reflect === "undefined" || !Reflect.construct)
-        return false;
-      if (Reflect.construct.sham)
-        return false;
-      if (typeof Proxy === "function")
-        return true;
+      if (typeof Reflect === "undefined" || !Reflect.construct) return false;
+      if (Reflect.construct.sham) return false;
+      if (typeof Proxy === "function") return true;
       try {
         Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {
         }));
     function _superPropBase(object, property) {
       while (!Object.prototype.hasOwnProperty.call(object, property)) {
         object = _getPrototypeOf(object);
-        if (object === null)
-          break;
+        if (object === null) break;
       }
       return object;
     }
       } else {
         _get = function _get2(target, property, receiver) {
           var base = _superPropBase(target, property);
-          if (!base)
-            return;
+          if (!base) return;
           var desc = Object.getOwnPropertyDescriptor(base, property);
           if (desc.get) {
             return desc.get.call(arguments.length < 3 ? target : receiver);
   // modules/index.js
   var modules_exports = {};
   __export(modules_exports, {
+    LANGUAGE_SUFFIX_REGEX: () => LANGUAGE_SUFFIX_REGEX,
     LocationManager: () => LocationManager,
     QAItem: () => QAItem,
     actionAddEntity: () => actionAddEntity,
     rendererMap: () => rendererMap,
     rendererPhotos: () => rendererPhotos,
     rendererTileLayer: () => rendererTileLayer,
-    serviceImproveOSM: () => improveOSM_default,
     serviceKartaview: () => kartaview_default,
     serviceKeepRight: () => keepRight_default,
     serviceMapRules: () => maprules_default,
     serviceOsm: () => osm_default,
     serviceOsmWikibase: () => osm_wikibase_default,
     serviceOsmose: () => osmose_default,
+    servicePanoramax: () => panoramax_default,
     serviceStreetside: () => streetside_default,
     serviceTaginfo: () => taginfo_default,
     serviceVectorTile: () => vector_tile_default,
     svgMidpoints: () => svgMidpoints,
     svgNotes: () => svgNotes,
     svgOsm: () => svgOsm,
+    svgPanoramaxImages: () => svgPanoramaxImages,
     svgPassiveVertex: () => svgPassiveVertex,
     svgPath: () => svgPath,
     svgPointTransform: () => svgPointTransform,
     uiFormFields: () => uiFormFields,
     uiFullScreen: () => uiFullScreen,
     uiGeolocate: () => uiGeolocate,
-    uiImproveOsmComments: () => uiImproveOsmComments,
-    uiImproveOsmDetails: () => uiImproveOsmDetails,
-    uiImproveOsmEditor: () => uiImproveOsmEditor,
-    uiImproveOsmHeader: () => uiImproveOsmHeader,
     uiInfo: () => uiInfo,
     uiInfoPanels: () => uiInfoPanels,
     uiInit: () => uiInit,
       return key;
     }
     function reverseValue(key, value, includeAbsolute, allTags) {
-      if (ignoreKey.test(key))
-        return value;
+      if (ignoreKey.test(key)) return value;
       if (turn_lanes.test(key)) {
         return value;
       } else if (key === "incline" && numeric.test(value)) {
         return onewayReplacements[value] || value;
       } else if (includeAbsolute && directionKey.test(key)) {
         return value.split(";").map((value2) => {
-          if (compassReplacements[value2])
-            return compassReplacements[value2];
+          if (compassReplacements[value2]) return compassReplacements[value2];
           var degrees3 = Number(value2);
           if (isFinite(degrees3)) {
             if (degrees3 < 180) {
     function reverseNodeTags(graph, nodeIDs) {
       for (var i3 = 0; i3 < nodeIDs.length; i3++) {
         var node = graph.hasEntity(nodeIDs[i3]);
-        if (!node || !Object.keys(node.tags).length)
-          continue;
+        if (!node || !Object.keys(node.tags).length) continue;
         var tags = {};
         for (var key in node.tags) {
           tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID, node.tags);
     };
     action.disabled = function(graph) {
       var entity = graph.hasEntity(entityID);
-      if (!entity || entity.type === "way")
-        return false;
+      if (!entity || entity.type === "way") return false;
       for (var key in entity.tags) {
         var value = entity.tags[key];
         if (reverseKey(key) !== key || reverseValue(key, value, true, entity.tags) !== value) {
     }
     function left(a2, x2, lo = 0, hi = a2.length) {
       if (lo < hi) {
-        if (compare1(x2, x2) !== 0)
-          return hi;
+        if (compare1(x2, x2) !== 0) return hi;
         do {
           const mid = lo + hi >>> 1;
-          if (compare2(a2[mid], x2) < 0)
-            lo = mid + 1;
-          else
-            hi = mid;
+          if (compare2(a2[mid], x2) < 0) lo = mid + 1;
+          else hi = mid;
         } while (lo < hi);
       }
       return lo;
     }
     function right(a2, x2, lo = 0, hi = a2.length) {
       if (lo < hi) {
-        if (compare1(x2, x2) !== 0)
-          return hi;
+        if (compare1(x2, x2) !== 0) return hi;
         do {
           const mid = lo + hi >>> 1;
-          if (compare2(a2[mid], x2) <= 0)
-            lo = mid + 1;
-          else
-            hi = mid;
+          if (compare2(a2[mid], x2) <= 0) lo = mid + 1;
+          else hi = mid;
         } while (lo < hi);
       }
       return lo;
       let i3 = 0;
       for (let j2 = 0; j2 < this._n && j2 < 32; j2++) {
         const y2 = p2[j2], hi = x2 + y2, lo = Math.abs(x2) < Math.abs(y2) ? x2 - (hi - y2) : y2 - (hi - x2);
-        if (lo)
-          p2[i3++] = lo;
+        if (lo) p2[i3++] = lo;
         x2 = hi;
       }
       p2[i3] = x2;
           y2 = p2[--n3];
           hi = x2 + y2;
           lo = y2 - (hi - x2);
-          if (lo)
-            break;
+          if (lo) break;
         }
         if (n3 > 0 && (lo < 0 && p2[n3 - 1] < 0 || lo > 0 && p2[n3 - 1] > 0)) {
           y2 = lo * 2;
           x2 = hi + y2;
-          if (y2 == x2 - hi)
-            hi = x2;
+          if (y2 == x2 - hi) hi = x2;
         }
       }
       return hi;
 
   // node_modules/d3-array/src/sort.js
   function compareDefined(compare2 = ascending) {
-    if (compare2 === ascending)
-      return ascendingDefined;
-    if (typeof compare2 !== "function")
-      throw new TypeError("compare is not a function");
+    if (compare2 === ascending) return ascendingDefined;
+    if (typeof compare2 !== "function") throw new TypeError("compare is not a function");
     return (a2, b2) => {
       const x2 = compare2(a2, b2);
-      if (x2 || x2 === 0)
-        return x2;
+      if (x2 || x2 === 0) return x2;
       return (compare2(b2, b2) === 0) - (compare2(a2, a2) === 0);
     };
   }
   function ticks(start2, stop, count) {
     var reverse, i3 = -1, n3, ticks2, step;
     stop = +stop, start2 = +start2, count = +count;
-    if (start2 === stop && count > 0)
-      return [start2];
-    if (reverse = stop < start2)
-      n3 = start2, start2 = stop, stop = n3;
-    if ((step = tickIncrement(start2, stop, count)) === 0 || !isFinite(step))
-      return [];
+    if (start2 === stop && count > 0) return [start2];
+    if (reverse = stop < start2) n3 = start2, start2 = stop, stop = n3;
+    if ((step = tickIncrement(start2, stop, count)) === 0 || !isFinite(step)) return [];
     if (step > 0) {
       let r0 = Math.round(start2 / step), r1 = Math.round(stop / step);
-      if (r0 * step < start2)
-        ++r0;
-      if (r1 * step > stop)
-        --r1;
+      if (r0 * step < start2) ++r0;
+      if (r1 * step > stop) --r1;
       ticks2 = new Array(n3 = r1 - r0 + 1);
-      while (++i3 < n3)
-        ticks2[i3] = (r0 + i3) * step;
+      while (++i3 < n3) ticks2[i3] = (r0 + i3) * step;
     } else {
       step = -step;
       let r0 = Math.round(start2 * step), r1 = Math.round(stop * step);
-      if (r0 / step < start2)
-        ++r0;
-      if (r1 / step > stop)
-        --r1;
+      if (r0 / step < start2) ++r0;
+      if (r1 / step > stop) --r1;
       ticks2 = new Array(n3 = r1 - r0 + 1);
-      while (++i3 < n3)
-        ticks2[i3] = (r0 + i3) / step;
+      while (++i3 < n3) ticks2[i3] = (r0 + i3) / step;
     }
-    if (reverse)
-      ticks2.reverse();
+    if (reverse) ticks2.reverse();
     return ticks2;
   }
   function tickIncrement(start2, stop, count) {
   }
   function tickStep(start2, stop, count) {
     var step0 = Math.abs(stop - start2) / Math.max(0, count), step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), error = step0 / step1;
-    if (error >= e10)
-      step1 *= 10;
-    else if (error >= e5)
-      step1 *= 5;
-    else if (error >= e2)
-      step1 *= 2;
+    if (error >= e10) step1 *= 10;
+    else if (error >= e5) step1 *= 5;
+    else if (error >= e2) step1 *= 2;
     return stop < start2 ? -step1 : step1;
   }
 
       let i3 = left;
       let j2 = right;
       swap(array2, left, k2);
-      if (compare2(array2[right], t2) > 0)
-        swap(array2, left, right);
+      if (compare2(array2[right], t2) > 0) swap(array2, left, right);
       while (i3 < j2) {
         swap(array2, i3, j2), ++i3, --j2;
-        while (compare2(array2[i3], t2) < 0)
-          ++i3;
-        while (compare2(array2[j2], t2) > 0)
-          --j2;
+        while (compare2(array2[i3], t2) < 0) ++i3;
+        while (compare2(array2[j2], t2) > 0) --j2;
       }
-      if (compare2(array2[left], t2) === 0)
-        swap(array2, left, j2);
-      else
-        ++j2, swap(array2, j2, right);
-      if (j2 <= k2)
-        left = j2 + 1;
-      if (k2 <= j2)
-        right = j2 - 1;
+      if (compare2(array2[left], t2) === 0) swap(array2, left, j2);
+      else ++j2, swap(array2, j2, right);
+      if (j2 <= k2) left = j2 + 1;
+      if (k2 <= j2) right = j2 - 1;
     }
     return array2;
   }
   // node_modules/d3-array/src/quantile.js
   function quantile(values, p2, valueof) {
     values = Float64Array.from(numbers(values, valueof));
-    if (!(n3 = values.length))
-      return;
-    if ((p2 = +p2) <= 0 || n3 < 2)
-      return min(values);
-    if (p2 >= 1)
-      return max(values);
+    if (!(n3 = values.length)) return;
+    if ((p2 = +p2) <= 0 || n3 < 2) return min(values);
+    if (p2 >= 1) return max(values);
     var n3, i3 = (n3 - 1) * p2, i0 = Math.floor(i3), value0 = max(quickselect(values, i0).subarray(0, i0 + 1)), value1 = min(values.subarray(i0 + 1));
     return value0 + (value1 - value0) * (i3 - i0);
   }
     let previous;
     let first = false;
     for (const value of values) {
-      if (first)
-        pairs2.push(pairof(previous, value));
+      if (first) pairs2.push(pairof(previous, value));
       previous = value;
       first = true;
     }
     },
     FeatureCollection: function(object, stream) {
       var features = object.features, i3 = -1, n3 = features.length;
-      while (++i3 < n3)
-        streamGeometry(features[i3].geometry, stream);
+      while (++i3 < n3) streamGeometry(features[i3].geometry, stream);
     }
   };
   var streamGeometryType = {
     },
     MultiPoint: function(object, stream) {
       var coordinates = object.coordinates, i3 = -1, n3 = coordinates.length;
-      while (++i3 < n3)
-        object = coordinates[i3], stream.point(object[0], object[1], object[2]);
+      while (++i3 < n3) object = coordinates[i3], stream.point(object[0], object[1], object[2]);
     },
     LineString: function(object, stream) {
       streamLine(object.coordinates, stream, 0);
     },
     MultiLineString: function(object, stream) {
       var coordinates = object.coordinates, i3 = -1, n3 = coordinates.length;
-      while (++i3 < n3)
-        streamLine(coordinates[i3], stream, 0);
+      while (++i3 < n3) streamLine(coordinates[i3], stream, 0);
     },
     Polygon: function(object, stream) {
       streamPolygon(object.coordinates, stream);
     },
     MultiPolygon: function(object, stream) {
       var coordinates = object.coordinates, i3 = -1, n3 = coordinates.length;
-      while (++i3 < n3)
-        streamPolygon(coordinates[i3], stream);
+      while (++i3 < n3) streamPolygon(coordinates[i3], stream);
     },
     GeometryCollection: function(object, stream) {
       var geometries = object.geometries, i3 = -1, n3 = geometries.length;
-      while (++i3 < n3)
-        streamGeometry(geometries[i3], stream);
+      while (++i3 < n3) streamGeometry(geometries[i3], stream);
     }
   };
   function streamLine(coordinates, stream, closed) {
     var i3 = -1, n3 = coordinates.length - closed, coordinate;
     stream.lineStart();
-    while (++i3 < n3)
-      coordinate = coordinates[i3], stream.point(coordinate[0], coordinate[1], coordinate[2]);
+    while (++i3 < n3) coordinate = coordinates[i3], stream.point(coordinate[0], coordinate[1], coordinate[2]);
     stream.lineEnd();
   }
   function streamPolygon(coordinates, stream) {
     var i3 = -1, n3 = coordinates.length;
     stream.polygonStart();
-    while (++i3 < n3)
-      streamLine(coordinates[i3], stream, 1);
+    while (++i3 < n3) streamLine(coordinates[i3], stream, 1);
     stream.polygonEnd();
   }
   function stream_default(object, stream) {
       boundsStream.point = boundsPoint;
       boundsStream.lineStart = boundsLineStart;
       boundsStream.lineEnd = boundsLineEnd;
-      if (areaRingSum < 0)
-        lambda02 = -(lambda1 = 180), phi0 = -(phi1 = 90);
-      else if (deltaSum > epsilon)
-        phi1 = 90;
-      else if (deltaSum < -epsilon)
-        phi0 = -90;
+      if (areaRingSum < 0) lambda02 = -(lambda1 = 180), phi0 = -(phi1 = 90);
+      else if (deltaSum > epsilon) phi1 = 90;
+      else if (deltaSum < -epsilon) phi0 = -90;
       range2[0] = lambda02, range2[1] = lambda1;
     },
     sphere: function() {
   };
   function boundsPoint(lambda, phi) {
     ranges.push(range2 = [lambda02 = lambda, lambda1 = lambda]);
-    if (phi < phi0)
-      phi0 = phi;
-    if (phi > phi1)
-      phi1 = phi;
+    if (phi < phi0) phi0 = phi;
+    if (phi > phi1) phi1 = phi;
   }
   function linePoint(lambda, phi) {
     var p2 = cartesian([lambda * radians, phi * radians]);
       var delta = lambda - lambda2, sign2 = delta > 0 ? 1 : -1, lambdai = inflection[0] * degrees * sign2, phii, antimeridian = abs(delta) > 180;
       if (antimeridian ^ (sign2 * lambda2 < lambdai && lambdai < sign2 * lambda)) {
         phii = inflection[1] * degrees;
-        if (phii > phi1)
-          phi1 = phii;
+        if (phii > phi1) phi1 = phii;
       } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign2 * lambda2 < lambdai && lambdai < sign2 * lambda)) {
         phii = -inflection[1] * degrees;
-        if (phii < phi0)
-          phi0 = phii;
+        if (phii < phi0) phi0 = phii;
       } else {
-        if (phi < phi0)
-          phi0 = phi;
-        if (phi > phi1)
-          phi1 = phi;
+        if (phi < phi0) phi0 = phi;
+        if (phi > phi1) phi1 = phi;
       }
       if (antimeridian) {
         if (lambda < lambda2) {
-          if (angle(lambda02, lambda) > angle(lambda02, lambda1))
-            lambda1 = lambda;
+          if (angle(lambda02, lambda) > angle(lambda02, lambda1)) lambda1 = lambda;
         } else {
-          if (angle(lambda, lambda1) > angle(lambda02, lambda1))
-            lambda02 = lambda;
+          if (angle(lambda, lambda1) > angle(lambda02, lambda1)) lambda02 = lambda;
         }
       } else {
         if (lambda1 >= lambda02) {
-          if (lambda < lambda02)
-            lambda02 = lambda;
-          if (lambda > lambda1)
-            lambda1 = lambda;
+          if (lambda < lambda02) lambda02 = lambda;
+          if (lambda > lambda1) lambda1 = lambda;
         } else {
           if (lambda > lambda2) {
-            if (angle(lambda02, lambda) > angle(lambda02, lambda1))
-              lambda1 = lambda;
+            if (angle(lambda02, lambda) > angle(lambda02, lambda1)) lambda1 = lambda;
           } else {
-            if (angle(lambda, lambda1) > angle(lambda02, lambda1))
-              lambda02 = lambda;
+            if (angle(lambda, lambda1) > angle(lambda02, lambda1)) lambda02 = lambda;
           }
         }
       }
     } else {
       ranges.push(range2 = [lambda02 = lambda, lambda1 = lambda]);
     }
-    if (phi < phi0)
-      phi0 = phi;
-    if (phi > phi1)
-      phi1 = phi;
+    if (phi < phi0) phi0 = phi;
+    if (phi > phi1) phi1 = phi;
     p0 = p2, lambda2 = lambda;
   }
   function boundsLineStart() {
   function boundsRingEnd() {
     boundsRingPoint(lambda002, phi002);
     areaStream.lineEnd();
-    if (abs(deltaSum) > epsilon)
-      lambda02 = -(lambda1 = 180);
+    if (abs(deltaSum) > epsilon) lambda02 = -(lambda1 = 180);
     range2[0] = lambda02, range2[1] = lambda1;
     p0 = null;
   }
       for (i3 = 1, a2 = ranges[0], merged = [a2]; i3 < n3; ++i3) {
         b2 = ranges[i3];
         if (rangeContains(a2, b2[0]) || rangeContains(a2, b2[1])) {
-          if (angle(a2[0], b2[1]) > angle(a2[0], a2[1]))
-            a2[1] = b2[1];
-          if (angle(b2[0], a2[1]) > angle(a2[0], a2[1]))
-            a2[0] = b2[0];
+          if (angle(a2[0], b2[1]) > angle(a2[0], a2[1])) a2[1] = b2[1];
+          if (angle(b2[0], a2[1]) > angle(a2[0], a2[1])) a2[0] = b2[0];
         } else {
           merged.push(a2 = b2);
         }
       }
       for (deltaMax = -Infinity, n3 = merged.length - 1, i3 = 0, a2 = merged[n3]; i3 <= n3; a2 = b2, ++i3) {
         b2 = merged[i3];
-        if ((delta = angle(a2[1], b2[0])) > deltaMax)
-          deltaMax = delta, lambda02 = b2[0], lambda1 = a2[1];
+        if ((delta = angle(a2[1], b2[0])) > deltaMax) deltaMax = delta, lambda02 = b2[0], lambda1 = a2[1];
       }
     }
     ranges = range2 = null;
     function compose(x2, y2) {
       return x2 = a2(x2, y2), b2(x2[0], x2[1]);
     }
-    if (a2.invert && b2.invert)
-      compose.invert = function(x2, y2) {
-        return x2 = b2.invert(x2, y2), x2 && a2.invert(x2[0], x2[1]);
-      };
+    if (a2.invert && b2.invert) compose.invert = function(x2, y2) {
+      return x2 = b2.invert(x2, y2), x2 && a2.invert(x2[0], x2[1]);
+    };
     return compose;
   }
 
 
   // node_modules/d3-geo/src/circle.js
   function circleStream(stream, radius, delta, direction, t0, t1) {
-    if (!delta)
-      return;
+    if (!delta) return;
     var cosRadius = cos(radius), sinRadius = sin(radius), step = direction * delta;
     if (t0 == null) {
       t0 = radius + direction * tau;
     } else {
       t0 = circleRadius(cosRadius, t0);
       t1 = circleRadius(cosRadius, t1);
-      if (direction > 0 ? t0 < t1 : t0 > t1)
-        t0 += direction * tau;
+      if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
     }
-    for (var point2, t2 = t0; direction > 0 ? t2 > t1 : t2 < t1; t2 -= step) {
-      point2 = spherical([cosRadius, -sinRadius * cos(t2), -sinRadius * sin(t2)]);
-      stream.point(point2[0], point2[1]);
+    for (var point, t2 = t0; direction > 0 ? t2 > t1 : t2 < t1; t2 -= step) {
+      point = spherical([cosRadius, -sinRadius * cos(t2), -sinRadius * sin(t2)]);
+      stream.point(point[0], point[1]);
     }
   }
-  function circleRadius(cosRadius, point2) {
-    point2 = cartesian(point2), point2[0] -= cosRadius;
-    cartesianNormalizeInPlace(point2);
-    var radius = acos(-point2[1]);
-    return ((-point2[2] < 0 ? -radius : radius) + tau - epsilon) % tau;
+  function circleRadius(cosRadius, point) {
+    point = cartesian(point), point[0] -= cosRadius;
+    cartesianNormalizeInPlace(point);
+    var radius = acos(-point[1]);
+    return ((-point[2] < 0 ? -radius : radius) + tau - epsilon) % tau;
   }
 
   // node_modules/d3-geo/src/clip/buffer.js
       },
       lineEnd: noop,
       rejoin: function() {
-        if (lines.length > 1)
-          lines.push(lines.pop().concat(lines.shift()));
+        if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
       },
       result: function() {
         var result = lines;
   }
 
   // node_modules/d3-geo/src/clip/rejoin.js
-  function Intersection(point2, points, other, entry) {
-    this.x = point2;
+  function Intersection(point, points, other, entry) {
+    this.x = point;
     this.z = points;
     this.o = other;
     this.e = entry;
   function rejoin_default(segments, compareIntersection2, startInside, interpolate, stream) {
     var subject = [], clip = [], i3, n3;
     segments.forEach(function(segment) {
-      if ((n4 = segment.length - 1) <= 0)
-        return;
+      if ((n4 = segment.length - 1) <= 0) return;
       var n4, p02 = segment[0], p1 = segment[n4], x2;
       if (pointEqual_default(p02, p1)) {
         if (!p02[2] && !p1[2]) {
           stream.lineStart();
-          for (i3 = 0; i3 < n4; ++i3)
-            stream.point((p02 = segment[i3])[0], p02[1]);
+          for (i3 = 0; i3 < n4; ++i3) stream.point((p02 = segment[i3])[0], p02[1]);
           stream.lineEnd();
           return;
         }
       subject.push(x2 = new Intersection(p1, segment, null, false));
       clip.push(x2.o = new Intersection(p1, null, x2, true));
     });
-    if (!subject.length)
-      return;
+    if (!subject.length) return;
     clip.sort(compareIntersection2);
     link(subject);
     link(clip);
     for (i3 = 0, n3 = clip.length; i3 < n3; ++i3) {
       clip[i3].e = startInside = !startInside;
     }
-    var start2 = subject[0], points, point2;
+    var start2 = subject[0], points, point;
     while (1) {
       var current = start2, isSubject = true;
-      while (current.v)
-        if ((current = current.n) === start2)
-          return;
+      while (current.v) if ((current = current.n) === start2) return;
       points = current.z;
       stream.lineStart();
       do {
         current.v = current.o.v = true;
         if (current.e) {
           if (isSubject) {
-            for (i3 = 0, n3 = points.length; i3 < n3; ++i3)
-              stream.point((point2 = points[i3])[0], point2[1]);
+            for (i3 = 0, n3 = points.length; i3 < n3; ++i3) stream.point((point = points[i3])[0], point[1]);
           } else {
             interpolate(current.x, current.n.x, 1, stream);
           }
         } else {
           if (isSubject) {
             points = current.p.z;
-            for (i3 = points.length - 1; i3 >= 0; --i3)
-              stream.point((point2 = points[i3])[0], point2[1]);
+            for (i3 = points.length - 1; i3 >= 0; --i3) stream.point((point = points[i3])[0], point[1]);
           } else {
             interpolate(current.x, current.p.x, -1, stream);
           }
     }
   }
   function link(array2) {
-    if (!(n3 = array2.length))
-      return;
+    if (!(n3 = array2.length)) return;
     var n3, i3 = 0, a2 = array2[0], b2;
     while (++i3 < n3) {
       a2.n = b2 = array2[i3];
   }
 
   // node_modules/d3-geo/src/polygonContains.js
-  function longitude(point2) {
-    return abs(point2[0]) <= pi ? point2[0] : sign(point2[0]) * ((abs(point2[0]) + pi) % tau - pi);
+  function longitude(point) {
+    return abs(point[0]) <= pi ? point[0] : sign(point[0]) * ((abs(point[0]) + pi) % tau - pi);
   }
-  function polygonContains_default(polygon2, point2) {
-    var lambda = longitude(point2), phi = point2[1], sinPhi = sin(phi), normal = [sin(lambda), -cos(lambda), 0], angle2 = 0, winding = 0;
+  function polygonContains_default(polygon2, point) {
+    var lambda = longitude(point), phi = point[1], sinPhi = sin(phi), normal = [sin(lambda), -cos(lambda), 0], angle2 = 0, winding = 0;
     var sum = new Adder();
-    if (sinPhi === 1)
-      phi = halfPi + epsilon;
-    else if (sinPhi === -1)
-      phi = -halfPi - epsilon;
+    if (sinPhi === 1) phi = halfPi + epsilon;
+    else if (sinPhi === -1) phi = -halfPi - epsilon;
     for (var i3 = 0, n3 = polygon2.length; i3 < n3; ++i3) {
-      if (!(m2 = (ring = polygon2[i3]).length))
-        continue;
+      if (!(m2 = (ring = polygon2[i3]).length)) continue;
       var ring, m2, point0 = ring[m2 - 1], lambda04 = longitude(point0), phi02 = point0[1] / 2 + quarterPi, sinPhi03 = sin(phi02), cosPhi03 = cos(phi02);
       for (var j2 = 0; j2 < m2; ++j2, lambda04 = lambda12, sinPhi03 = sinPhi1, cosPhi03 = cosPhi1, point0 = point1) {
         var point1 = ring[j2], lambda12 = longitude(point1), phi12 = point1[1] / 2 + quarterPi, sinPhi1 = sin(phi12), cosPhi1 = cos(phi12), delta = lambda12 - lambda04, sign2 = delta >= 0 ? 1 : -1, absDelta = sign2 * delta, antimeridian = absDelta > pi, k2 = sinPhi03 * sinPhi1;
     return function(sink) {
       var line = clipLine(sink), ringBuffer = buffer_default(), ringSink = clipLine(ringBuffer), polygonStarted = false, polygon2, segments, ring;
       var clip = {
-        point: point2,
+        point,
         lineStart,
         lineEnd,
         polygonStart: function() {
           polygon2 = [];
         },
         polygonEnd: function() {
-          clip.point = point2;
+          clip.point = point;
           clip.lineStart = lineStart;
           clip.lineEnd = lineEnd;
           segments = merge(segments);
           var startInside = polygonContains_default(polygon2, start2);
           if (segments.length) {
-            if (!polygonStarted)
-              sink.polygonStart(), polygonStarted = true;
+            if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
             rejoin_default(segments, compareIntersection, startInside, interpolate, sink);
           } else if (startInside) {
-            if (!polygonStarted)
-              sink.polygonStart(), polygonStarted = true;
+            if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
             sink.lineStart();
             interpolate(null, null, 1, sink);
             sink.lineEnd();
           }
-          if (polygonStarted)
-            sink.polygonEnd(), polygonStarted = false;
+          if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
           segments = polygon2 = null;
         },
         sphere: function() {
           sink.polygonEnd();
         }
       };
-      function point2(lambda, phi) {
-        if (pointVisible(lambda, phi))
-          sink.point(lambda, phi);
+      function point(lambda, phi) {
+        if (pointVisible(lambda, phi)) sink.point(lambda, phi);
       }
       function pointLine(lambda, phi) {
         line.point(lambda, phi);
         line.lineStart();
       }
       function lineEnd() {
-        clip.point = point2;
+        clip.point = point;
         line.lineEnd();
       }
       function pointRing(lambda, phi) {
       function ringEnd() {
         pointRing(ring[0][0], ring[0][1]);
         ringSink.lineEnd();
-        var clean2 = ringSink.clean(), ringSegments = ringBuffer.result(), i3, n3 = ringSegments.length, m2, segment, point3;
+        var clean2 = ringSink.clean(), ringSegments = ringBuffer.result(), i3, n3 = ringSegments.length, m2, segment, point2;
         ring.pop();
         polygon2.push(ring);
         ring = null;
-        if (!n3)
-          return;
+        if (!n3) return;
         if (clean2 & 1) {
           segment = ringSegments[0];
           if ((m2 = segment.length - 1) > 0) {
-            if (!polygonStarted)
-              sink.polygonStart(), polygonStarted = true;
+            if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
             sink.lineStart();
-            for (i3 = 0; i3 < m2; ++i3)
-              sink.point((point3 = segment[i3])[0], point3[1]);
+            for (i3 = 0; i3 < m2; ++i3) sink.point((point2 = segment[i3])[0], point2[1]);
             sink.lineEnd();
           }
           return;
         }
-        if (n3 > 1 && clean2 & 2)
-          ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
+        if (n3 > 1 && clean2 & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
         segments.push(ringSegments.filter(validSegment));
       }
       return clip;
           stream.point(lambda12, phi02);
           clean2 = 0;
         } else if (sign0 !== sign1 && delta >= pi) {
-          if (abs(lambda04 - sign0) < epsilon)
-            lambda04 -= sign0 * epsilon;
-          if (abs(lambda12 - sign1) < epsilon)
-            lambda12 -= sign1 * epsilon;
+          if (abs(lambda04 - sign0) < epsilon) lambda04 -= sign0 * epsilon;
+          if (abs(lambda12 - sign1) < epsilon) lambda12 -= sign1 * epsilon;
           phi02 = clipAntimeridianIntersect(lambda04, phi02, lambda12, phi12);
           stream.point(sign0, phi02);
           stream.lineEnd();
         },
         point: function(lambda, phi) {
           var point1 = [lambda, phi], point2, v2 = visible(lambda, phi), c2 = smallRadius ? v2 ? 0 : code(lambda, phi) : v2 ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
-          if (!point0 && (v00 = v0 = v2))
-            stream.lineStart();
+          if (!point0 && (v00 = v0 = v2)) stream.lineStart();
           if (v2 !== v0) {
             point2 = intersect2(point0, point1);
             if (!point2 || pointEqual_default(point0, point2) || pointEqual_default(point1, point2))
           point0 = point1, v0 = v2, c0 = c2;
         },
         lineEnd: function() {
-          if (v0)
-            stream.lineEnd();
+          if (v0) stream.lineEnd();
           point0 = null;
         },
         // Rejoin first and last segments if there were intersections and the first
     function intersect2(a2, b2, two) {
       var pa = cartesian(a2), pb = cartesian(b2);
       var n1 = [1, 0, 0], n22 = cartesianCross(pa, pb), n2n2 = cartesianDot(n22, n22), n1n2 = n22[0], determinant = n2n2 - n1n2 * n1n2;
-      if (!determinant)
-        return !two && a2;
+      if (!determinant) return !two && a2;
       var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = cartesianCross(n1, n22), A2 = cartesianScale(n1, c1), B2 = cartesianScale(n22, c2);
       cartesianAddInPlace(A2, B2);
       var u2 = n1xn2, w2 = cartesianDot(A2, u2), uu = cartesianDot(u2, u2), t2 = w2 * w2 - uu * (cartesianDot(A2, A2) - 1);
-      if (t2 < 0)
-        return;
+      if (t2 < 0) return;
       var t3 = sqrt(t2), q2 = cartesianScale(u2, (-w2 - t3) / uu);
       cartesianAddInPlace(q2, A2);
       q2 = spherical(q2);
-      if (!two)
-        return q2;
+      if (!two) return q2;
       var lambda04 = a2[0], lambda12 = b2[0], phi02 = a2[1], phi12 = b2[1], z2;
-      if (lambda12 < lambda04)
-        z2 = lambda04, lambda04 = lambda12, lambda12 = z2;
+      if (lambda12 < lambda04) z2 = lambda04, lambda04 = lambda12, lambda12 = z2;
       var delta2 = lambda12 - lambda04, polar = abs(delta2 - pi) < epsilon, meridian = polar || delta2 < epsilon;
-      if (!polar && phi12 < phi02)
-        z2 = phi02, phi02 = phi12, phi12 = z2;
+      if (!polar && phi12 < phi02) z2 = phi02, phi02 = phi12, phi12 = z2;
       if (meridian ? polar ? phi02 + phi12 > 0 ^ q2[1] < (abs(q2[0] - lambda04) < epsilon ? phi02 : phi12) : phi02 <= q2[1] && q2[1] <= phi12 : delta2 > pi ^ (lambda04 <= q2[0] && q2[0] <= lambda12)) {
         var q1 = cartesianScale(u2, (-w2 + t3) / uu);
         cartesianAddInPlace(q1, A2);
     }
     function code(lambda, phi) {
       var r2 = smallRadius ? radius : pi - radius, code2 = 0;
-      if (lambda < -r2)
-        code2 |= 1;
-      else if (lambda > r2)
-        code2 |= 2;
-      if (phi < -r2)
-        code2 |= 4;
-      else if (phi > r2)
-        code2 |= 8;
+      if (lambda < -r2) code2 |= 1;
+      else if (lambda > r2) code2 |= 2;
+      if (phi < -r2) code2 |= 4;
+      else if (phi > r2) code2 |= 8;
       return code2;
     }
     return clip_default(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
   function line_default(a2, b2, x05, y05, x12, y12) {
     var ax = a2[0], ay = a2[1], bx = b2[0], by = b2[1], t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r2;
     r2 = x05 - ax;
-    if (!dx && r2 > 0)
-      return;
+    if (!dx && r2 > 0) return;
     r2 /= dx;
     if (dx < 0) {
-      if (r2 < t0)
-        return;
-      if (r2 < t1)
-        t1 = r2;
+      if (r2 < t0) return;
+      if (r2 < t1) t1 = r2;
     } else if (dx > 0) {
-      if (r2 > t1)
-        return;
-      if (r2 > t0)
-        t0 = r2;
+      if (r2 > t1) return;
+      if (r2 > t0) t0 = r2;
     }
     r2 = x12 - ax;
-    if (!dx && r2 < 0)
-      return;
+    if (!dx && r2 < 0) return;
     r2 /= dx;
     if (dx < 0) {
-      if (r2 > t1)
-        return;
-      if (r2 > t0)
-        t0 = r2;
+      if (r2 > t1) return;
+      if (r2 > t0) t0 = r2;
     } else if (dx > 0) {
-      if (r2 < t0)
-        return;
-      if (r2 < t1)
-        t1 = r2;
+      if (r2 < t0) return;
+      if (r2 < t1) t1 = r2;
     }
     r2 = y05 - ay;
-    if (!dy && r2 > 0)
-      return;
+    if (!dy && r2 > 0) return;
     r2 /= dy;
     if (dy < 0) {
-      if (r2 < t0)
-        return;
-      if (r2 < t1)
-        t1 = r2;
+      if (r2 < t0) return;
+      if (r2 < t1) t1 = r2;
     } else if (dy > 0) {
-      if (r2 > t1)
-        return;
-      if (r2 > t0)
-        t0 = r2;
+      if (r2 > t1) return;
+      if (r2 > t0) t0 = r2;
     }
     r2 = y12 - ay;
-    if (!dy && r2 < 0)
-      return;
+    if (!dy && r2 < 0) return;
     r2 /= dy;
     if (dy < 0) {
-      if (r2 > t1)
-        return;
-      if (r2 > t0)
-        t0 = r2;
+      if (r2 > t1) return;
+      if (r2 > t0) t0 = r2;
     } else if (dy > 0) {
-      if (r2 < t0)
-        return;
-      if (r2 < t1)
-        t1 = r2;
+      if (r2 < t0) return;
+      if (r2 < t1) t1 = r2;
     }
-    if (t0 > 0)
-      a2[0] = ax + t0 * dx, a2[1] = ay + t0 * dy;
-    if (t1 < 1)
-      b2[0] = ax + t1 * dx, b2[1] = ay + t1 * dy;
+    if (t0 > 0) a2[0] = ax + t0 * dx, a2[1] = ay + t0 * dy;
+    if (t1 < 1) b2[0] = ax + t1 * dx, b2[1] = ay + t1 * dy;
     return true;
   }
 
     return function(stream) {
       var activeStream = stream, bufferStream = buffer_default(), segments, polygon2, ring, x__, y__, v__, x_, y_, v_, first, clean2;
       var clipStream = {
-        point: point2,
+        point,
         lineStart,
         lineEnd,
         polygonStart,
         polygonEnd
       };
-      function point2(x2, y2) {
-        if (visible(x2, y2))
-          activeStream.point(x2, y2);
+      function point(x2, y2) {
+        if (visible(x2, y2)) activeStream.point(x2, y2);
       }
       function polygonInside() {
         var winding = 0;
         for (var i3 = 0, n3 = polygon2.length; i3 < n3; ++i3) {
-          for (var ring2 = polygon2[i3], j2 = 1, m2 = ring2.length, point3 = ring2[0], a0, a1, b0 = point3[0], b1 = point3[1]; j2 < m2; ++j2) {
-            a0 = b0, a1 = b1, point3 = ring2[j2], b0 = point3[0], b1 = point3[1];
+          for (var ring2 = polygon2[i3], j2 = 1, m2 = ring2.length, point2 = ring2[0], a0, a1, b0 = point2[0], b1 = point2[1]; j2 < m2; ++j2) {
+            a0 = b0, a1 = b1, point2 = ring2[j2], b0 = point2[0], b1 = point2[1];
             if (a1 <= y12) {
-              if (b1 > y12 && (b0 - a0) * (y12 - a1) > (b1 - a1) * (x05 - a0))
-                ++winding;
+              if (b1 > y12 && (b0 - a0) * (y12 - a1) > (b1 - a1) * (x05 - a0)) ++winding;
             } else {
-              if (b1 <= y12 && (b0 - a0) * (y12 - a1) < (b1 - a1) * (x05 - a0))
-                --winding;
+              if (b1 <= y12 && (b0 - a0) * (y12 - a1) < (b1 - a1) * (x05 - a0)) --winding;
             }
           }
         }
       }
       function lineStart() {
         clipStream.point = linePoint2;
-        if (polygon2)
-          polygon2.push(ring = []);
+        if (polygon2) polygon2.push(ring = []);
         first = true;
         v_ = false;
         x_ = y_ = NaN;
       function lineEnd() {
         if (segments) {
           linePoint2(x__, y__);
-          if (v__ && v_)
-            bufferStream.rejoin();
+          if (v__ && v_) bufferStream.rejoin();
           segments.push(bufferStream.result());
         }
-        clipStream.point = point2;
-        if (v_)
-          activeStream.lineEnd();
+        clipStream.point = point;
+        if (v_) activeStream.lineEnd();
       }
       function linePoint2(x2, y2) {
         var v2 = visible(x2, y2);
-        if (polygon2)
-          ring.push([x2, y2]);
+        if (polygon2) ring.push([x2, y2]);
         if (first) {
           x__ = x2, y__ = y2, v__ = v2;
           first = false;
             activeStream.point(x2, y2);
           }
         } else {
-          if (v2 && v_)
-            activeStream.point(x2, y2);
+          if (v2 && v_) activeStream.point(x2, y2);
           else {
             var a2 = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))], b2 = [x2 = Math.max(clipMin, Math.min(clipMax, x2)), y2 = Math.max(clipMin, Math.min(clipMax, y2))];
             if (line_default(a2, b2, x05, y05, x12, y12)) {
                 activeStream.point(a2[0], a2[1]);
               }
               activeStream.point(b2[0], b2[1]);
-              if (!v2)
-                activeStream.lineEnd();
+              if (!v2) activeStream.lineEnd();
               clean2 = false;
             } else if (v2) {
               activeStream.lineStart();
     }
   };
   function boundsPoint2(x2, y2) {
-    if (x2 < x02)
-      x02 = x2;
-    if (x2 > x1)
-      x1 = x2;
-    if (y2 < y02)
-      y02 = y2;
-    if (y2 > y1)
-      y1 = y2;
+    if (x2 < x02) x02 = x2;
+    if (x2 > x1) x1 = x2;
+    if (y2 < y02) y02 = y2;
+    if (y2 > y1) y1 = y2;
   }
   var bounds_default2 = boundsStream2;
 
       this._point = 0;
     },
     lineEnd: function() {
-      if (this._line === 0)
-        this._context.closePath();
+      if (this._line === 0) this._context.closePath();
       this._point = NaN;
     },
     point: function(x2, y2) {
       lengthStream2.point = lengthPointFirst2;
     },
     lineEnd: function() {
-      if (lengthRing)
-        lengthPoint2(x003, y003);
+      if (lengthRing) lengthPoint2(x003, y003);
       lengthStream2.point = noop;
     },
     polygonStart: function() {
     _radius: 4.5,
     _circle: circle(4.5),
     pointRadius: function(_2) {
-      if ((_2 = +_2) !== this._radius)
-        this._radius = _2, this._circle = null;
+      if ((_2 = +_2) !== this._radius) this._radius = _2, this._circle = null;
       return this;
     },
     polygonStart: function() {
       this._point = 0;
     },
     lineEnd: function() {
-      if (this._line === 0)
-        this._string.push("Z");
+      if (this._line === 0) this._string.push("Z");
       this._point = NaN;
     },
     point: function(x2, y2) {
           break;
         }
         default: {
-          if (this._circle == null)
-            this._circle = circle(this._radius);
+          if (this._circle == null) this._circle = circle(this._radius);
           this._string.push("M", x2, ",", y2, this._circle);
           break;
         }
     var pointRadius = 4.5, projectionStream, contextStream;
     function path(object) {
       if (object) {
-        if (typeof pointRadius === "function")
-          contextStream.pointRadius(+pointRadius.apply(this, arguments));
+        if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
         stream_default(object, projectionStream(contextStream));
       }
       return contextStream.result();
       return arguments.length ? (projectionStream = _2 == null ? (projection2 = null, identity_default) : (projection2 = _2).stream, path) : projection2;
     };
     path.context = function(_2) {
-      if (!arguments.length)
-        return context;
+      if (!arguments.length) return context;
       contextStream = _2 == null ? (context = null, new PathString()) : new PathContext(context = _2);
-      if (typeof pointRadius !== "function")
-        contextStream.pointRadius(pointRadius);
+      if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
       return path;
     };
     path.pointRadius = function(_2) {
-      if (!arguments.length)
-        return pointRadius;
+      if (!arguments.length) return pointRadius;
       pointRadius = typeof _2 === "function" ? _2 : (contextStream.pointRadius(+_2), +_2);
       return path;
     };
   function transformer(methods2) {
     return function(stream) {
       var s2 = new TransformStream();
-      for (var key in methods2)
-        s2[key] = methods2[key];
+      for (var key in methods2) s2[key] = methods2[key];
       s2.stream = stream;
       return s2;
     };
   function fit(projection2, fitBounds, object) {
     var clip = projection2.clipExtent && projection2.clipExtent();
     projection2.scale(150).translate([0, 0]);
-    if (clip != null)
-      projection2.clipExtent(null);
+    if (clip != null) projection2.clipExtent(null);
     stream_default(object, projection2.stream(bounds_default2));
     fitBounds(bounds_default2.result());
-    if (clip != null)
-      projection2.clipExtent(clip);
+    if (clip != null) projection2.clipExtent(clip);
     return projection2;
   }
   function fitExtent(projection2, extent, object) {
     return function(stream) {
       var lambda003, x004, y004, a00, b00, c00, lambda04, x05, y05, a0, b0, c0;
       var resampleStream = {
-        point: point2,
+        point,
         lineStart,
         lineEnd,
         polygonStart: function() {
           resampleStream.lineStart = lineStart;
         }
       };
-      function point2(x2, y2) {
+      function point(x2, y2) {
         x2 = project(x2, y2);
         stream.point(x2[0], x2[1]);
       }
         stream.point(x05, y05);
       }
       function lineEnd() {
-        resampleStream.point = point2;
+        resampleStream.point = point;
         stream.lineEnd();
       }
       function ringStart() {
     return transform2;
   }
   function scaleTranslateRotate(k2, dx, dy, sx, sy, alpha) {
-    if (!alpha)
-      return scaleTranslate(k2, dx, dy, sx, sy);
+    if (!alpha) return scaleTranslate(k2, dx, dy, sx, sy);
     var cosAlpha = cos(alpha), sinAlpha = sin(alpha), a2 = cosAlpha * k2, b2 = sinAlpha * k2, ai = cosAlpha / k2, bi = sinAlpha / k2, ci = (sinAlpha * dy - cosAlpha * dx) / k2, fi = (sinAlpha * dx + cosAlpha * dy) / k2;
     function transform2(x2, y2) {
       x2 *= sx;
   }
   function projectionMutator(projectAt) {
     var project, k2 = 150, x2 = 480, y2 = 250, lambda = 0, phi = 0, deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, alpha = 0, sx = 1, sy = 1, theta = null, preclip = antimeridian_default, x05 = null, y05, x12, y12, postclip = identity_default, delta2 = 0.5, projectResample, projectTransform, projectRotateTransform, cache, cacheStream;
-    function projection2(point2) {
-      return projectRotateTransform(point2[0] * radians, point2[1] * radians);
+    function projection2(point) {
+      return projectRotateTransform(point[0] * radians, point[1] * radians);
     }
-    function invert(point2) {
-      point2 = projectRotateTransform.invert(point2[0], point2[1]);
-      return point2 && [point2[0] * degrees, point2[1] * degrees];
+    function invert(point) {
+      point = projectRotateTransform.invert(point[0], point[1]);
+      return point && [point[0] * degrees, point[1] * degrees];
     }
     projection2.stream = function(stream) {
       return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
     tileSize = tileSize || 256;
     return tileSize * Math.pow(2, z2) / TAU;
   }
-  function geoSphericalClosestNode(nodes, point2) {
+  function geoSphericalClosestNode(nodes, point) {
     var minDistance = Infinity, distance;
     var indexOfMin;
     for (var i3 in nodes) {
-      distance = geoSphericalDistance(nodes[i3].loc, point2);
+      distance = geoSphericalDistance(nodes[i3].loc, point);
       if (distance < minDistance) {
         minDistance = distance;
         indexOfMin = i3;
       return this[0][0] === obj[0][0] && this[0][1] === obj[0][1] && this[1][0] === obj[1][0] && this[1][1] === obj[1][1];
     },
     extend: function(obj) {
-      if (!(obj instanceof geoExtent))
-        obj = new geoExtent(obj);
+      if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
       return geoExtent(
         [Math.min(obj[0][0], this[0][0]), Math.min(obj[0][1], this[0][1])],
         [Math.max(obj[1][0], this[1][0]), Math.max(obj[1][1], this[1][1])]
       ];
     },
     contains: function(obj) {
-      if (!(obj instanceof geoExtent))
-        obj = new geoExtent(obj);
+      if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
       return obj[0][0] >= this[0][0] && obj[0][1] >= this[0][1] && obj[1][0] <= this[1][0] && obj[1][1] <= this[1][1];
     },
     intersects: function(obj) {
-      if (!(obj instanceof geoExtent))
-        obj = new geoExtent(obj);
+      if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
       return obj[0][0] <= this[1][0] && obj[0][1] <= this[1][1] && obj[1][0] >= this[0][0] && obj[1][1] >= this[0][1];
     },
     intersection: function(obj) {
-      if (!this.intersects(obj))
-        return new geoExtent();
+      if (!this.intersects(obj)) return new geoExtent();
       return new geoExtent(
         [Math.max(obj[0][0], this[0][0]), Math.max(obj[0][1], this[0][1])],
         [Math.min(obj[1][0], this[1][0]), Math.min(obj[1][1], this[1][1])]
       );
     },
     percentContainedIn: function(obj) {
-      if (!(obj instanceof geoExtent))
-        obj = new geoExtent(obj);
+      if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
       var a1 = this.intersection(obj).area();
       var a2 = this.area();
       if (a1 === Infinity || a2 === Infinity) {
     const n3 = points.length, indexes = [0, 1];
     let size = 2, i3;
     for (i3 = 2; i3 < n3; ++i3) {
-      while (size > 1 && cross_default(points[indexes[size - 2]], points[indexes[size - 1]], points[i3]) <= 0)
-        --size;
+      while (size > 1 && cross_default(points[indexes[size - 2]], points[indexes[size - 1]], points[i3]) <= 0) --size;
       indexes[size++] = i3;
     }
     return indexes.slice(0, size);
   }
   function hull_default(points) {
-    if ((n3 = points.length) < 3)
-      return null;
+    if ((n3 = points.length) < 3) return null;
     var i3, n3, sortedPoints = new Array(n3), flippedPoints = new Array(n3);
-    for (i3 = 0; i3 < n3; ++i3)
-      sortedPoints[i3] = [+points[i3][0], +points[i3][1], i3];
+    for (i3 = 0; i3 < n3; ++i3) sortedPoints[i3] = [+points[i3][0], +points[i3][1], i3];
     sortedPoints.sort(lexicographicOrder);
-    for (i3 = 0; i3 < n3; ++i3)
-      flippedPoints[i3] = [sortedPoints[i3][0], -sortedPoints[i3][1]];
+    for (i3 = 0; i3 < n3; ++i3) flippedPoints[i3] = [sortedPoints[i3][0], -sortedPoints[i3][1]];
     var upperIndexes = computeUpperHullIndexes(sortedPoints), lowerIndexes = computeUpperHullIndexes(flippedPoints);
     var skipLeft = lowerIndexes[0] === upperIndexes[0], skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1], hull = [];
-    for (i3 = upperIndexes.length - 1; i3 >= 0; --i3)
-      hull.push(points[sortedPoints[upperIndexes[i3]][2]]);
-    for (i3 = +skipLeft; i3 < lowerIndexes.length - skipRight; ++i3)
-      hull.push(points[sortedPoints[lowerIndexes[i3]][2]]);
+    for (i3 = upperIndexes.length - 1; i3 >= 0; --i3) hull.push(points[sortedPoints[upperIndexes[i3]][2]]);
+    for (i3 = +skipLeft; i3 < lowerIndexes.length - skipRight; ++i3) hull.push(points[sortedPoints[lowerIndexes[i3]][2]]);
     return hull;
   }
 
     return a2[0] === b2[0] && a2[1] === b2[1] || a2[0] === b2[1] && a2[1] === b2[0];
   }
   function geoRotate(points, angle2, around) {
-    return points.map(function(point2) {
-      var radial = geoVecSubtract(point2, around);
+    return points.map(function(point) {
+      var radial = geoVecSubtract(point, around);
       return [
         radial[0] * Math.cos(angle2) - radial[1] * Math.sin(angle2) + around[0],
         radial[0] * Math.sin(angle2) + radial[1] * Math.cos(angle2) + around[1]
       ];
     });
   }
-  function geoChooseEdge(nodes, point2, projection2, activeID) {
+  function geoChooseEdge(nodes, point, projection2, activeID) {
     var dist = geoVecLength;
     var points = nodes.map(function(n3) {
       return projection2(n3.loc);
     var idx;
     var loc;
     for (var i3 = 0; i3 < points.length - 1; i3++) {
-      if (ids[i3] === activeID || ids[i3 + 1] === activeID)
-        continue;
+      if (ids[i3] === activeID || ids[i3 + 1] === activeID) continue;
       var o2 = points[i3];
       var s2 = geoVecSubtract(points[i3 + 1], o2);
-      var v2 = geoVecSubtract(point2, o2);
+      var v2 = geoVecSubtract(point, o2);
       var proj = geoVecDot(v2, s2) / geoVecDot(s2, s2);
       var p2;
       if (proj < 0) {
       } else {
         p2 = [o2[0] + proj * s2[0], o2[1] + proj * s2[1]];
       }
-      var d2 = dist(p2, point2);
+      var d2 = dist(p2, point);
       if (d2 < min3) {
         min3 = d2;
         idx = i3 + 1;
     }
     return false;
   }
-  function geoPointInPolygon(point2, polygon2) {
-    var x2 = point2[0];
-    var y2 = point2[1];
+  function geoPointInPolygon(point, polygon2) {
+    var x2 = point[0];
+    var y2 = point[1];
     var inside = false;
     for (var i3 = 0, j2 = polygon2.length - 1; i3 < polygon2.length; j2 = i3++) {
       var xi = polygon2[i3][0];
       var xj = polygon2[j2][0];
       var yj = polygon2[j2][1];
       var intersect2 = yi > y2 !== yj > y2 && x2 < (xj - xi) * (y2 - yi) / (yj - yi) + xi;
-      if (intersect2)
-        inside = !inside;
+      if (intersect2) inside = !inside;
     }
     return inside;
   }
   function geoPolygonContainsPolygon(outer, inner) {
-    return inner.every(function(point2) {
-      return geoPointInPolygon(point2, outer);
+    return inner.every(function(point) {
+      return geoPointInPolygon(point, outer);
     });
   }
   function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
     function testPoints(outer2, inner2) {
-      return inner2.some(function(point2) {
-        return geoPointInPolygon(point2, outer2);
+      return inner2.some(function(point) {
+        return geoPointInPolygon(point, outer2);
       });
     }
     return testPoints(outer, inner) || !!checkSegments && geoPathHasIntersections(outer, inner);
       var c2 = i3 === hull.length - 1 ? hull[0] : hull[i3 + 1];
       var angle2 = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]);
       var poly = geoRotate(hull, -angle2, centroid);
-      var extent = poly.reduce(function(extent2, point2) {
-        return extent2.extend(geoExtent(point2));
+      var extent = poly.reduce(function(extent2, point) {
+        return extent2.extend(geoExtent(point));
       }, geoExtent());
       var area = extent.area();
       if (area < minArea) {
     }
     return length2;
   }
-  function geoViewportEdge(point2, dimensions) {
+  function geoViewportEdge(point, dimensions) {
     var pad2 = [80, 20, 50, 20];
     var x2 = 0;
     var y2 = 0;
-    if (point2[0] > dimensions[0] - pad2[1]) {
+    if (point[0] > dimensions[0] - pad2[1]) {
       x2 = -10;
     }
-    if (point2[0] < pad2[3]) {
+    if (point[0] < pad2[3]) {
       x2 = 10;
     }
-    if (point2[1] > dimensions[1] - pad2[2]) {
+    if (point[1] > dimensions[1] - pad2[2]) {
       y2 = -10;
     }
-    if (point2[1] < pad2[0]) {
+    if (point[1] < pad2[0]) {
       y2 = 10;
     }
     if (x2 || y2) {
   } };
   function dispatch() {
     for (var i3 = 0, n3 = arguments.length, _2 = {}, t2; i3 < n3; ++i3) {
-      if (!(t2 = arguments[i3] + "") || t2 in _2 || /[\s.]/.test(t2))
-        throw new Error("illegal type: " + t2);
+      if (!(t2 = arguments[i3] + "") || t2 in _2 || /[\s.]/.test(t2)) throw new Error("illegal type: " + t2);
       _2[t2] = [];
     }
     return new Dispatch(_2);
   function parseTypenames(typenames, types) {
     return typenames.trim().split(/^|\s+/).map(function(t2) {
       var name = "", i3 = t2.indexOf(".");
-      if (i3 >= 0)
-        name = t2.slice(i3 + 1), t2 = t2.slice(0, i3);
-      if (t2 && !types.hasOwnProperty(t2))
-        throw new Error("unknown type: " + t2);
+      if (i3 >= 0) name = t2.slice(i3 + 1), t2 = t2.slice(0, i3);
+      if (t2 && !types.hasOwnProperty(t2)) throw new Error("unknown type: " + t2);
       return { type: t2, name };
     });
   }
     on: function(typename, callback) {
       var _2 = this._, T2 = parseTypenames(typename + "", _2), t2, i3 = -1, n3 = T2.length;
       if (arguments.length < 2) {
-        while (++i3 < n3)
-          if ((t2 = (typename = T2[i3]).type) && (t2 = get(_2[t2], typename.name)))
-            return t2;
+        while (++i3 < n3) if ((t2 = (typename = T2[i3]).type) && (t2 = get(_2[t2], typename.name))) return t2;
         return;
       }
-      if (callback != null && typeof callback !== "function")
-        throw new Error("invalid callback: " + callback);
+      if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
       while (++i3 < n3) {
-        if (t2 = (typename = T2[i3]).type)
-          _2[t2] = set(_2[t2], typename.name, callback);
-        else if (callback == null)
-          for (t2 in _2)
-            _2[t2] = set(_2[t2], typename.name, null);
+        if (t2 = (typename = T2[i3]).type) _2[t2] = set(_2[t2], typename.name, callback);
+        else if (callback == null) for (t2 in _2) _2[t2] = set(_2[t2], typename.name, null);
       }
       return this;
     },
     copy: function() {
       var copy2 = {}, _2 = this._;
-      for (var t2 in _2)
-        copy2[t2] = _2[t2].slice();
+      for (var t2 in _2) copy2[t2] = _2[t2].slice();
       return new Dispatch(copy2);
     },
     call: function(type2, that) {
-      if ((n3 = arguments.length - 2) > 0)
-        for (var args = new Array(n3), i3 = 0, n3, t2; i3 < n3; ++i3)
-          args[i3] = arguments[i3 + 2];
-      if (!this._.hasOwnProperty(type2))
-        throw new Error("unknown type: " + type2);
-      for (t2 = this._[type2], i3 = 0, n3 = t2.length; i3 < n3; ++i3)
-        t2[i3].value.apply(that, args);
+      if ((n3 = arguments.length - 2) > 0) for (var args = new Array(n3), i3 = 0, n3, t2; i3 < n3; ++i3) args[i3] = arguments[i3 + 2];
+      if (!this._.hasOwnProperty(type2)) throw new Error("unknown type: " + type2);
+      for (t2 = this._[type2], i3 = 0, n3 = t2.length; i3 < n3; ++i3) t2[i3].value.apply(that, args);
     },
     apply: function(type2, that, args) {
-      if (!this._.hasOwnProperty(type2))
-        throw new Error("unknown type: " + type2);
-      for (var t2 = this._[type2], i3 = 0, n3 = t2.length; i3 < n3; ++i3)
-        t2[i3].value.apply(that, args);
+      if (!this._.hasOwnProperty(type2)) throw new Error("unknown type: " + type2);
+      for (var t2 = this._[type2], i3 = 0, n3 = t2.length; i3 < n3; ++i3) t2[i3].value.apply(that, args);
     }
   };
   function get(type2, name) {
         break;
       }
     }
-    if (callback != null)
-      type2.push({ name, value: callback });
+    if (callback != null) type2.push({ name, value: callback });
     return type2;
   }
   var dispatch_default = dispatch;
   // node_modules/d3-selection/src/namespace.js
   function namespace_default(name) {
     var prefix = name += "", i3 = prefix.indexOf(":");
-    if (i3 >= 0 && (prefix = name.slice(0, i3)) !== "xmlns")
-      name = name.slice(i3 + 1);
+    if (i3 >= 0 && (prefix = name.slice(0, i3)) !== "xmlns") name = name.slice(i3 + 1);
     return namespaces_default.hasOwnProperty(prefix) ? { space: namespaces_default[prefix], local: name } : name;
   }
 
 
   // node_modules/d3-selection/src/selection/select.js
   function select_default(select) {
-    if (typeof select !== "function")
-      select = selector_default(select);
+    if (typeof select !== "function") select = selector_default(select);
     for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
       for (var group = groups[j2], n3 = group.length, subgroup = subgroups[j2] = new Array(n3), node, subnode, i3 = 0; i3 < n3; ++i3) {
         if ((node = group[i3]) && (subnode = select.call(node, node.__data__, i3, group))) {
-          if ("__data__" in node)
-            subnode.__data__ = node.__data__;
+          if ("__data__" in node) subnode.__data__ = node.__data__;
           subgroup[i3] = subnode;
         }
       }
     };
   }
   function selectAll_default(select) {
-    if (typeof select === "function")
-      select = arrayAll(select);
-    else
-      select = selectorAll_default(select);
+    if (typeof select === "function") select = arrayAll(select);
+    else select = selectorAll_default(select);
     for (var groups = this._groups, m2 = groups.length, subgroups = [], parents = [], j2 = 0; j2 < m2; ++j2) {
       for (var group = groups[j2], n3 = group.length, node, i3 = 0; i3 < n3; ++i3) {
         if (node = group[i3]) {
 
   // node_modules/d3-selection/src/selection/filter.js
   function filter_default(match) {
-    if (typeof match !== "function")
-      match = matcher_default(match);
+    if (typeof match !== "function") match = matcher_default(match);
     for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
       for (var group = groups[j2], n3 = group.length, subgroup = subgroups[j2] = [], node, i3 = 0; i3 < n3; ++i3) {
         if ((node = group[i3]) && match.call(node, node.__data__, i3, group)) {
     return node.__data__;
   }
   function data_default(value, key) {
-    if (!arguments.length)
-      return Array.from(this, datum);
+    if (!arguments.length) return Array.from(this, datum);
     var bind = key ? bindKey : bindIndex, parents = this._parents, groups = this._groups;
-    if (typeof value !== "function")
-      value = constant_default(value);
+    if (typeof value !== "function") value = constant_default(value);
     for (var m2 = groups.length, update = new Array(m2), enter = new Array(m2), exit = new Array(m2), j2 = 0; j2 < m2; ++j2) {
       var parent = parents[j2], group = groups[j2], groupLength = group.length, data = arraylike(value.call(parent, parent && parent.__data__, j2, parents)), dataLength = data.length, enterGroup = enter[j2] = new Array(dataLength), updateGroup = update[j2] = new Array(dataLength), exitGroup = exit[j2] = new Array(groupLength);
       bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
       for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
         if (previous = enterGroup[i0]) {
-          if (i0 >= i1)
-            i1 = i0 + 1;
-          while (!(next = updateGroup[i1]) && ++i1 < dataLength)
-            ;
+          if (i0 >= i1) i1 = i0 + 1;
+          while (!(next = updateGroup[i1]) && ++i1 < dataLength) ;
           previous._next = next || null;
         }
       }
     var enter = this.enter(), update = this, exit = this.exit();
     if (typeof onenter === "function") {
       enter = onenter(enter);
-      if (enter)
-        enter = enter.selection();
+      if (enter) enter = enter.selection();
     } else {
       enter = enter.append(onenter + "");
     }
     if (onupdate != null) {
       update = onupdate(update);
-      if (update)
-        update = update.selection();
+      if (update) update = update.selection();
     }
-    if (onexit == null)
-      exit.remove();
-    else
-      onexit(exit);
+    if (onexit == null) exit.remove();
+    else onexit(exit);
     return enter && update ? enter.merge(update).order() : update;
   }
 
     for (var groups = this._groups, j2 = -1, m2 = groups.length; ++j2 < m2; ) {
       for (var group = groups[j2], i3 = group.length - 1, next = group[i3], node; --i3 >= 0; ) {
         if (node = group[i3]) {
-          if (next && node.compareDocumentPosition(next) ^ 4)
-            next.parentNode.insertBefore(node, next);
+          if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
           next = node;
         }
       }
 
   // node_modules/d3-selection/src/selection/sort.js
   function sort_default(compare2) {
-    if (!compare2)
-      compare2 = ascending2;
+    if (!compare2) compare2 = ascending2;
     function compareNode(a2, b2) {
       return a2 && b2 ? compare2(a2.__data__, b2.__data__) : !a2 - !b2;
     }
     for (var groups = this._groups, j2 = 0, m2 = groups.length; j2 < m2; ++j2) {
       for (var group = groups[j2], i3 = 0, n3 = group.length; i3 < n3; ++i3) {
         var node = group[i3];
-        if (node)
-          return node;
+        if (node) return node;
       }
     }
     return null;
   // node_modules/d3-selection/src/selection/size.js
   function size_default() {
     let size = 0;
-    for (const node of this)
-      ++size;
+    for (const node of this) ++size;
     return size;
   }
 
   function each_default(callback) {
     for (var groups = this._groups, j2 = 0, m2 = groups.length; j2 < m2; ++j2) {
       for (var group = groups[j2], i3 = 0, n3 = group.length, node; i3 < n3; ++i3) {
-        if (node = group[i3])
-          callback.call(node, node.__data__, i3, group);
+        if (node = group[i3]) callback.call(node, node.__data__, i3, group);
       }
     }
     return this;
   function attrFunction(name, value) {
     return function() {
       var v2 = value.apply(this, arguments);
-      if (v2 == null)
-        this.removeAttribute(name);
-      else
-        this.setAttribute(name, v2);
+      if (v2 == null) this.removeAttribute(name);
+      else this.setAttribute(name, v2);
     };
   }
   function attrFunctionNS(fullname, value) {
     return function() {
       var v2 = value.apply(this, arguments);
-      if (v2 == null)
-        this.removeAttributeNS(fullname.space, fullname.local);
-      else
-        this.setAttributeNS(fullname.space, fullname.local, v2);
+      if (v2 == null) this.removeAttributeNS(fullname.space, fullname.local);
+      else this.setAttributeNS(fullname.space, fullname.local, v2);
     };
   }
   function attr_default(name, value) {
   function styleFunction(name, value, priority) {
     return function() {
       var v2 = value.apply(this, arguments);
-      if (v2 == null)
-        this.style.removeProperty(name);
-      else
-        this.style.setProperty(name, v2, priority);
+      if (v2 == null) this.style.removeProperty(name);
+      else this.style.setProperty(name, v2, priority);
     };
   }
   function style_default(name, value, priority) {
   function propertyFunction(name, value) {
     return function() {
       var v2 = value.apply(this, arguments);
-      if (v2 == null)
-        delete this[name];
-      else
-        this[name] = v2;
+      if (v2 == null) delete this[name];
+      else this[name] = v2;
     };
   }
   function property_default(name, value) {
   };
   function classedAdd(node, names) {
     var list2 = classList(node), i3 = -1, n3 = names.length;
-    while (++i3 < n3)
-      list2.add(names[i3]);
+    while (++i3 < n3) list2.add(names[i3]);
   }
   function classedRemove(node, names) {
     var list2 = classList(node), i3 = -1, n3 = names.length;
-    while (++i3 < n3)
-      list2.remove(names[i3]);
+    while (++i3 < n3) list2.remove(names[i3]);
   }
   function classedTrue(names) {
     return function() {
     var names = classArray(name + "");
     if (arguments.length < 2) {
       var list2 = classList(this.node()), i3 = -1, n3 = names.length;
-      while (++i3 < n3)
-        if (!list2.contains(names[i3]))
-          return false;
+      while (++i3 < n3) if (!list2.contains(names[i3])) return false;
       return true;
     }
     return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
 
   // node_modules/d3-selection/src/selection/raise.js
   function raise() {
-    if (this.nextSibling)
-      this.parentNode.appendChild(this);
+    if (this.nextSibling) this.parentNode.appendChild(this);
   }
   function raise_default() {
     return this.each(raise);
 
   // node_modules/d3-selection/src/selection/lower.js
   function lower() {
-    if (this.previousSibling)
-      this.parentNode.insertBefore(this, this.parentNode.firstChild);
+    if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
   }
   function lower_default() {
     return this.each(lower);
   // node_modules/d3-selection/src/selection/remove.js
   function remove() {
     var parent = this.parentNode;
-    if (parent)
-      parent.removeChild(this);
+    if (parent) parent.removeChild(this);
   }
   function remove_default() {
     return this.each(remove);
   function parseTypenames2(typenames) {
     return typenames.trim().split(/^|\s+/).map(function(t2) {
       var name = "", i3 = t2.indexOf(".");
-      if (i3 >= 0)
-        name = t2.slice(i3 + 1), t2 = t2.slice(0, i3);
+      if (i3 >= 0) name = t2.slice(i3 + 1), t2 = t2.slice(0, i3);
       return { type: t2, name };
     });
   }
   function onRemove(typename) {
     return function() {
       var on = this.__on;
-      if (!on)
-        return;
+      if (!on) return;
       for (var j2 = 0, i3 = -1, m2 = on.length, o2; j2 < m2; ++j2) {
         if (o2 = on[j2], (!typename.type || o2.type === typename.type) && o2.name === typename.name) {
           this.removeEventListener(o2.type, o2.listener, o2.options);
           on[++i3] = o2;
         }
       }
-      if (++i3)
-        on.length = i3;
-      else
-        delete this.__on;
+      if (++i3) on.length = i3;
+      else delete this.__on;
     };
   }
   function onAdd(typename, value, options2) {
     return function() {
       var on = this.__on, o2, listener = contextListener(value);
-      if (on)
-        for (var j2 = 0, m2 = on.length; j2 < m2; ++j2) {
-          if ((o2 = on[j2]).type === typename.type && o2.name === typename.name) {
-            this.removeEventListener(o2.type, o2.listener, o2.options);
-            this.addEventListener(o2.type, o2.listener = listener, o2.options = options2);
-            o2.value = value;
-            return;
-          }
+      if (on) for (var j2 = 0, m2 = on.length; j2 < m2; ++j2) {
+        if ((o2 = on[j2]).type === typename.type && o2.name === typename.name) {
+          this.removeEventListener(o2.type, o2.listener, o2.options);
+          this.addEventListener(o2.type, o2.listener = listener, o2.options = options2);
+          o2.value = value;
+          return;
         }
+      }
       this.addEventListener(typename.type, listener, options2);
       o2 = { type: typename.type, name: typename.name, value, listener, options: options2 };
-      if (!on)
-        this.__on = [o2];
-      else
-        on.push(o2);
+      if (!on) this.__on = [o2];
+      else on.push(o2);
     };
   }
   function on_default(typename, value, options2) {
     var typenames = parseTypenames2(typename + ""), i3, n3 = typenames.length, t2;
     if (arguments.length < 2) {
       var on = this.node().__on;
-      if (on)
-        for (var j2 = 0, m2 = on.length, o2; j2 < m2; ++j2) {
-          for (i3 = 0, o2 = on[j2]; i3 < n3; ++i3) {
-            if ((t2 = typenames[i3]).type === o2.type && t2.name === o2.name) {
-              return o2.value;
-            }
+      if (on) for (var j2 = 0, m2 = on.length, o2; j2 < m2; ++j2) {
+        for (i3 = 0, o2 = on[j2]; i3 < n3; ++i3) {
+          if ((t2 = typenames[i3]).type === o2.type && t2.name === o2.name) {
+            return o2.value;
           }
         }
+      }
       return;
     }
     on = value ? onAdd : onRemove;
-    for (i3 = 0; i3 < n3; ++i3)
-      this.each(on(typenames[i3], value, options2));
+    for (i3 = 0; i3 < n3; ++i3) this.each(on(typenames[i3], value, options2));
     return this;
   }
 
       event = new event(type2, params);
     } else {
       event = window2.document.createEvent("Event");
-      if (params)
-        event.initEvent(type2, params.bubbles, params.cancelable), event.detail = params.detail;
-      else
-        event.initEvent(type2, false, false);
+      if (params) event.initEvent(type2, params.bubbles, params.cancelable), event.detail = params.detail;
+      else event.initEvent(type2, false, false);
     }
     node.dispatchEvent(event);
   }
   function* iterator_default() {
     for (var groups = this._groups, j2 = 0, m2 = groups.length; j2 < m2; ++j2) {
       for (var group = groups[j2], i3 = 0, n3 = group.length, node; i3 < n3; ++i3) {
-        if (node = group[i3])
-          yield node;
+        if (node = group[i3]) yield node;
       }
     }
   }
   // node_modules/d3-selection/src/sourceEvent.js
   function sourceEvent_default(event) {
     let sourceEvent;
-    while (sourceEvent = event.sourceEvent)
-      event = sourceEvent;
+    while (sourceEvent = event.sourceEvent) event = sourceEvent;
     return event;
   }
 
   // node_modules/d3-selection/src/pointer.js
   function pointer_default(event, node) {
     event = sourceEvent_default(event);
-    if (node === void 0)
-      node = event.currentTarget;
+    if (node === void 0) node = event.currentTarget;
     if (node) {
       var svg2 = node.ownerSVGElement || node;
       if (svg2.createSVGPoint) {
-        var point2 = svg2.createSVGPoint();
-        point2.x = event.clientX, point2.y = event.clientY;
-        point2 = point2.matrixTransform(node.getScreenCTM().inverse());
-        return [point2.x, point2.y];
+        var point = svg2.createSVGPoint();
+        point.x = event.clientX, point.y = event.clientY;
+        point = point.matrixTransform(node.getScreenCTM().inverse());
+        return [point.x, point.y];
       }
       if (node.getBoundingClientRect) {
         var rect = node.getBoundingClientRect();
       selection2.on("mousedown.drag", mousedowned).filter(touchable).on("touchstart.drag", touchstarted).on("touchmove.drag", touchmoved, nonpassive).on("touchend.drag touchcancel.drag", touchended).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
     }
     function mousedowned(event, d2) {
-      if (touchending || !filter2.call(this, event, d2))
-        return;
+      if (touchending || !filter2.call(this, event, d2)) return;
       var gesture = beforestart(this, container.call(this, event, d2), event, d2, "mouse");
-      if (!gesture)
-        return;
+      if (!gesture) return;
       select_default2(event.view).on("mousemove.drag", mousemoved, nonpassivecapture).on("mouseup.drag", mouseupped, nonpassivecapture);
       nodrag_default(event.view);
       nopropagation(event);
       gestures.mouse("end", event);
     }
     function touchstarted(event, d2) {
-      if (!filter2.call(this, event, d2))
-        return;
+      if (!filter2.call(this, event, d2)) return;
       var touches = event.changedTouches, c2 = container.call(this, event, d2), n3 = touches.length, i3, gesture;
       for (i3 = 0; i3 < n3; ++i3) {
         if (gesture = beforestart(this, c2, event, d2, touches[i3].identifier, touches[i3])) {
     }
     function touchended(event) {
       var touches = event.changedTouches, n3 = touches.length, i3, gesture;
-      if (touchending)
-        clearTimeout(touchending);
+      if (touchending) clearTimeout(touchending);
       touchending = setTimeout(function() {
         touchending = null;
       }, 500);
         dx: 0,
         dy: 0,
         dispatch: dispatch14
-      }), d2)) == null)
-        return;
+      }), d2)) == null) return;
       dx = s2.x - p2[0] || 0;
       dy = s2.y - p2[1] || 0;
       return function gesture(type2, event2, touch2) {
             break;
           case "end":
             delete gestures[identifier], --active;
+          // falls through
           case "drag":
             p2 = pointer_default(touch2 || event2, container2), n3 = active;
             break;
   }
   function extend(parent, definition) {
     var prototype = Object.create(parent.prototype);
-    for (var key in definition)
-      prototype[key] = definition[key];
+    for (var key in definition) prototype[key] = definition[key];
     return prototype;
   }
 
     return new Rgb(n3 >> 16 & 255, n3 >> 8 & 255, n3 & 255, 1);
   }
   function rgba(r2, g3, b2, a2) {
-    if (a2 <= 0)
-      r2 = g3 = b2 = NaN;
+    if (a2 <= 0) r2 = g3 = b2 = NaN;
     return new Rgb(r2, g3, b2, a2);
   }
   function rgbConvert(o2) {
-    if (!(o2 instanceof Color))
-      o2 = color(o2);
-    if (!o2)
-      return new Rgb();
+    if (!(o2 instanceof Color)) o2 = color(o2);
+    if (!o2) return new Rgb();
     o2 = o2.rgb();
     return new Rgb(o2.r, o2.g, o2.b, o2.opacity);
   }
     return (value < 16 ? "0" : "") + value.toString(16);
   }
   function hsla(h2, s2, l2, a2) {
-    if (a2 <= 0)
-      h2 = s2 = l2 = NaN;
-    else if (l2 <= 0 || l2 >= 1)
-      h2 = s2 = NaN;
-    else if (s2 <= 0)
-      h2 = NaN;
+    if (a2 <= 0) h2 = s2 = l2 = NaN;
+    else if (l2 <= 0 || l2 >= 1) h2 = s2 = NaN;
+    else if (s2 <= 0) h2 = NaN;
     return new Hsl(h2, s2, l2, a2);
   }
   function hslConvert(o2) {
-    if (o2 instanceof Hsl)
-      return new Hsl(o2.h, o2.s, o2.l, o2.opacity);
-    if (!(o2 instanceof Color))
-      o2 = color(o2);
-    if (!o2)
-      return new Hsl();
-    if (o2 instanceof Hsl)
-      return o2;
+    if (o2 instanceof Hsl) return new Hsl(o2.h, o2.s, o2.l, o2.opacity);
+    if (!(o2 instanceof Color)) o2 = color(o2);
+    if (!o2) return new Hsl();
+    if (o2 instanceof Hsl) return o2;
     o2 = o2.rgb();
     var r2 = o2.r / 255, g3 = o2.g / 255, b2 = o2.b / 255, min3 = Math.min(r2, g3, b2), max3 = Math.max(r2, g3, b2), h2 = NaN, s2 = max3 - min3, l2 = (max3 + min3) / 2;
     if (s2) {
-      if (r2 === max3)
-        h2 = (g3 - b2) / s2 + (g3 < b2) * 6;
-      else if (g3 === max3)
-        h2 = (b2 - r2) / s2 + 2;
-      else
-        h2 = (r2 - g3) / s2 + 4;
+      if (r2 === max3) h2 = (g3 - b2) / s2 + (g3 < b2) * 6;
+      else if (g3 === max3) h2 = (b2 - r2) / s2 + 2;
+      else h2 = (r2 - g3) / s2 + 4;
       s2 /= l2 < 0.5 ? max3 + min3 : 2 - max3 - min3;
       h2 *= 60;
     } else {
 
   // node_modules/d3-interpolate/src/numberArray.js
   function numberArray_default(a2, b2) {
-    if (!b2)
-      b2 = [];
+    if (!b2) b2 = [];
     var n3 = a2 ? Math.min(b2.length, a2.length) : 0, c2 = b2.slice(), i3;
     return function(t2) {
-      for (i3 = 0; i3 < n3; ++i3)
-        c2[i3] = a2[i3] * (1 - t2) + b2[i3] * t2;
+      for (i3 = 0; i3 < n3; ++i3) c2[i3] = a2[i3] * (1 - t2) + b2[i3] * t2;
       return c2;
     };
   }
   // node_modules/d3-interpolate/src/array.js
   function genericArray(a2, b2) {
     var nb = b2 ? b2.length : 0, na = a2 ? Math.min(nb, a2.length) : 0, x2 = new Array(na), c2 = new Array(nb), i3;
-    for (i3 = 0; i3 < na; ++i3)
-      x2[i3] = value_default(a2[i3], b2[i3]);
-    for (; i3 < nb; ++i3)
-      c2[i3] = b2[i3];
+    for (i3 = 0; i3 < na; ++i3) x2[i3] = value_default(a2[i3], b2[i3]);
+    for (; i3 < nb; ++i3) c2[i3] = b2[i3];
     return function(t2) {
-      for (i3 = 0; i3 < na; ++i3)
-        c2[i3] = x2[i3](t2);
+      for (i3 = 0; i3 < na; ++i3) c2[i3] = x2[i3](t2);
       return c2;
     };
   }
   // node_modules/d3-interpolate/src/object.js
   function object_default(a2, b2) {
     var i3 = {}, c2 = {}, k2;
-    if (a2 === null || typeof a2 !== "object")
-      a2 = {};
-    if (b2 === null || typeof b2 !== "object")
-      b2 = {};
+    if (a2 === null || typeof a2 !== "object") a2 = {};
+    if (b2 === null || typeof b2 !== "object") b2 = {};
     for (k2 in b2) {
       if (k2 in a2) {
         i3[k2] = value_default(a2[k2], b2[k2]);
       }
     }
     return function(t2) {
-      for (k2 in i3)
-        c2[k2] = i3[k2](t2);
+      for (k2 in i3) c2[k2] = i3[k2](t2);
       return c2;
     };
   }
     while ((am = reA.exec(a2)) && (bm = reB.exec(b2))) {
       if ((bs = bm.index) > bi) {
         bs = b2.slice(bi, bs);
-        if (s2[i3])
-          s2[i3] += bs;
-        else
-          s2[++i3] = bs;
+        if (s2[i3]) s2[i3] += bs;
+        else s2[++i3] = bs;
       }
       if ((am = am[0]) === (bm = bm[0])) {
-        if (s2[i3])
-          s2[i3] += bm;
-        else
-          s2[++i3] = bm;
+        if (s2[i3]) s2[i3] += bm;
+        else s2[++i3] = bm;
       } else {
         s2[++i3] = null;
         q2.push({ i: i3, x: number_default(am, bm) });
     }
     if (bi < b2.length) {
       bs = b2.slice(bi);
-      if (s2[i3])
-        s2[i3] += bs;
-      else
-        s2[++i3] = bs;
+      if (s2[i3]) s2[i3] += bs;
+      else s2[++i3] = bs;
     }
     return s2.length < 2 ? q2[0] ? one(q2[0].x) : zero2(b2) : (b2 = q2.length, function(t2) {
-      for (var i4 = 0, o2; i4 < b2; ++i4)
-        s2[(o2 = q2[i4]).i] = o2.x(t2);
+      for (var i4 = 0, o2; i4 < b2; ++i4) s2[(o2 = q2[i4]).i] = o2.x(t2);
       return s2.join("");
     });
   }
   };
   function decompose_default(a2, b2, c2, d2, e3, f2) {
     var scaleX, scaleY, skewX;
-    if (scaleX = Math.sqrt(a2 * a2 + b2 * b2))
-      a2 /= scaleX, b2 /= scaleX;
-    if (skewX = a2 * c2 + b2 * d2)
-      c2 -= a2 * skewX, d2 -= b2 * skewX;
-    if (scaleY = Math.sqrt(c2 * c2 + d2 * d2))
-      c2 /= scaleY, d2 /= scaleY, skewX /= scaleY;
-    if (a2 * d2 < b2 * c2)
-      a2 = -a2, b2 = -b2, skewX = -skewX, scaleX = -scaleX;
+    if (scaleX = Math.sqrt(a2 * a2 + b2 * b2)) a2 /= scaleX, b2 /= scaleX;
+    if (skewX = a2 * c2 + b2 * d2) c2 -= a2 * skewX, d2 -= b2 * skewX;
+    if (scaleY = Math.sqrt(c2 * c2 + d2 * d2)) c2 /= scaleY, d2 /= scaleY, skewX /= scaleY;
+    if (a2 * d2 < b2 * c2) a2 = -a2, b2 = -b2, skewX = -skewX, scaleX = -scaleX;
     return {
       translateX: e3,
       translateY: f2,
     return m2.isIdentity ? identity : decompose_default(m2.a, m2.b, m2.c, m2.d, m2.e, m2.f);
   }
   function parseSvg(value) {
-    if (value == null)
-      return identity;
-    if (!svgNode)
-      svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
+    if (value == null) return identity;
+    if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
     svgNode.setAttribute("transform", value);
-    if (!(value = svgNode.transform.baseVal.consolidate()))
-      return identity;
+    if (!(value = svgNode.transform.baseVal.consolidate())) return identity;
     value = value.matrix;
     return decompose_default(value.a, value.b, value.c, value.d, value.e, value.f);
   }
     }
     function rotate(a2, b2, s2, q2) {
       if (a2 !== b2) {
-        if (a2 - b2 > 180)
-          b2 += 360;
-        else if (b2 - a2 > 180)
-          a2 += 360;
+        if (a2 - b2 > 180) b2 += 360;
+        else if (b2 - a2 > 180) a2 += 360;
         q2.push({ i: s2.push(pop(s2) + "rotate(", null, degParen) - 2, x: number_default(a2, b2) });
       } else if (b2) {
         s2.push(pop(s2) + "rotate(" + b2 + degParen);
       a2 = b2 = null;
       return function(t2) {
         var i3 = -1, n3 = q2.length, o2;
-        while (++i3 < n3)
-          s2[(o2 = q2[i3]).i] = o2.x(t2);
+        while (++i3 < n3) s2[(o2 = q2[i3]).i] = o2.x(t2);
         return s2.join("");
       };
     };
   // node_modules/d3-interpolate/src/quantize.js
   function quantize_default(interpolator, n3) {
     var samples = new Array(n3);
-    for (var i3 = 0; i3 < n3; ++i3)
-      samples[i3] = interpolator(i3 / (n3 - 1));
+    for (var i3 = 0; i3 < n3; ++i3) samples[i3] = interpolator(i3 / (n3 - 1));
     return samples;
   }
 
   Timer.prototype = timer.prototype = {
     constructor: Timer,
     restart: function(callback, delay, time) {
-      if (typeof callback !== "function")
-        throw new TypeError("callback is not a function");
+      if (typeof callback !== "function") throw new TypeError("callback is not a function");
       time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
       if (!this._next && taskTail !== this) {
-        if (taskTail)
-          taskTail._next = this;
-        else
-          taskHead = this;
+        if (taskTail) taskTail._next = this;
+        else taskHead = this;
         taskTail = this;
       }
       this._call = callback;
     ++frame;
     var t2 = taskHead, e3;
     while (t2) {
-      if ((e3 = clockNow - t2._time) >= 0)
-        t2._call.call(void 0, e3);
+      if ((e3 = clockNow - t2._time) >= 0) t2._call.call(void 0, e3);
       t2 = t2._next;
     }
     --frame;
   }
   function poke() {
     var now3 = clock.now(), delay = now3 - clockLast;
-    if (delay > pokeDelay)
-      clockSkew -= delay, clockLast = now3;
+    if (delay > pokeDelay) clockSkew -= delay, clockLast = now3;
   }
   function nap() {
     var t0, t1 = taskHead, t2, time = Infinity;
     while (t1) {
       if (t1._call) {
-        if (time > t1._time)
-          time = t1._time;
+        if (time > t1._time) time = t1._time;
         t0 = t1, t1 = t1._next;
       } else {
         t2 = t1._next, t1._next = null;
     sleep(time);
   }
   function sleep(time) {
-    if (frame)
-      return;
-    if (timeout)
-      timeout = clearTimeout(timeout);
+    if (frame) return;
+    if (timeout) timeout = clearTimeout(timeout);
     var delay = time - clockNow;
     if (delay > 24) {
-      if (time < Infinity)
-        timeout = setTimeout(wake, time - clock.now() - clockSkew);
-      if (interval)
-        interval = clearInterval(interval);
+      if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
+      if (interval) interval = clearInterval(interval);
     } else {
-      if (!interval)
-        clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
+      if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
       frame = 1, setFrame(wake);
     }
   }
   var ENDED = 6;
   function schedule_default(node, name, id2, index, group, timing) {
     var schedules = node.__transition;
-    if (!schedules)
-      node.__transition = {};
-    else if (id2 in schedules)
-      return;
+    if (!schedules) node.__transition = {};
+    else if (id2 in schedules) return;
     create(node, id2, {
       name,
       index,
   }
   function init(node, id2) {
     var schedule = get2(node, id2);
-    if (schedule.state > CREATED)
-      throw new Error("too late; already scheduled");
+    if (schedule.state > CREATED) throw new Error("too late; already scheduled");
     return schedule;
   }
   function set2(node, id2) {
     var schedule = get2(node, id2);
-    if (schedule.state > STARTED)
-      throw new Error("too late; already running");
+    if (schedule.state > STARTED) throw new Error("too late; already running");
     return schedule;
   }
   function get2(node, id2) {
     var schedule = node.__transition;
-    if (!schedule || !(schedule = schedule[id2]))
-      throw new Error("transition not found");
+    if (!schedule || !(schedule = schedule[id2])) throw new Error("transition not found");
     return schedule;
   }
   function create(node, id2, self2) {
     function schedule(elapsed) {
       self2.state = SCHEDULED;
       self2.timer.restart(start2, self2.delay, self2.time);
-      if (self2.delay <= elapsed)
-        start2(elapsed - self2.delay);
+      if (self2.delay <= elapsed) start2(elapsed - self2.delay);
     }
     function start2(elapsed) {
       var i3, j2, n3, o2;
-      if (self2.state !== SCHEDULED)
-        return stop();
+      if (self2.state !== SCHEDULED) return stop();
       for (i3 in schedules) {
         o2 = schedules[i3];
-        if (o2.name !== self2.name)
-          continue;
-        if (o2.state === STARTED)
-          return timeout_default(start2);
+        if (o2.name !== self2.name) continue;
+        if (o2.state === STARTED) return timeout_default(start2);
         if (o2.state === RUNNING) {
           o2.state = ENDED;
           o2.timer.stop();
       });
       self2.state = STARTING;
       self2.on.call("start", node, node.__data__, self2.index, self2.group);
-      if (self2.state !== STARTING)
-        return;
+      if (self2.state !== STARTING) return;
       self2.state = STARTED;
       tween = new Array(n3 = self2.tween.length);
       for (i3 = 0, j2 = -1; i3 < n3; ++i3) {
       self2.state = ENDED;
       self2.timer.stop();
       delete schedules[id2];
-      for (var i3 in schedules)
-        return;
+      for (var i3 in schedules) return;
       delete node.__transition;
     }
   }
   // node_modules/d3-transition/src/interrupt.js
   function interrupt_default(node, name) {
     var schedules = node.__transition, schedule, active, empty2 = true, i3;
-    if (!schedules)
-      return;
+    if (!schedules) return;
     name = name == null ? null : name + "";
     for (i3 in schedules) {
       if ((schedule = schedules[i3]).name !== name) {
       schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
       delete schedules[i3];
     }
-    if (empty2)
-      delete node.__transition;
+    if (empty2) delete node.__transition;
   }
 
   // node_modules/d3-transition/src/selection/interrupt.js
   }
   function tweenFunction(id2, name, value) {
     var tween0, tween1;
-    if (typeof value !== "function")
-      throw new Error();
+    if (typeof value !== "function") throw new Error();
     return function() {
       var schedule = set2(this, id2), tween = schedule.tween;
       if (tween !== tween0) {
             break;
           }
         }
-        if (i3 === n3)
-          tween1.push(t2);
+        if (i3 === n3) tween1.push(t2);
       }
       schedule.tween = tween1;
     };
     var string00, string10, interpolate0;
     return function() {
       var string0, value1 = value(this), string1;
-      if (value1 == null)
-        return void this.removeAttribute(name);
+      if (value1 == null) return void this.removeAttribute(name);
       string0 = this.getAttribute(name);
       string1 = value1 + "";
       return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
     var string00, string10, interpolate0;
     return function() {
       var string0, value1 = value(this), string1;
-      if (value1 == null)
-        return void this.removeAttributeNS(fullname.space, fullname.local);
+      if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
       string0 = this.getAttributeNS(fullname.space, fullname.local);
       string1 = value1 + "";
       return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
     var t0, i0;
     function tween() {
       var i3 = value.apply(this, arguments);
-      if (i3 !== i0)
-        t0 = (i0 = i3) && attrInterpolateNS(fullname, i3);
+      if (i3 !== i0) t0 = (i0 = i3) && attrInterpolateNS(fullname, i3);
       return t0;
     }
     tween._value = value;
     var t0, i0;
     function tween() {
       var i3 = value.apply(this, arguments);
-      if (i3 !== i0)
-        t0 = (i0 = i3) && attrInterpolate(name, i3);
+      if (i3 !== i0) t0 = (i0 = i3) && attrInterpolate(name, i3);
       return t0;
     }
     tween._value = value;
   }
   function attrTween_default(name, value) {
     var key = "attr." + name;
-    if (arguments.length < 2)
-      return (key = this.tween(key)) && key._value;
-    if (value == null)
-      return this.tween(key, null);
-    if (typeof value !== "function")
-      throw new Error();
+    if (arguments.length < 2) return (key = this.tween(key)) && key._value;
+    if (value == null) return this.tween(key, null);
+    if (typeof value !== "function") throw new Error();
     var fullname = namespace_default(name);
     return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
   }
 
   // node_modules/d3-transition/src/transition/ease.js
   function easeConstant(id2, value) {
-    if (typeof value !== "function")
-      throw new Error();
+    if (typeof value !== "function") throw new Error();
     return function() {
       set2(this, id2).ease = value;
     };
   function easeVarying(id2, value) {
     return function() {
       var v2 = value.apply(this, arguments);
-      if (typeof v2 !== "function")
-        throw new Error();
+      if (typeof v2 !== "function") throw new Error();
       set2(this, id2).ease = v2;
     };
   }
   function easeVarying_default(value) {
-    if (typeof value !== "function")
-      throw new Error();
+    if (typeof value !== "function") throw new Error();
     return this.each(easeVarying(this._id, value));
   }
 
   // node_modules/d3-transition/src/transition/filter.js
   function filter_default2(match) {
-    if (typeof match !== "function")
-      match = matcher_default(match);
+    if (typeof match !== "function") match = matcher_default(match);
     for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
       for (var group = groups[j2], n3 = group.length, subgroup = subgroups[j2] = [], node, i3 = 0; i3 < n3; ++i3) {
         if ((node = group[i3]) && match.call(node, node.__data__, i3, group)) {
 
   // node_modules/d3-transition/src/transition/merge.js
   function merge_default2(transition2) {
-    if (transition2._id !== this._id)
-      throw new Error();
+    if (transition2._id !== this._id) throw new Error();
     for (var groups0 = this._groups, groups1 = transition2._groups, m0 = groups0.length, m1 = groups1.length, m2 = Math.min(m0, m1), merges = new Array(m0), j2 = 0; j2 < m2; ++j2) {
       for (var group0 = groups0[j2], group1 = groups1[j2], n3 = group0.length, merge2 = merges[j2] = new Array(n3), node, i3 = 0; i3 < n3; ++i3) {
         if (node = group0[i3] || group1[i3]) {
   function start(name) {
     return (name + "").trim().split(/^|\s+/).every(function(t2) {
       var i3 = t2.indexOf(".");
-      if (i3 >= 0)
-        t2 = t2.slice(0, i3);
+      if (i3 >= 0) t2 = t2.slice(0, i3);
       return !t2 || t2 === "start";
     });
   }
     var on0, on1, sit = start(name) ? init : set2;
     return function() {
       var schedule = sit(this, id2), on = schedule.on;
-      if (on !== on0)
-        (on1 = (on0 = on).copy()).on(name, listener);
+      if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
       schedule.on = on1;
     };
   }
   function removeFunction(id2) {
     return function() {
       var parent = this.parentNode;
-      for (var i3 in this.__transition)
-        if (+i3 !== id2)
-          return;
-      if (parent)
-        parent.removeChild(this);
+      for (var i3 in this.__transition) if (+i3 !== id2) return;
+      if (parent) parent.removeChild(this);
     };
   }
   function remove_default2() {
   // node_modules/d3-transition/src/transition/select.js
   function select_default3(select) {
     var name = this._name, id2 = this._id;
-    if (typeof select !== "function")
-      select = selector_default(select);
+    if (typeof select !== "function") select = selector_default(select);
     for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
       for (var group = groups[j2], n3 = group.length, subgroup = subgroups[j2] = new Array(n3), node, subnode, i3 = 0; i3 < n3; ++i3) {
         if ((node = group[i3]) && (subnode = select.call(node, node.__data__, i3, group))) {
-          if ("__data__" in node)
-            subnode.__data__ = node.__data__;
+          if ("__data__" in node) subnode.__data__ = node.__data__;
           subgroup[i3] = subnode;
           schedule_default(subgroup[i3], name, id2, i3, subgroup, get2(node, id2));
         }
   // node_modules/d3-transition/src/transition/selectAll.js
   function selectAll_default3(select) {
     var name = this._name, id2 = this._id;
-    if (typeof select !== "function")
-      select = selectorAll_default(select);
+    if (typeof select !== "function") select = selectorAll_default(select);
     for (var groups = this._groups, m2 = groups.length, subgroups = [], parents = [], j2 = 0; j2 < m2; ++j2) {
       for (var group = groups[j2], n3 = group.length, node, i3 = 0; i3 < n3; ++i3) {
         if (node = group[i3]) {
     var string00, string10, interpolate0;
     return function() {
       var string0 = styleValue(this, name), value1 = value(this), string1 = value1 + "";
-      if (value1 == null)
-        string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
+      if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
       return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
     };
   }
     var on0, on1, listener0, key = "style." + name, event = "end." + key, remove2;
     return function() {
       var schedule = set2(this, id2), on = schedule.on, listener = schedule.value[key] == null ? remove2 || (remove2 = styleRemove2(name)) : void 0;
-      if (on !== on0 || listener0 !== listener)
-        (on1 = (on0 = on).copy()).on(event, listener0 = listener);
+      if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
       schedule.on = on1;
     };
   }
     var t2, i0;
     function tween() {
       var i3 = value.apply(this, arguments);
-      if (i3 !== i0)
-        t2 = (i0 = i3) && styleInterpolate(name, i3, priority);
+      if (i3 !== i0) t2 = (i0 = i3) && styleInterpolate(name, i3, priority);
       return t2;
     }
     tween._value = value;
   }
   function styleTween_default(name, value, priority) {
     var key = "style." + (name += "");
-    if (arguments.length < 2)
-      return (key = this.tween(key)) && key._value;
-    if (value == null)
-      return this.tween(key, null);
-    if (typeof value !== "function")
-      throw new Error();
+    if (arguments.length < 2) return (key = this.tween(key)) && key._value;
+    if (value == null) return this.tween(key, null);
+    if (typeof value !== "function") throw new Error();
     return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
   }
 
     var t0, i0;
     function tween() {
       var i3 = value.apply(this, arguments);
-      if (i3 !== i0)
-        t0 = (i0 = i3) && textInterpolate(i3);
+      if (i3 !== i0) t0 = (i0 = i3) && textInterpolate(i3);
       return t0;
     }
     tween._value = value;
   }
   function textTween_default(value) {
     var key = "text";
-    if (arguments.length < 1)
-      return (key = this.tween(key)) && key._value;
-    if (value == null)
-      return this.tween(key, null);
-    if (typeof value !== "function")
-      throw new Error();
+    if (arguments.length < 1) return (key = this.tween(key)) && key._value;
+    if (value == null) return this.tween(key, null);
+    if (typeof value !== "function") throw new Error();
     return this.tween(key, textTween(value));
   }
 
     var on0, on1, that = this, id2 = that._id, size = that.size();
     return new Promise(function(resolve, reject) {
       var cancel = { value: reject }, end = { value: function() {
-        if (--size === 0)
-          resolve();
+        if (--size === 0) resolve();
       } };
       that.each(function() {
         var schedule = set2(this, id2), on = schedule.on;
         }
         schedule.on = on1;
       });
-      if (size === 0)
-        resolve();
+      if (size === 0) resolve();
     });
   }
 
     translate: function(x2, y2) {
       return x2 === 0 & y2 === 0 ? this : new Transform(this.k, this.x + this.k * x2, this.y + this.k * y2);
     },
-    apply: function(point2) {
-      return [point2[0] * this.k + this.x, point2[1] * this.k + this.y];
+    apply: function(point) {
+      return [point[0] * this.k + this.x, point[1] * this.k + this.y];
     },
     applyX: function(x2) {
       return x2 * this.k + this.x;
   var identity2 = new Transform(1, 0, 0);
   transform.prototype = Transform.prototype;
   function transform(node) {
-    while (!node.__zoom)
-      if (!(node = node.parentNode))
-        return identity2;
+    while (!node.__zoom) if (!(node = node.parentNode)) return identity2;
     return node.__zoom;
   }
 
     function zoom(selection2) {
       selection2.property("__zoom", defaultTransform).on("wheel.zoom", wheeled, { passive: false }).on("mousedown.zoom", mousedowned).on("dblclick.zoom", dblclicked).filter(touchable).on("touchstart.zoom", touchstarted).on("touchmove.zoom", touchmoved).on("touchend.zoom touchcancel.zoom", touchended).style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
     }
-    zoom.transform = function(collection, transform2, point2, event) {
+    zoom.transform = function(collection, transform2, point, event) {
       var selection2 = collection.selection ? collection.selection() : collection;
       selection2.property("__zoom", defaultTransform);
       if (collection !== selection2) {
-        schedule(collection, transform2, point2, event);
+        schedule(collection, transform2, point, event);
       } else {
         selection2.interrupt().each(function() {
           gesture(this, arguments).event(event).start().zoom(null, typeof transform2 === "function" ? transform2.apply(this, arguments) : transform2).end();
     function centroid(extent2) {
       return [(+extent2[0][0] + +extent2[1][0]) / 2, (+extent2[0][1] + +extent2[1][1]) / 2];
     }
-    function schedule(transition2, transform2, point2, event) {
+    function schedule(transition2, transform2, point, event) {
       transition2.on("start.zoom", function() {
         gesture(this, arguments).event(event).start();
       }).on("interrupt.zoom end.zoom", function() {
         gesture(this, arguments).event(event).end();
       }).tween("zoom", function() {
-        var that = this, args = arguments, g3 = gesture(that, args).event(event), e3 = extent.apply(that, args), p2 = point2 == null ? centroid(e3) : typeof point2 === "function" ? point2.apply(that, args) : point2, w2 = Math.max(e3[1][0] - e3[0][0], e3[1][1] - e3[0][1]), a2 = that.__zoom, b2 = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i3 = interpolate(a2.invert(p2).concat(w2 / a2.k), b2.invert(p2).concat(w2 / b2.k));
+        var that = this, args = arguments, g3 = gesture(that, args).event(event), e3 = extent.apply(that, args), p2 = point == null ? centroid(e3) : typeof point === "function" ? point.apply(that, args) : point, w2 = Math.max(e3[1][0] - e3[0][0], e3[1][1] - e3[0][1]), a2 = that.__zoom, b2 = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i3 = interpolate(a2.invert(p2).concat(w2 / a2.k), b2.invert(p2).concat(w2 / b2.k));
         return function(t2) {
-          if (t2 === 1)
-            t2 = b2;
+          if (t2 === 1) t2 = b2;
           else {
             var l2 = i3(t2), k2 = w2 / l2[2];
             t2 = new Transform(k2, p2[0] - l2[0] * k2, p2[1] - l2[1] * k2);
     }
     Gesture.prototype = {
       event: function(event) {
-        if (event)
-          this.sourceEvent = event;
+        if (event) this.sourceEvent = event;
         return this;
       },
       start: function() {
         return this;
       },
       zoom: function(key, transform2) {
-        if (this.mouse && key !== "mouse")
-          this.mouse[1] = transform2.invert(this.mouse[0]);
-        if (this.touch0 && key !== "touch")
-          this.touch0[1] = transform2.invert(this.touch0[0]);
-        if (this.touch1 && key !== "touch")
-          this.touch1[1] = transform2.invert(this.touch1[0]);
+        if (this.mouse && key !== "mouse") this.mouse[1] = transform2.invert(this.mouse[0]);
+        if (this.touch0 && key !== "touch") this.touch0[1] = transform2.invert(this.touch0[0]);
+        if (this.touch1 && key !== "touch") this.touch1[1] = transform2.invert(this.touch1[0]);
         this.that.__zoom = transform2;
         this.emit("zoom");
         return this;
       }
     };
     function wheeled(event, ...args) {
-      if (!filter2.apply(this, arguments))
-        return;
+      if (!filter2.apply(this, arguments)) return;
       var g3 = gesture(this, args).event(event), t2 = this.__zoom, k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t2.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p2 = pointer_default(event);
       if (g3.wheel) {
         if (g3.mouse[0][0] !== p2[0] || g3.mouse[0][1] !== p2[1]) {
           g3.mouse[1] = t2.invert(g3.mouse[0] = p2);
         }
         clearTimeout(g3.wheel);
-      } else if (t2.k === k2)
-        return;
+      } else if (t2.k === k2) return;
       else {
         g3.mouse = [p2, t2.invert(p2)];
         interrupt_default(this);
       }
     }
     function mousedowned(event, ...args) {
-      if (touchending || !filter2.apply(this, arguments))
-        return;
+      if (touchending || !filter2.apply(this, arguments)) return;
       var currentTarget = event.currentTarget, g3 = gesture(this, args, true).event(event), v2 = select_default2(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true), p2 = pointer_default(event, currentTarget), x05 = event.clientX, y05 = event.clientY;
       nodrag_default(event.view);
       nopropagation2(event);
       }
     }
     function dblclicked(event, ...args) {
-      if (!filter2.apply(this, arguments))
-        return;
+      if (!filter2.apply(this, arguments)) return;
       var t0 = this.__zoom, p02 = pointer_default(event.changedTouches ? event.changedTouches[0] : event, this), p1 = t0.invert(p02), k1 = t0.k * (event.shiftKey ? 0.5 : 2), t1 = constrain(translate(scale(t0, k1), p02, p1), extent.apply(this, args), translateExtent);
       noevent_default2(event);
-      if (duration > 0)
-        select_default2(this).transition().duration(duration).call(schedule, t1, p02, event);
-      else
-        select_default2(this).call(zoom.transform, t1, p02, event);
+      if (duration > 0) select_default2(this).transition().duration(duration).call(schedule, t1, p02, event);
+      else select_default2(this).call(zoom.transform, t1, p02, event);
     }
     function touchstarted(event, ...args) {
-      if (!filter2.apply(this, arguments))
-        return;
+      if (!filter2.apply(this, arguments)) return;
       var touches = event.touches, n3 = touches.length, g3 = gesture(this, args, event.changedTouches.length === n3).event(event), started, i3, t2, p2;
       nopropagation2(event);
       for (i3 = 0; i3 < n3; ++i3) {
         t2 = touches[i3], p2 = pointer_default(t2, this);
         p2 = [p2, this.__zoom.invert(p2), t2.identifier];
-        if (!g3.touch0)
-          g3.touch0 = p2, started = true, g3.taps = 1 + !!touchstarting;
-        else if (!g3.touch1 && g3.touch0[2] !== p2[2])
-          g3.touch1 = p2, g3.taps = 0;
+        if (!g3.touch0) g3.touch0 = p2, started = true, g3.taps = 1 + !!touchstarting;
+        else if (!g3.touch1 && g3.touch0[2] !== p2[2]) g3.touch1 = p2, g3.taps = 0;
       }
-      if (touchstarting)
-        touchstarting = clearTimeout(touchstarting);
+      if (touchstarting) touchstarting = clearTimeout(touchstarting);
       if (started) {
-        if (g3.taps < 2)
-          touchfirst = p2[0], touchstarting = setTimeout(function() {
-            touchstarting = null;
-          }, touchDelay);
+        if (g3.taps < 2) touchfirst = p2[0], touchstarting = setTimeout(function() {
+          touchstarting = null;
+        }, touchDelay);
         interrupt_default(this);
         g3.start();
       }
     }
     function touchmoved(event, ...args) {
-      if (!this.__zooming)
-        return;
+      if (!this.__zooming) return;
       var g3 = gesture(this, args).event(event), touches = event.changedTouches, n3 = touches.length, i3, t2, p2, l2;
       noevent_default2(event);
       for (i3 = 0; i3 < n3; ++i3) {
         t2 = touches[i3], p2 = pointer_default(t2, this);
-        if (g3.touch0 && g3.touch0[2] === t2.identifier)
-          g3.touch0[0] = p2;
-        else if (g3.touch1 && g3.touch1[2] === t2.identifier)
-          g3.touch1[0] = p2;
+        if (g3.touch0 && g3.touch0[2] === t2.identifier) g3.touch0[0] = p2;
+        else if (g3.touch1 && g3.touch1[2] === t2.identifier) g3.touch1[0] = p2;
       }
       t2 = g3.that.__zoom;
       if (g3.touch1) {
         t2 = scale(t2, Math.sqrt(dp / dl));
         p2 = [(p02[0] + p1[0]) / 2, (p02[1] + p1[1]) / 2];
         l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
-      } else if (g3.touch0)
-        p2 = g3.touch0[0], l2 = g3.touch0[1];
-      else
-        return;
+      } else if (g3.touch0) p2 = g3.touch0[0], l2 = g3.touch0[1];
+      else return;
       g3.zoom("touch", constrain(translate(t2, p2, l2), g3.extent, translateExtent));
     }
     function touchended(event, ...args) {
-      if (!this.__zooming)
-        return;
+      if (!this.__zooming) return;
       var g3 = gesture(this, args).event(event), touches = event.changedTouches, n3 = touches.length, i3, t2;
       nopropagation2(event);
-      if (touchending)
-        clearTimeout(touchending);
+      if (touchending) clearTimeout(touchending);
       touchending = setTimeout(function() {
         touchending = null;
       }, touchDelay);
       for (i3 = 0; i3 < n3; ++i3) {
         t2 = touches[i3];
-        if (g3.touch0 && g3.touch0[2] === t2.identifier)
-          delete g3.touch0;
-        else if (g3.touch1 && g3.touch1[2] === t2.identifier)
-          delete g3.touch1;
-      }
-      if (g3.touch1 && !g3.touch0)
-        g3.touch0 = g3.touch1, delete g3.touch1;
-      if (g3.touch0)
-        g3.touch0[1] = this.__zoom.invert(g3.touch0[0]);
+        if (g3.touch0 && g3.touch0[2] === t2.identifier) delete g3.touch0;
+        else if (g3.touch1 && g3.touch1[2] === t2.identifier) delete g3.touch1;
+      }
+      if (g3.touch1 && !g3.touch0) g3.touch0 = g3.touch1, delete g3.touch1;
+      if (g3.touch0) g3.touch0[1] = this.__zoom.invert(g3.touch0[0]);
       else {
         g3.end();
         if (g3.taps === 2) {
           t2 = pointer_default(t2, this);
           if (Math.hypot(touchfirst[0] - t2[0], touchfirst[1] - t2[1]) < tapDistance) {
             var p2 = select_default2(this).on("dblclick.zoom");
-            if (p2)
-              p2.apply(this, arguments);
+            if (p2) p2.apply(this, arguments);
           }
         }
       }
     var x2 = 0;
     var y2 = 0;
     var clipExtent = [[0, 0], [0, 0]];
-    function projection2(point2) {
-      point2 = project(point2[0] * Math.PI / 180, point2[1] * Math.PI / 180);
-      return [point2[0] * k2 + x2, y2 - point2[1] * k2];
+    function projection2(point) {
+      point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
+      return [point[0] * k2 + x2, y2 - point[1] * k2];
     }
-    projection2.invert = function(point2) {
-      point2 = project.invert((point2[0] - x2) / k2, (y2 - point2[1]) / k2);
-      return point2 && [point2[0] * 180 / Math.PI, point2[1] * 180 / Math.PI];
+    projection2.invert = function(point) {
+      point = project.invert((point[0] - x2) / k2, (y2 - point[1]) / k2);
+      return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
     };
     projection2.scale = function(_2) {
-      if (!arguments.length)
-        return k2;
+      if (!arguments.length) return k2;
       k2 = +_2;
       return projection2;
     };
     projection2.translate = function(_2) {
-      if (!arguments.length)
-        return [x2, y2];
+      if (!arguments.length) return [x2, y2];
       x2 = +_2[0];
       y2 = +_2[1];
       return projection2;
     };
     projection2.clipExtent = function(_2) {
-      if (!arguments.length)
-        return clipExtent;
+      if (!arguments.length) return clipExtent;
       clipExtent = _2;
       return projection2;
     };
     projection2.transform = function(obj) {
-      if (!arguments.length)
-        return identity2.translate(x2, y2).scale(k2);
+      if (!arguments.length) return identity2.translate(x2, y2).scale(k2);
       x2 = +obj.x;
       y2 = +obj.y;
       k2 = +obj.k;
       var origin = coords[i3];
       var b2 = coords[(i3 + 1) % coords.length];
       var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a2, b2, origin), epsilon3, lowerThreshold, upperThreshold);
-      if (dotp === null)
-        continue;
+      if (dotp === null) continue;
       score = score + 2 * Math.min(Math.abs(dotp - 1), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
     }
     return score;
       var b2 = coords[(i3 + 1) % coords.length];
       var normalizedDotP = geoOrthoNormalizedDotProduct(a2, b2, origin);
       var angle2 = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI;
-      if (angle2 > 45)
-        angle2 = 90 - angle2;
-      if (angle2 >= lessThan)
-        continue;
-      if (angle2 > max3)
-        max3 = angle2;
+      if (angle2 > 45) angle2 = 90 - angle2;
+      if (angle2 >= lessThan) continue;
+      if (angle2 > max3) max3 = angle2;
     }
-    if (max3 === -Infinity)
-      return null;
+    if (max3 === -Infinity) return null;
     return max3;
   }
   function geoOrthoCanOrthogonalize(coords, isClosed, epsilon3, threshold, allowStraightAngles) {
       var origin = coords[i3];
       var b2 = coords[(i3 + 1) % coords.length];
       var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a2, b2, origin), epsilon3, lowerThreshold, upperThreshold, allowStraightAngles);
-      if (dotp === null)
-        continue;
-      if (Math.abs(dotp) > 0)
-        return 1;
+      if (dotp === null) continue;
+      if (Math.abs(dotp) > 0) return 1;
       score = 0;
     }
     return score;
     // nonexistent, might be built
     proposed: true,
     planned: true,
-    // under maintentance or between groundbreaking and opening
+    // under maintenance or between groundbreaking and opening
     construction: true,
     // existent but not functional
     disused: true,
   };
   function osmRemoveLifecyclePrefix(key) {
     const keySegments = key.split(":");
-    if (keySegments.length === 1)
-      return key;
+    if (keySegments.length === 1) return key;
     if (keySegments[0] in osmLifecyclePrefixes) {
       return key.slice(keySegments[0].length + 1);
     }
       station: true,
       traverser: true,
       turntable: true,
-      wash: true
+      wash: true,
+      ventilation_shaft: true
     },
     waterway: {
       dam: true
     }
   };
   function osmTagSuggestingArea(tags) {
-    if (tags.area === "yes")
-      return { area: "yes" };
-    if (tags.area === "no")
-      return null;
+    if (tags.area === "yes") return { area: "yes" };
+    if (tags.area === "no") return null;
     var returnTags = {};
     for (var realKey in tags) {
       const key = osmRemoveLifecyclePrefix(realKey);
       if (osmVertexTags[key] && (osmVertexTags[key]["*"] || osmVertexTags[key][nodeTags[key]])) {
         geometries.vertex = true;
       }
-      if (geometries.point && geometries.vertex)
-        break;
+      if (geometries.point && geometries.vertex) break;
     }
     return geometries;
   }
       "t-bar": true,
       "zip_line": true
     },
+    "conveying": {
+      "forward": true,
+      "backward": true,
+      "reversible": true
+    },
     "highway": {
       "motorway": true
     },
       "ditch": true,
       "drain": true,
       "fish_pass": true,
+      "flowline": true,
       "pressurised": true,
       "river": true,
       "spillway": true,
     bridleway: true,
     pedestrian: true,
     corridor: true,
-    steps: true
+    steps: true,
+    ladder: true
   };
   var osmPathHighwayTagValues = {
     path: true,
     bridleway: true,
     pedestrian: true,
     corridor: true,
-    steps: true
+    steps: true,
+    ladder: true
   };
   var osmRailwayTrackTagValues = {
     rail: true,
     ditch: true,
     drain: true,
     fish_pass: true,
+    flowline: true,
     river: true,
     stream: true,
     tidal_channel: true
 
   // modules/util/array.js
   function utilArrayIdentical(a2, b2) {
-    if (a2 === b2)
-      return true;
+    if (a2 === b2) return true;
     var i3 = a2.length;
-    if (i3 !== b2.length)
-      return false;
+    if (i3 !== b2.length) return false;
     while (i3--) {
-      if (a2[i3] !== b2[i3])
-        return false;
+      if (a2[i3] !== b2[i3]) return false;
     }
     return true;
   }
     return Array.from(new Set(a2));
   }
   function utilArrayChunk(a2, chunkSize) {
-    if (!chunkSize || chunkSize < 0)
-      return [a2.slice()];
+    if (!chunkSize || chunkSize < 0) return [a2.slice()];
     var result = new Array(Math.ceil(a2.length / chunkSize));
     return Array.from(result, function(item, i3) {
       return a2.slice(i3 * chunkSize, i3 * chunkSize + chunkSize);
   var _listeners = {};
   function corePreferences(k2, v2) {
     try {
-      if (v2 === void 0)
-        return _storage.getItem(k2);
-      else if (v2 === null)
-        _storage.removeItem(k2);
-      else
-        _storage.setItem(k2, v2);
+      if (v2 === void 0) return _storage.getItem(k2);
+      else if (v2 === null) _storage.removeItem(k2);
+      else _storage.setItem(k2, v2);
       if (_listeners[k2]) {
         _listeners[k2].forEach((handler) => handler(v2));
       }
     live: {
       url: "https://www.openstreetmap.org",
       apiUrl: "https://api.openstreetmap.org",
-      client_id: "0tmNTmd0Jo1dQp4AUmMBLtGiD9YpMuXzHefitcuVStc",
-      client_secret: "BTlNrNxIPitHdL4sP2clHw5KLoee9aKkA7dQbc0Bj7Q"
+      client_id: "0tmNTmd0Jo1dQp4AUmMBLtGiD9YpMuXzHefitcuVStc"
     },
     dev: {
       url: "https://api06.dev.openstreetmap.org",
-      client_id: "Ee1wWJ6UlpERbF6BfTNOpwn0R8k_06mvMXdDUkeHMgw",
-      client_secret: "OnfWFC-JkZNHyYdr_viNn_h_RTZXRslKcUxllOXqf5g"
+      client_id: "Ee1wWJ6UlpERbF6BfTNOpwn0R8k_06mvMXdDUkeHMgw"
     }
   };
   var osmApiConnections = [];
   if (false) {
     osmApiConnections.push({
       url: null,
-      apiUrl: ENV__ID_API_CONNECTION_API_URL,
-      client_id: null,
-      client_secret: null
+      apiUrl: null,
+      client_id: null
     });
   } else if (false) {
     osmApiConnections.push(defaultOsmApiConnections[null]);
   // package.json
   var package_default = {
     name: "iD",
-    version: "2.29.0",
+    version: "2.30.4",
     description: "A friendly editor for OpenStreetMap",
     main: "dist/iD.min.js",
     repository: "github:openstreetmap/iD",
       "dist:svg:roentgen": 'svg-sprite --shape-id-generator "roentgen-%s" --shape-dim-width 16 --shape-dim-height 16 --symbol --symbol-dest . --symbol-sprite dist/img/roentgen-sprite.svg svg/roentgen/*.svg',
       "dist:svg:temaki": 'svg-sprite --symbol --symbol-dest . --shape-id-generator "temaki-%s" --symbol-sprite dist/img/temaki-sprite.svg node_modules/@rapideditor/temaki/icons/*.svg',
       imagery: "node scripts/update_imagery.js",
-      lint: "eslint config scripts test/spec modules -c config/eslint.config.mjs",
-      "lint:fix": "eslint scripts test/spec modules -c config/eslint.config.mjs --fix",
+      lint: "eslint config scripts test/spec modules",
+      "lint:fix": "eslint scripts test/spec modules --fix",
       start: "run-s start:watch",
       "start:single-build": "run-p build:js start:server",
       "start:watch": "run-p build:js:watch start:server",
     dependencies: {
       "@mapbox/geojson-area": "^0.2.2",
       "@mapbox/sexagesimal": "1.2.0",
-      "@mapbox/vector-tile": "^1.3.1",
-      "@rapideditor/country-coder": "~5.2.2",
-      "@rapideditor/location-conflation": "~1.3.0",
+      "@mapbox/vector-tile": "^2.0.3",
+      "@rapideditor/country-coder": "~5.3.0",
+      "@rapideditor/location-conflation": "~1.4.0",
       "@tmcw/togeojson": "^5.8.1",
-      "@turf/bbox": "^6.0.0",
-      "@turf/bbox-clip": "^6.0.0",
+      "@turf/bbox": "^7.1.0",
+      "@turf/bbox-clip": "^7.1.0",
       "abortcontroller-polyfill": "^1.7.5",
       "aes-js": "^3.1.2",
-      "alif-toolkit": "^1.2.9",
-      "core-js-bundle": "^3.37.0",
+      "alif-toolkit": "^1.3.0",
+      "core-js-bundle": "^3.38.0",
       diacritics: "1.3.0",
       exifr: "^7.1.3",
       "fast-deep-equal": "~3.1.1",
       "fast-json-stable-stringify": "2.1.0",
       "lodash-es": "~4.17.15",
-      marked: "~12.0.2",
+      marked: "~14.0.0",
       "node-diff3": "~3.1.0",
-      "osm-auth": "~2.4.0",
+      "osm-auth": "~2.5.0",
       pannellum: "2.5.6",
-      pbf: "^3.2.1",
+      pbf: "^4.0.1",
       "polygon-clipping": "~0.15.7",
-      rbush: "3.0.1",
+      rbush: "4.0.0",
       "whatwg-fetch": "^3.6.20",
       "which-polygon": "2.2.1"
     },
     devDependencies: {
-      "@fortawesome/fontawesome-svg-core": "~6.5.2",
-      "@fortawesome/free-brands-svg-icons": "~6.5.2",
-      "@fortawesome/free-regular-svg-icons": "~6.5.2",
-      "@fortawesome/free-solid-svg-icons": "~6.5.2",
+      "@fortawesome/fontawesome-svg-core": "~6.6.0",
+      "@fortawesome/free-brands-svg-icons": "~6.6.0",
+      "@fortawesome/free-regular-svg-icons": "~6.6.0",
+      "@fortawesome/free-solid-svg-icons": "~6.6.0",
       "@mapbox/maki": "^8.0.1",
-      "@openstreetmap/id-tagging-schema": "^6.7.3",
+      "@openstreetmap/id-tagging-schema": "^6.8.1",
       "@rapideditor/mapillary_sprite_source": "^1.8.0",
-      "@rapideditor/temaki": "^5.8.0",
-      "@transifex/api": "^7.1.0",
-      autoprefixer: "^10.4.19",
-      browserslist: "^4.23.0",
+      "@rapideditor/temaki": "^5.9.0",
+      "@transifex/api": "^7.1.2",
+      autoprefixer: "^10.4.20",
+      browserslist: "^4.23.3",
       "browserslist-to-esbuild": "^2.1.1",
-      chai: "^4.4.1",
+      chai: "^4.5.0",
       chalk: "^4.1.2",
       "cldr-core": "^45.0.0",
       "cldr-localenames-full": "^45.0.0",
       d3: "~7.9.0",
       dotenv: "^16.4.5",
       "editor-layer-index": "github:osmlab/editor-layer-index#gh-pages",
-      esbuild: "^0.20.2",
+      esbuild: "^0.23.1",
       "esbuild-visualizer": "^0.6.0",
-      eslint: "^9.1.1",
+      eslint: "^9.9.0",
       "fetch-mock": "^9.11.0",
       gaze: "^1.1.3",
-      glob: "^10.3.12",
+      glob: "^10.4.5",
       happen: "^0.3.2",
       "js-yaml": "^4.0.0",
       "json-stringify-pretty-compact": "^3.0.0",
-      karma: "^6.4.3",
+      karma: "^6.4.4",
       "karma-chrome-launcher": "^3.2.0",
       "karma-coverage": "2.1.1",
       "karma-mocha": "^2.0.1",
       "karma-remap-istanbul": "^0.6.0",
       "mapillary-js": "4.1.2",
       minimist: "^1.2.8",
-      mocha: "^10.4.0",
+      mocha: "^10.7.3",
       "name-suggestion-index": "~6.0",
       "npm-run-all": "^4.0.0",
-      "osm-community-index": "~5.6.2",
-      postcss: "^8.4.38",
+      "osm-community-index": "~5.8.0",
+      postcss: "^8.4.41",
       "postcss-selector-prepend": "^0.5.0",
       shelljs: "^0.8.0",
       shx: "^0.3.0",
           return getUrl(url.replace("{presets_version}", presetsVersion2), which);
         });
       } else {
-        return getUrl(url);
+        return getUrl(url, which);
       }
     };
     function getUrl(url, which) {
           if (!response.ok || !response.json) {
             throw new Error(response.status + " " + response.statusText);
           }
-          if (response.status === 204 || response.status === 205)
-            return;
+          if (response.status === 204 || response.status === 205) return;
           return response.json();
         }).then((result) => {
           delete _inflight4[url];
       return prom;
     }
     _this.fileMap = function(val) {
-      if (!arguments.length)
-        return _fileMap;
+      if (!arguments.length) return _fileMap;
       _fileMap = val;
       return _this;
     };
     let _assetPath = "";
     _this.assetPath = function(val) {
-      if (!arguments.length)
-        return _assetPath;
+      if (!arguments.length) return _assetPath;
       _assetPath = val;
       return _this;
     };
     let _assetMap = {};
     _this.assetMap = function(val) {
-      if (!arguments.length)
-        return _assetMap;
+      if (!arguments.length) return _assetMap;
       _assetMap = val;
       return _this;
     };
     _this.asset = (val) => {
-      if (/^http(s)?:\/\//i.test(val))
-        return val;
+      if (/^http(s)?:\/\//i.test(val)) return val;
       const filename = _assetPath + val;
       return _assetMap[filename] || filename;
     };
     { type: "Feature", properties: { m49: "155", wikidata: "Q27496", nameEn: "Western Europe", level: "subregion" }, geometry: null },
     { type: "Feature", properties: { m49: "202", wikidata: "Q132959", nameEn: "Sub-Saharan Africa", level: "subregion" }, geometry: null },
     { type: "Feature", properties: { m49: "419", wikidata: "Q72829598", nameEn: "Latin America and the Caribbean", level: "subregion" }, geometry: null },
-    { type: "Feature", properties: { m49: "680", wikidata: "Q3405693", nameEn: "Sark", country: "GB", groups: ["GG", "830", "Q185086", "154", "150", "UN"], level: "subterritory", driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["44 01481"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-2.36485, 49.48223], [-2.65349, 49.15373], [-2.09454, 49.46288], [-2.36485, 49.48223]]]] } },
     { type: "Feature", properties: { m49: "830", wikidata: "Q42314", nameEn: "Channel Islands", level: "intermediateRegion" }, geometry: null },
     { type: "Feature", properties: { iso1A2: "AC", iso1A3: "ASC", wikidata: "Q46197", nameEn: "Ascension Island", aliases: ["SH-AC"], country: "GB", groups: ["SH", "BOTS", "011", "202", "002", "UN"], isoStatus: "excRes", driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["247"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-14.82771, -8.70814], [-13.33271, -8.07391], [-14.91926, -6.63386], [-14.82771, -8.70814]]]] } },
     { type: "Feature", properties: { iso1A2: "AD", iso1A3: "AND", iso1N3: "020", wikidata: "Q228", nameEn: "Andorra", groups: ["Q12837", "039", "150", "UN"], callingCodes: ["376"] }, geometry: { type: "MultiPolygon", coordinates: [[[[1.72515, 42.50338], [1.73683, 42.55492], [1.7858, 42.57698], [1.72588, 42.59098], [1.73452, 42.61515], [1.68267, 42.62533], [1.6625, 42.61982], [1.63485, 42.62957], [1.60085, 42.62703], [1.55418, 42.65669], [1.50867, 42.64483], [1.48043, 42.65203], [1.46718, 42.63296], [1.47986, 42.61346], [1.44197, 42.60217], [1.42512, 42.58292], [1.44529, 42.56722], [1.4234, 42.55959], [1.41245, 42.53539], [1.44759, 42.54431], [1.46661, 42.50949], [1.41648, 42.48315], [1.43838, 42.47848], [1.44529, 42.43724], [1.5127, 42.42959], [1.55073, 42.43299], [1.55937, 42.45808], [1.57953, 42.44957], [1.58933, 42.46275], [1.65674, 42.47125], [1.66826, 42.50779], [1.70571, 42.48867], [1.72515, 42.50338]]]] } },
     { type: "Feature", properties: { iso1A2: "CN", iso1A3: "CHN", iso1N3: "156", wikidata: "Q148", nameEn: "People's Republic of China" }, geometry: null },
     { type: "Feature", properties: { iso1A2: "CO", iso1A3: "COL", iso1N3: "170", wikidata: "Q739", nameEn: "Colombia", groups: ["005", "419", "019", "UN"], callingCodes: ["57"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-71.19849, 12.65801], [-81.58685, 18.0025], [-82.06974, 14.49418], [-82.56142, 11.91792], [-78.79327, 9.93766], [-77.58292, 9.22278], [-77.32389, 8.81247], [-77.45064, 8.49991], [-77.17257, 7.97422], [-77.57185, 7.51147], [-77.72514, 7.72348], [-77.72157, 7.47612], [-77.81426, 7.48319], [-77.89178, 7.22681], [-78.06168, 7.07793], [-82.12561, 4.00341], [-78.87137, 1.47457], [-78.42749, 1.15389], [-77.85677, 0.80197], [-77.7148, 0.85003], [-77.68613, 0.83029], [-77.66416, 0.81604], [-77.67815, 0.73863], [-77.49984, 0.64476], [-77.52001, 0.40782], [-76.89177, 0.24736], [-76.4094, 0.24015], [-76.41215, 0.38228], [-76.23441, 0.42294], [-75.82927, 0.09578], [-75.25764, -0.11943], [-75.18513, -0.0308], [-74.42701, -0.50218], [-74.26675, -0.97229], [-73.65312, -1.26222], [-72.92587, -2.44514], [-71.75223, -2.15058], [-70.94377, -2.23142], [-70.04609, -2.73906], [-70.71396, -3.7921], [-70.52393, -3.87553], [-70.3374, -3.79505], [-69.94708, -4.2431], [-69.43395, -1.42219], [-69.4215, -1.01853], [-69.59796, -0.75136], [-69.603, -0.51947], [-70.03658, -0.19681], [-70.04162, 0.55437], [-69.47696, 0.71065], [-69.20976, 0.57958], [-69.14422, 0.84172], [-69.26017, 1.06856], [-69.82987, 1.07864], [-69.83491, 1.69353], [-69.53746, 1.76408], [-69.38621, 1.70865], [-68.18128, 1.72881], [-68.26699, 1.83463], [-68.18632, 2.00091], [-67.9292, 1.82455], [-67.40488, 2.22258], [-67.299, 1.87494], [-67.15784, 1.80439], [-67.08222, 1.17441], [-66.85795, 1.22998], [-67.21967, 2.35778], [-67.65696, 2.81691], [-67.85862, 2.79173], [-67.85862, 2.86727], [-67.30945, 3.38393], [-67.50067, 3.75812], [-67.62671, 3.74303], [-67.85358, 4.53249], [-67.83341, 5.31104], [-67.59141, 5.5369], [-67.63914, 5.64963], [-67.58558, 5.84537], [-67.43513, 5.98835], [-67.4625, 6.20625], [-67.60654, 6.2891], [-69.41843, 6.1072], [-70.10716, 6.96516], [-70.7596, 7.09799], [-71.03941, 6.98163], [-71.37234, 7.01588], [-71.42212, 7.03854], [-71.44118, 7.02116], [-71.82441, 7.04314], [-72.04895, 7.03837], [-72.19437, 7.37034], [-72.43132, 7.40034], [-72.47415, 7.48928], [-72.45321, 7.57232], [-72.47827, 7.65604], [-72.46763, 7.79518], [-72.44454, 7.86031], [-72.46183, 7.90682], [-72.45806, 7.91141], [-72.47042, 7.92306], [-72.48183, 7.92909], [-72.48801, 7.94329], [-72.47213, 7.96106], [-72.39137, 8.03534], [-72.35163, 8.01163], [-72.36987, 8.19976], [-72.4042, 8.36513], [-72.65474, 8.61428], [-72.77415, 9.10165], [-72.94052, 9.10663], [-73.02119, 9.27584], [-73.36905, 9.16636], [-72.98085, 9.85253], [-72.88002, 10.44309], [-72.4767, 11.1117], [-72.24983, 11.14138], [-71.9675, 11.65536], [-71.3275, 11.85], [-70.92579, 11.96275], [-71.19849, 12.65801]]]] } },
     { type: "Feature", properties: { iso1A2: "CP", iso1A3: "CPT", wikidata: "Q161258", nameEn: "Clipperton Island", country: "FR", groups: ["EU", "013", "003", "019", "UN"], isoStatus: "excRes" }, geometry: { type: "MultiPolygon", coordinates: [[[[-110.36279, 9.79626], [-108.755, 9.84085], [-109.04145, 11.13245], [-110.36279, 9.79626]]]] } },
+    { type: "Feature", properties: { iso1A2: "CQ", iso1A3: "CRQ", iso1N3: "680", m49: "680", wikidata: "Q3405693", ccTLD: null, nameEn: "Sark", country: "GB", groups: ["GG", "830", "Q185086", "154", "150", "UN"], level: "subterritory", isoStatus: "excRes", driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["44 01481"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-2.36485, 49.48223], [-2.65349, 49.15373], [-2.09454, 49.46288], [-2.36485, 49.48223]]]] } },
     { type: "Feature", properties: { iso1A2: "CR", iso1A3: "CRI", iso1N3: "188", wikidata: "Q800", nameEn: "Costa Rica", groups: ["013", "003", "419", "019", "UN"], callingCodes: ["506"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-83.68276, 11.01562], [-83.66597, 10.79916], [-83.90838, 10.71161], [-84.68197, 11.07568], [-84.92439, 10.9497], [-85.60529, 11.22607], [-85.71223, 11.06868], [-86.14524, 11.09059], [-87.41779, 5.02401], [-82.94503, 7.93865], [-82.89978, 8.04083], [-82.89137, 8.05755], [-82.88641, 8.10219], [-82.9388, 8.26634], [-83.05209, 8.33394], [-82.93056, 8.43465], [-82.8679, 8.44042], [-82.8382, 8.48117], [-82.83322, 8.52464], [-82.83975, 8.54755], [-82.82739, 8.60153], [-82.8794, 8.6981], [-82.92068, 8.74832], [-82.91377, 8.774], [-82.88253, 8.83331], [-82.72126, 8.97125], [-82.93516, 9.07687], [-82.93516, 9.46741], [-82.84871, 9.4973], [-82.87919, 9.62645], [-82.77206, 9.59573], [-82.66667, 9.49746], [-82.61345, 9.49881], [-82.56507, 9.57279], [-82.51044, 9.65379], [-83.54024, 10.96805], [-83.68276, 11.01562]]]] } },
     { type: "Feature", properties: { iso1A2: "CU", iso1A3: "CUB", iso1N3: "192", wikidata: "Q241", nameEn: "Cuba", groups: ["029", "003", "419", "019", "UN"], callingCodes: ["53"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-73.62304, 20.6935], [-82.02215, 24.23074], [-85.77883, 21.92705], [-74.81171, 18.82201], [-73.62304, 20.6935]]]] } },
     { type: "Feature", properties: { iso1A2: "CV", iso1A3: "CPV", iso1N3: "132", wikidata: "Q1011", nameEn: "Cape Verde", groups: ["Q105472", "011", "202", "002", "UN"], callingCodes: ["238"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-28.81604, 14.57305], [-20.39702, 14.12816], [-23.37101, 19.134], [-28.81604, 14.57305]]]] } },
     }
     function loadTLD(feature22) {
       const props = feature22.properties;
-      if (props.level === "unitedNations")
-        return;
+      if (props.level === "unitedNations") return;
+      if (props.ccTLD === null) return;
       if (!props.ccTLD && props.iso1A2) {
         props.ccTLD = "." + props.iso1A2.toLowerCase();
       }
     }
     function loadLevel(feature22) {
       const props = feature22.properties;
-      if (props.level)
-        return;
+      if (props.level) return;
       if (!props.country) {
         props.level = "country";
       } else if (!props.iso1A2 || props.isoStatus === "official") {
     }
     function loadGroupGroups(feature22) {
       const props = feature22.properties;
-      if (feature22.geometry || !props.members)
-        return;
+      if (feature22.geometry || !props.members) return;
       const featureLevelIndex = levels.indexOf(props.level);
       let sharedGroups = [];
       props.members.forEach((memberID, index) => {
     function loadRoadSpeedUnit(feature22) {
       const props = feature22.properties;
       if (feature22.geometry) {
-        if (!props.roadSpeedUnit)
-          props.roadSpeedUnit = "km/h";
+        if (!props.roadSpeedUnit) props.roadSpeedUnit = "km/h";
       } else if (props.members) {
         const vals = Array.from(
           new Set(
             props.members.map((id2) => {
               const member = _featuresByCode[id2];
-              if (member.geometry)
-                return member.properties.roadSpeedUnit || "km/h";
+              if (member.geometry) return member.properties.roadSpeedUnit || "km/h";
             }).filter(Boolean)
           )
         );
-        if (vals.length === 1)
-          props.roadSpeedUnit = vals[0];
+        if (vals.length === 1) props.roadSpeedUnit = vals[0];
       }
     }
     function loadRoadHeightUnit(feature22) {
       const props = feature22.properties;
       if (feature22.geometry) {
-        if (!props.roadHeightUnit)
-          props.roadHeightUnit = "m";
+        if (!props.roadHeightUnit) props.roadHeightUnit = "m";
       } else if (props.members) {
         const vals = Array.from(
           new Set(
             props.members.map((id2) => {
               const member = _featuresByCode[id2];
-              if (member.geometry)
-                return member.properties.roadHeightUnit || "m";
+              if (member.geometry) return member.properties.roadHeightUnit || "m";
             }).filter(Boolean)
           )
         );
-        if (vals.length === 1)
-          props.roadHeightUnit = vals[0];
+        if (vals.length === 1) props.roadHeightUnit = vals[0];
       }
     }
     function loadDriveSide(feature22) {
       const props = feature22.properties;
       if (feature22.geometry) {
-        if (!props.driveSide)
-          props.driveSide = "right";
+        if (!props.driveSide) props.driveSide = "right";
       } else if (props.members) {
         const vals = Array.from(
           new Set(
             props.members.map((id2) => {
               const member = _featuresByCode[id2];
-              if (member.geometry)
-                return member.properties.driveSide || "right";
+              if (member.geometry) return member.properties.driveSide || "right";
             }).filter(Boolean)
           )
         );
-        if (vals.length === 1)
-          props.driveSide = vals[0];
+        if (vals.length === 1) props.driveSide = vals[0];
       }
     }
     function loadCallingCodes(feature22) {
       }
     }
     function loadFlag(feature22) {
-      if (!feature22.properties.iso1A2)
-        return;
+      if (!feature22.properties.iso1A2) return;
       const flag = feature22.properties.iso1A2.replace(/./g, function(char) {
         return String.fromCodePoint(char.charCodeAt(0) + 127397);
       });
   function smallestFeature(loc) {
     const query = locArray(loc);
     const featureProperties = _whichPolygon(query);
-    if (!featureProperties)
-      return null;
+    if (!featureProperties) return null;
     return _featuresByCode[featureProperties.id];
   }
   function countryFeature(loc) {
     const feature22 = smallestFeature(loc);
-    if (!feature22)
-      return null;
+    if (!feature22) return null;
     const countryCode = feature22.properties.country || feature22.properties.iso1A2;
     return _featuresByCode[countryCode] || null;
   }
     const maxLevel = opts.maxLevel || "world";
     const withProp = opts.withProp;
     const targetLevelIndex = levels.indexOf(targetLevel);
-    if (targetLevelIndex === -1)
-      return null;
+    if (targetLevelIndex === -1) return null;
     const maxLevelIndex = levels.indexOf(maxLevel);
-    if (maxLevelIndex === -1)
-      return null;
-    if (maxLevelIndex < targetLevelIndex)
-      return null;
+    if (maxLevelIndex === -1) return null;
+    if (maxLevelIndex < targetLevelIndex) return null;
     if (targetLevel === "country") {
       const fastFeature = countryFeature(loc);
       if (fastFeature) {
   function iso1A2Code(query, opts = defaultOpts) {
     opts.withProp = "iso1A2";
     const match = feature(query, opts);
-    if (!match)
-      return null;
+    if (!match) return null;
     return match.properties.iso1A2 || null;
   }
   function propertiesForQuery(query, property) {
       const smallestOrMatching = smallestOrMatchingFeature(query);
       matchingFeatures = smallestOrMatching ? [smallestOrMatching] : [];
     }
-    if (!matchingFeatures.length)
-      return [];
+    if (!matchingFeatures.length) return [];
     let returnFeatures;
     if (!strict || typeof query === "object") {
       returnFeatures = matchingFeatures.slice();
   }
   function featuresIn(id2, strict) {
     const feature22 = featureForID(id2);
-    if (!feature22)
-      return [];
+    if (!feature22) return [];
     let features = [];
     if (!strict) {
       features.push(feature22);
     return features;
   }
   function aggregateFeature(id2) {
-    var _a2;
+    var _a3;
     const features = featuresIn(id2, false);
-    if (features.length === 0)
-      return null;
+    if (features.length === 0) return null;
     let aggregateCoordinates = [];
     for (const feature22 of features) {
-      if (((_a2 = feature22.geometry) == null ? void 0 : _a2.type) === "MultiPolygon" && feature22.geometry.coordinates) {
+      if (((_a3 = feature22.geometry) == null ? void 0 : _a3.type) === "MultiPolygon" && feature22.geometry.coordinates) {
         aggregateCoordinates = aggregateCoordinates.concat(feature22.geometry.coordinates);
       }
     }
     }, ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz", alphabetHasNormalDecimalDigits = true;
     function BigNumber2(v2, b2) {
       var alphabet, c2, caseChanged, e3, i3, isNum, len, str, x2 = this;
-      if (!(x2 instanceof BigNumber2))
-        return new BigNumber2(v2, b2);
+      if (!(x2 instanceof BigNumber2)) return new BigNumber2(v2, b2);
       if (b2 == null) {
         if (v2 && v2._isBigNumber === true) {
           x2.s = v2.s;
         if ((isNum = typeof v2 == "number") && v2 * 0 == 0) {
           x2.s = 1 / v2 < 0 ? (v2 = -v2, -1) : 1;
           if (v2 === ~~v2) {
-            for (e3 = 0, i3 = v2; i3 >= 10; i3 /= 10, e3++)
-              ;
+            for (e3 = 0, i3 = v2; i3 >= 10; i3 /= 10, e3++) ;
             if (e3 > MAX_EXP) {
               x2.c = x2.e = null;
             } else {
           }
           str = String(v2);
         } else {
-          if (!isNumeric.test(str = String(v2)))
-            return parseNumeric2(x2, str, isNum);
+          if (!isNumeric.test(str = String(v2))) return parseNumeric2(x2, str, isNum);
           x2.s = str.charCodeAt(0) == 45 ? (str = str.slice(1), -1) : 1;
         }
-        if ((e3 = str.indexOf(".")) > -1)
-          str = str.replace(".", "");
+        if ((e3 = str.indexOf(".")) > -1) str = str.replace(".", "");
         if ((i3 = str.search(/e/i)) > 0) {
-          if (e3 < 0)
-            e3 = i3;
+          if (e3 < 0) e3 = i3;
           e3 += +str.slice(i3 + 1);
           str = str.substring(0, i3);
         } else if (e3 < 0) {
         }
         str = String(v2);
         if (isNum = typeof v2 == "number") {
-          if (v2 * 0 != 0)
-            return parseNumeric2(x2, str, isNum, b2);
+          if (v2 * 0 != 0) return parseNumeric2(x2, str, isNum, b2);
           x2.s = 1 / v2 < 0 ? (str = str.slice(1), -1) : 1;
           if (BigNumber2.DEBUG && str.replace(/^0\.0*|\./, "").length > 15) {
             throw Error(tooManyDigits + v2);
         }
         isNum = false;
         str = convertBase(str, b2, 10, x2.s);
-        if ((e3 = str.indexOf(".")) > -1)
-          str = str.replace(".", "");
-        else
-          e3 = str.length;
+        if ((e3 = str.indexOf(".")) > -1) str = str.replace(".", "");
+        else e3 = str.length;
       }
-      for (i3 = 0; str.charCodeAt(i3) === 48; i3++)
-        ;
-      for (len = str.length; str.charCodeAt(--len) === 48; )
-        ;
+      for (i3 = 0; str.charCodeAt(i3) === 48; i3++) ;
+      for (len = str.length; str.charCodeAt(--len) === 48; ) ;
       if (str = str.slice(i3, ++len)) {
         len -= i3;
         if (isNum && BigNumber2.DEBUG && len > 15 && (v2 > MAX_SAFE_INTEGER || v2 !== mathfloor(v2))) {
           x2.e = e3;
           x2.c = [];
           i3 = (e3 + 1) % LOG_BASE;
-          if (e3 < 0)
-            i3 += LOG_BASE;
+          if (e3 < 0) i3 += LOG_BASE;
           if (i3 < len) {
-            if (i3)
-              x2.c.push(+str.slice(0, i3));
+            if (i3) x2.c.push(+str.slice(0, i3));
             for (len -= LOG_BASE; i3 < len; ) {
               x2.c.push(+str.slice(i3, i3 += LOG_BASE));
             }
           } else {
             i3 -= len;
           }
-          for (; i3--; str += "0")
-            ;
+          for (; i3--; str += "0") ;
           x2.c.push(+str);
         }
       } else {
           }
           if (obj.hasOwnProperty(p2 = "FORMAT")) {
             v2 = obj[p2];
-            if (typeof v2 == "object")
-              FORMAT = v2;
-            else
-              throw Error(bignumberError + p2 + " not an object: " + v2);
+            if (typeof v2 == "object") FORMAT = v2;
+            else throw Error(bignumberError + p2 + " not an object: " + v2);
           }
           if (obj.hasOwnProperty(p2 = "ALPHABET")) {
             v2 = obj[p2];
       };
     };
     BigNumber2.isBigNumber = function(v2) {
-      if (!v2 || v2._isBigNumber !== true)
-        return false;
-      if (!BigNumber2.DEBUG)
-        return true;
+      if (!v2 || v2._isBigNumber !== true) return false;
+      if (!BigNumber2.DEBUG) return true;
       var i3, n3, c2 = v2.c, e3 = v2.e, s2 = v2.s;
-      out:
-        if ({}.toString.call(c2) == "[object Array]") {
-          if ((s2 === 1 || s2 === -1) && e3 >= -MAX && e3 <= MAX && e3 === mathfloor(e3)) {
-            if (c2[0] === 0) {
-              if (e3 === 0 && c2.length === 1)
-                return true;
-              break out;
-            }
-            i3 = (e3 + 1) % LOG_BASE;
-            if (i3 < 1)
-              i3 += LOG_BASE;
-            if (String(c2[0]).length == i3) {
-              for (i3 = 0; i3 < c2.length; i3++) {
-                n3 = c2[i3];
-                if (n3 < 0 || n3 >= BASE || n3 !== mathfloor(n3))
-                  break out;
-              }
-              if (n3 !== 0)
-                return true;
+      out: if ({}.toString.call(c2) == "[object Array]") {
+        if ((s2 === 1 || s2 === -1) && e3 >= -MAX && e3 <= MAX && e3 === mathfloor(e3)) {
+          if (c2[0] === 0) {
+            if (e3 === 0 && c2.length === 1) return true;
+            break out;
+          }
+          i3 = (e3 + 1) % LOG_BASE;
+          if (i3 < 1) i3 += LOG_BASE;
+          if (String(c2[0]).length == i3) {
+            for (i3 = 0; i3 < c2.length; i3++) {
+              n3 = c2[i3];
+              if (n3 < 0 || n3 >= BASE || n3 !== mathfloor(n3)) break out;
             }
+            if (n3 !== 0) return true;
           }
-        } else if (c2 === null && e3 === null && (s2 === null || s2 === 1 || s2 === -1)) {
-          return true;
         }
+      } else if (c2 === null && e3 === null && (s2 === null || s2 === 1 || s2 === -1)) {
+        return true;
+      }
       throw Error(bignumberError + "Invalid BigNumber: " + v2);
     };
     BigNumber2.maximum = BigNumber2.max = function() {
       };
       return function(dp) {
         var a2, b2, e3, k2, v2, i3 = 0, c2 = [], rand = new BigNumber2(ONE);
-        if (dp == null)
-          dp = DECIMAL_PLACES;
-        else
-          intCheck(dp, 0, MAX);
+        if (dp == null) dp = DECIMAL_PLACES;
+        else intCheck(dp, 0, MAX);
         k2 = mathceil(dp / LOG_BASE);
         if (CRYPTO) {
           if (crypto.getRandomValues) {
         if (!CRYPTO) {
           for (; i3 < k2; ) {
             v2 = random53bitInt();
-            if (v2 < 9e15)
-              c2[i3++] = v2 % 1e14;
+            if (v2 < 9e15) c2[i3++] = v2 % 1e14;
           }
         }
         k2 = c2[--i3];
           v2 = POWS_TEN[LOG_BASE - dp];
           c2[i3] = mathfloor(k2 / v2) * v2;
         }
-        for (; c2[i3] === 0; c2.pop(), i3--)
-          ;
+        for (; c2[i3] === 0; c2.pop(), i3--) ;
         if (i3 < 0) {
           c2 = [e3 = 0];
         } else {
-          for (e3 = -1; c2[0] === 0; c2.splice(0, 1), e3 -= LOG_BASE)
-            ;
-          for (i3 = 1, v2 = c2[0]; v2 >= 10; v2 /= 10, i3++)
-            ;
-          if (i3 < LOG_BASE)
-            e3 -= LOG_BASE - i3;
+          for (e3 = -1; c2[0] === 0; c2.splice(0, 1), e3 -= LOG_BASE) ;
+          for (i3 = 1, v2 = c2[0]; v2 >= 10; v2 /= 10, i3++) ;
+          if (i3 < LOG_BASE) e3 -= LOG_BASE - i3;
         }
         rand.e = e3;
         rand.c = c2;
     }();
     BigNumber2.sum = function() {
       var i3 = 1, args = arguments, sum = new BigNumber2(args[0]);
-      for (; i3 < args.length; )
-        sum = sum.plus(args[i3++]);
+      for (; i3 < args.length; ) sum = sum.plus(args[i3++]);
       return sum;
     };
     convertBase = /* @__PURE__ */ function() {
       function toBaseOut(str, baseIn, baseOut, alphabet) {
         var j2, arr = [0], arrL, i3 = 0, len = str.length;
         for (; i3 < len; ) {
-          for (arrL = arr.length; arrL--; arr[arrL] *= baseIn)
-            ;
+          for (arrL = arr.length; arrL--; arr[arrL] *= baseIn) ;
           arr[0] += alphabet.indexOf(str.charAt(i3++));
           for (j2 = 0; j2 < arr.length; j2++) {
             if (arr[j2] > baseOut - 1) {
-              if (arr[j2 + 1] == null)
-                arr[j2 + 1] = 0;
+              if (arr[j2 + 1] == null) arr[j2 + 1] = 0;
               arr[j2 + 1] += arr[j2] / baseOut | 0;
               arr[j2] %= baseOut;
             }
         }
         xc = toBaseOut(str, baseIn, baseOut, callerIsToString ? (alphabet = ALPHABET, decimal) : (alphabet = decimal, ALPHABET));
         e3 = k2 = xc.length;
-        for (; xc[--k2] == 0; xc.pop())
-          ;
-        if (!xc[0])
-          return alphabet.charAt(0);
+        for (; xc[--k2] == 0; xc.pop()) ;
+        if (!xc[0]) return alphabet.charAt(0);
         if (i3 < 0) {
           --e3;
         } else {
               }
             }
           }
-          for (k2 = xc.length; !xc[--k2]; )
-            ;
-          for (i3 = 0, str = ""; i3 <= k2; str += alphabet.charAt(xc[i3++]))
-            ;
+          for (k2 = xc.length; !xc[--k2]; ) ;
+          for (i3 = 0, str = ""; i3 <= k2; str += alphabet.charAt(xc[i3++])) ;
           str = toFixedPoint(str, e3, alphabet.charAt(0));
         }
         return str;
           carry = (temp / base | 0) + (m2 / SQRT_BASE | 0) + khi * xhi;
           x2[i3] = temp % base;
         }
-        if (carry)
-          x2 = [carry].concat(x2);
+        if (carry) x2 = [carry].concat(x2);
         return x2;
       }
       function compare2(a2, b2, aL, bL) {
           i3 = a2[aL] < b2[aL] ? 1 : 0;
           a2[aL] = i3 * base + a2[aL] - b2[aL];
         }
-        for (; !a2[0] && a2.length > 1; a2.splice(0, 1))
-          ;
+        for (; !a2[0] && a2.length > 1; a2.splice(0, 1)) ;
       }
       return function(x2, y2, dp, rm, base) {
         var cmp, e3, i3, more, n3, prod, prodL, q2, qc, rem, remL, rem0, xi, xL, yc0, yL, yz, s2 = x2.s == y2.s ? 1 : -1, xc = x2.c, yc = y2.c;
           e3 = bitFloor(x2.e / LOG_BASE) - bitFloor(y2.e / LOG_BASE);
           s2 = s2 / LOG_BASE | 0;
         }
-        for (i3 = 0; yc[i3] == (xc[i3] || 0); i3++)
-          ;
-        if (yc[i3] > (xc[i3] || 0))
-          e3--;
+        for (i3 = 0; yc[i3] == (xc[i3] || 0); i3++) ;
+        if (yc[i3] > (xc[i3] || 0)) e3--;
         if (s2 < 0) {
           qc.push(1);
           more = true;
           xi = yL;
           rem = xc.slice(0, yL);
           remL = rem.length;
-          for (; remL < yL; rem[remL++] = 0)
-            ;
+          for (; remL < yL; rem[remL++] = 0) ;
           yz = yc.slice();
           yz = [0].concat(yz);
           yc0 = yc[0];
-          if (yc[1] >= base / 2)
-            yc0++;
+          if (yc[1] >= base / 2) yc0++;
           do {
             n3 = 0;
             cmp = compare2(yc, rem, yL, remL);
             if (cmp < 0) {
               rem0 = rem[0];
-              if (yL != remL)
-                rem0 = rem0 * base + (rem[1] || 0);
+              if (yL != remL) rem0 = rem0 * base + (rem[1] || 0);
               n3 = mathfloor(rem0 / yc0);
               if (n3 > 1) {
-                if (n3 >= base)
-                  n3 = base - 1;
+                if (n3 >= base) n3 = base - 1;
                 prod = multiply(yc, n3, base);
                 prodL = prod.length;
                 remL = rem.length;
                 prod = yc.slice();
                 prodL = prod.length;
               }
-              if (prodL < remL)
-                prod = [0].concat(prod);
+              if (prodL < remL) prod = [0].concat(prod);
               subtract(rem, prod, remL, base);
               remL = rem.length;
               if (cmp == -1) {
             }
           } while ((xi++ < xL || rem[0] != null) && s2--);
           more = rem[0] != null;
-          if (!qc[0])
-            qc.splice(0, 1);
+          if (!qc[0]) qc.splice(0, 1);
         }
         if (base == BASE) {
-          for (i3 = 1, s2 = qc[0]; s2 >= 10; s2 /= 10, i3++)
-            ;
+          for (i3 = 1, s2 = qc[0]; s2 >= 10; s2 /= 10, i3++) ;
           round(q2, dp + (q2.e = i3 + e3 * LOG_BASE - 1) + 1, rm, more);
         } else {
           q2.e = e3;
     }();
     function format2(n3, i3, rm, id2) {
       var c0, e3, ne2, len, str;
-      if (rm == null)
-        rm = ROUNDING_MODE;
-      else
-        intCheck(rm, 0, 8);
-      if (!n3.c)
-        return n3.toString();
+      if (rm == null) rm = ROUNDING_MODE;
+      else intCheck(rm, 0, 8);
+      if (!n3.c) return n3.toString();
       c0 = n3.c[0];
       ne2 = n3.e;
       if (i3 == null) {
         str = coeffToString(n3.c);
         len = str.length;
         if (id2 == 1 || id2 == 2 && (i3 <= e3 || e3 <= TO_EXP_NEG)) {
-          for (; len < i3; str += "0", len++)
-            ;
+          for (; len < i3; str += "0", len++) ;
           str = toExponential(str, e3);
         } else {
           i3 -= ne2;
           str = toFixedPoint(str, e3, "0");
           if (e3 + 1 > len) {
-            if (--i3 > 0)
-              for (str += "."; i3--; str += "0")
-                ;
+            if (--i3 > 0) for (str += "."; i3--; str += "0") ;
           } else {
             i3 += e3 - len;
             if (i3 > 0) {
-              if (e3 + 1 == len)
-                str += ".";
-              for (; i3--; str += "0")
-                ;
+              if (e3 + 1 == len) str += ".";
+              for (; i3--; str += "0") ;
             }
           }
         }
     }
     function normalise(n3, c2, e3) {
       var i3 = 1, j2 = c2.length;
-      for (; !c2[--j2]; c2.pop())
-        ;
-      for (j2 = c2[0]; j2 >= 10; j2 /= 10, i3++)
-        ;
+      for (; !c2[--j2]; c2.pop()) ;
+      for (j2 = c2[0]; j2 >= 10; j2 /= 10, i3++) ;
       if ((e3 = i3 + e3 * LOG_BASE - 1) > MAX_EXP) {
         n3.c = n3.e = null;
       } else if (e3 < MIN_EXP) {
               base = b2;
               s2 = s2.replace(dotAfter, "$1").replace(dotBefore, "0.$1");
             }
-            if (str != s2)
-              return new BigNumber2(s2, base);
+            if (str != s2) return new BigNumber2(s2, base);
           }
           if (BigNumber2.DEBUG) {
             throw Error(bignumberError + "Not a" + (b2 ? " base " + b2 : "") + " number: " + str);
       var d2, i3, j2, k2, n3, ni, rd, xc = x2.c, pows10 = POWS_TEN;
       if (xc) {
         out: {
-          for (d2 = 1, k2 = xc[0]; k2 >= 10; k2 /= 10, d2++)
-            ;
+          for (d2 = 1, k2 = xc[0]; k2 >= 10; k2 /= 10, d2++) ;
           i3 = sd - d2;
           if (i3 < 0) {
             i3 += LOG_BASE;
             ni = mathceil((i3 + 1) / LOG_BASE);
             if (ni >= xc.length) {
               if (r2) {
-                for (; xc.length <= ni; xc.push(0))
-                  ;
+                for (; xc.length <= ni; xc.push(0)) ;
                 n3 = rd = 0;
                 d2 = 1;
                 i3 %= LOG_BASE;
               }
             } else {
               n3 = k2 = xc[ni];
-              for (d2 = 1; k2 >= 10; k2 /= 10, d2++)
-                ;
+              for (d2 = 1; k2 >= 10; k2 /= 10, d2++) ;
               i3 %= LOG_BASE;
               j2 = i3 - LOG_BASE + d2;
               rd = j2 < 0 ? 0 : mathfloor(n3 / pows10[d2 - j2 - 1] % 10);
           if (r2) {
             for (; ; ) {
               if (ni == 0) {
-                for (i3 = 1, j2 = xc[0]; j2 >= 10; j2 /= 10, i3++)
-                  ;
+                for (i3 = 1, j2 = xc[0]; j2 >= 10; j2 /= 10, i3++) ;
                 j2 = xc[0] += k2;
-                for (k2 = 1; j2 >= 10; j2 /= 10, k2++)
-                  ;
+                for (k2 = 1; j2 >= 10; j2 /= 10, k2++) ;
                 if (i3 != k2) {
                   x2.e++;
-                  if (xc[0] == BASE)
-                    xc[0] = 1;
+                  if (xc[0] == BASE) xc[0] = 1;
                 }
                 break;
               } else {
                 xc[ni] += k2;
-                if (xc[ni] != BASE)
-                  break;
+                if (xc[ni] != BASE) break;
                 xc[ni--] = 0;
                 k2 = 1;
               }
             }
           }
-          for (i3 = xc.length; xc[--i3] === 0; xc.pop())
-            ;
+          for (i3 = xc.length; xc[--i3] === 0; xc.pop()) ;
         }
         if (x2.e > MAX_EXP) {
           x2.c = x2.e = null;
     }
     function valueOf(n3) {
       var str, e3 = n3.e;
-      if (e3 === null)
-        return n3.toString();
+      if (e3 === null) return n3.toString();
       str = coeffToString(n3.c);
       str = e3 <= TO_EXP_NEG || e3 >= TO_EXP_POS ? toExponential(str, e3) : toFixedPoint(str, e3, "0");
       return n3.s < 0 ? "-" + str : str;
     }
     P2.absoluteValue = P2.abs = function() {
       var x2 = new BigNumber2(this);
-      if (x2.s < 0)
-        x2.s = 1;
+      if (x2.s < 0) x2.s = 1;
       return x2;
     };
     P2.comparedTo = function(y2, b2) {
       var c2, n3, v2, x2 = this;
       if (dp != null) {
         intCheck(dp, 0, MAX);
-        if (rm == null)
-          rm = ROUNDING_MODE;
-        else
-          intCheck(rm, 0, 8);
+        if (rm == null) rm = ROUNDING_MODE;
+        else intCheck(rm, 0, 8);
         return round(new BigNumber2(x2), dp + x2.e + 1, rm);
       }
-      if (!(c2 = x2.c))
-        return null;
+      if (!(c2 = x2.c)) return null;
       n3 = ((v2 = c2.length - 1) - bitFloor(this.e / LOG_BASE)) * LOG_BASE;
-      if (v2 = c2[v2])
-        for (; v2 % 10 == 0; v2 /= 10, n3--)
-          ;
-      if (n3 < 0)
-        n3 = 0;
+      if (v2 = c2[v2]) for (; v2 % 10 == 0; v2 /= 10, n3--) ;
+      if (n3 < 0) n3 = 0;
       return n3;
     };
     P2.dividedBy = P2.div = function(y2, b2) {
       if (n3.c && !n3.isInteger()) {
         throw Error(bignumberError + "Exponent not an integer: " + valueOf(n3));
       }
-      if (m2 != null)
-        m2 = new BigNumber2(m2);
+      if (m2 != null) m2 = new BigNumber2(m2);
       nIsBig = n3.e > 14;
       if (!x2.c || !x2.c[0] || x2.c[0] == 1 && !x2.e && x2.c.length == 1 || !n3.c || !n3.c[0]) {
         y2 = new BigNumber2(Math.pow(+valueOf(x2), nIsBig ? n3.s * (2 - isOdd(n3)) : +valueOf(n3)));
       }
       nIsNeg = n3.s < 0;
       if (m2) {
-        if (m2.c ? !m2.c[0] : !m2.s)
-          return new BigNumber2(NaN);
+        if (m2.c ? !m2.c[0] : !m2.s) return new BigNumber2(NaN);
         isModExp = !nIsNeg && x2.isInteger() && m2.isInteger();
-        if (isModExp)
-          x2 = x2.mod(m2);
+        if (isModExp) x2 = x2.mod(m2);
       } else if (n3.e > 9 && (x2.e > 0 || x2.e < -1 || (x2.e == 0 ? x2.c[0] > 1 || nIsBig && x2.c[1] >= 24e7 : x2.c[0] < 8e13 || nIsBig && x2.c[0] <= 9999975e7))) {
         k2 = x2.s < 0 && isOdd(n3) ? -0 : 0;
-        if (x2.e > -1)
-          k2 = 1 / k2;
+        if (x2.e > -1) k2 = 1 / k2;
         return new BigNumber2(nIsNeg ? 1 / k2 : k2);
       } else if (POW_PRECISION) {
         k2 = mathceil(POW_PRECISION / LOG_BASE + 2);
       }
       if (nIsBig) {
         half = new BigNumber2(0.5);
-        if (nIsNeg)
-          n3.s = 1;
+        if (nIsNeg) n3.s = 1;
         nIsOdd = isOdd(n3);
       } else {
         i3 = Math.abs(+valueOf(n3));
       for (; ; ) {
         if (nIsOdd) {
           y2 = y2.times(x2);
-          if (!y2.c)
-            break;
+          if (!y2.c) break;
           if (k2) {
-            if (y2.c.length > k2)
-              y2.c.length = k2;
+            if (y2.c.length > k2) y2.c.length = k2;
           } else if (isModExp) {
             y2 = y2.mod(m2);
           }
         }
         if (i3) {
           i3 = mathfloor(i3 / 2);
-          if (i3 === 0)
-            break;
+          if (i3 === 0) break;
           nIsOdd = i3 % 2;
         } else {
           n3 = n3.times(half);
             nIsOdd = isOdd(n3);
           } else {
             i3 = +valueOf(n3);
-            if (i3 === 0)
-              break;
+            if (i3 === 0) break;
             nIsOdd = i3 % 2;
           }
         }
         x2 = x2.times(x2);
         if (k2) {
-          if (x2.c && x2.c.length > k2)
-            x2.c.length = k2;
+          if (x2.c && x2.c.length > k2) x2.c.length = k2;
         } else if (isModExp) {
           x2 = x2.mod(m2);
         }
       }
-      if (isModExp)
-        return y2;
-      if (nIsNeg)
-        y2 = ONE.div(y2);
+      if (isModExp) return y2;
+      if (nIsNeg) y2 = ONE.div(y2);
       return m2 ? y2.mod(m2) : k2 ? round(y2, POW_PRECISION, ROUNDING_MODE, more) : y2;
     };
     P2.integerValue = function(rm) {
       var n3 = new BigNumber2(this);
-      if (rm == null)
-        rm = ROUNDING_MODE;
-      else
-        intCheck(rm, 0, 8);
+      if (rm == null) rm = ROUNDING_MODE;
+      else intCheck(rm, 0, 8);
       return round(n3, n3.e + 1, rm);
     };
     P2.isEqualTo = P2.eq = function(y2, b2) {
       var i3, j2, t2, xLTy, x2 = this, a2 = x2.s;
       y2 = new BigNumber2(y2, b2);
       b2 = y2.s;
-      if (!a2 || !b2)
-        return new BigNumber2(NaN);
+      if (!a2 || !b2) return new BigNumber2(NaN);
       if (a2 != b2) {
         y2.s = -b2;
         return x2.plus(y2);
       }
       var xe2 = x2.e / LOG_BASE, ye2 = y2.e / LOG_BASE, xc = x2.c, yc = y2.c;
       if (!xe2 || !ye2) {
-        if (!xc || !yc)
-          return xc ? (y2.s = -b2, y2) : new BigNumber2(yc ? x2 : NaN);
+        if (!xc || !yc) return xc ? (y2.s = -b2, y2) : new BigNumber2(yc ? x2 : NaN);
         if (!xc[0] || !yc[0]) {
           return yc[0] ? (y2.s = -b2, y2) : new BigNumber2(xc[0] ? x2 : (
             // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity
           t2 = yc;
         }
         t2.reverse();
-        for (b2 = a2; b2--; t2.push(0))
-          ;
+        for (b2 = a2; b2--; t2.push(0)) ;
         t2.reverse();
       } else {
         j2 = (xLTy = (a2 = xc.length) < (b2 = yc.length)) ? a2 : b2;
         y2.s = -y2.s;
       }
       b2 = (j2 = yc.length) - (i3 = xc.length);
-      if (b2 > 0)
-        for (; b2--; xc[i3++] = 0)
-          ;
+      if (b2 > 0) for (; b2--; xc[i3++] = 0) ;
       b2 = BASE - 1;
       for (; j2 > a2; ) {
         if (xc[--j2] < yc[j2]) {
-          for (i3 = j2; i3 && !xc[--i3]; xc[i3] = b2)
-            ;
+          for (i3 = j2; i3 && !xc[--i3]; xc[i3] = b2) ;
           --xc[i3];
           xc[j2] += BASE;
         }
         xc[j2] -= yc[j2];
       }
-      for (; xc[0] == 0; xc.splice(0, 1), --ye2)
-        ;
+      for (; xc[0] == 0; xc.splice(0, 1), --ye2) ;
       if (!xc[0]) {
         y2.s = ROUNDING_MODE == 3 ? -1 : 1;
         y2.c = [y2.e = 0];
         q2 = div(x2, y2, 0, MODULO_MODE);
       }
       y2 = x2.minus(q2.times(y2));
-      if (!y2.c[0] && MODULO_MODE == 1)
-        y2.s = x2.s;
+      if (!y2.c[0] && MODULO_MODE == 1) y2.s = x2.s;
       return y2;
     };
     P2.multipliedBy = P2.times = function(y2, b2) {
         xcL = ycL;
         ycL = i3;
       }
-      for (i3 = xcL + ycL, zc = []; i3--; zc.push(0))
-        ;
+      for (i3 = xcL + ycL, zc = []; i3--; zc.push(0)) ;
       base = BASE;
       sqrtBase = SQRT_BASE;
       for (i3 = ycL; --i3 >= 0; ) {
       var t2, x2 = this, a2 = x2.s;
       y2 = new BigNumber2(y2, b2);
       b2 = y2.s;
-      if (!a2 || !b2)
-        return new BigNumber2(NaN);
+      if (!a2 || !b2) return new BigNumber2(NaN);
       if (a2 != b2) {
         y2.s = -b2;
         return x2.minus(y2);
       }
       var xe2 = x2.e / LOG_BASE, ye2 = y2.e / LOG_BASE, xc = x2.c, yc = y2.c;
       if (!xe2 || !ye2) {
-        if (!xc || !yc)
-          return new BigNumber2(a2 / 0);
-        if (!xc[0] || !yc[0])
-          return yc[0] ? y2 : new BigNumber2(xc[0] ? x2 : a2 * 0);
+        if (!xc || !yc) return new BigNumber2(a2 / 0);
+        if (!xc[0] || !yc[0]) return yc[0] ? y2 : new BigNumber2(xc[0] ? x2 : a2 * 0);
       }
       xe2 = bitFloor(xe2);
       ye2 = bitFloor(ye2);
           t2 = xc;
         }
         t2.reverse();
-        for (; a2--; t2.push(0))
-          ;
+        for (; a2--; t2.push(0)) ;
         t2.reverse();
       }
       a2 = xc.length;
       var c2, n3, v2, x2 = this;
       if (sd != null && sd !== !!sd) {
         intCheck(sd, 1, MAX);
-        if (rm == null)
-          rm = ROUNDING_MODE;
-        else
-          intCheck(rm, 0, 8);
+        if (rm == null) rm = ROUNDING_MODE;
+        else intCheck(rm, 0, 8);
         return round(new BigNumber2(x2), sd, rm);
       }
-      if (!(c2 = x2.c))
-        return null;
+      if (!(c2 = x2.c)) return null;
       v2 = c2.length - 1;
       n3 = v2 * LOG_BASE + 1;
       if (v2 = c2[v2]) {
-        for (; v2 % 10 == 0; v2 /= 10, n3--)
-          ;
-        for (v2 = c2[0]; v2 >= 10; v2 /= 10, n3++)
-          ;
+        for (; v2 % 10 == 0; v2 /= 10, n3--) ;
+        for (v2 = c2[0]; v2 >= 10; v2 /= 10, n3++) ;
       }
-      if (sd && x2.e + 1 > n3)
-        n3 = x2.e + 1;
+      if (sd && x2.e + 1 > n3) n3 = x2.e + 1;
       return n3;
     };
     P2.shiftedBy = function(k2) {
       s2 = Math.sqrt(+valueOf(x2));
       if (s2 == 0 || s2 == 1 / 0) {
         n3 = coeffToString(c2);
-        if ((n3.length + e3) % 2 == 0)
-          n3 += "0";
+        if ((n3.length + e3) % 2 == 0) n3 += "0";
         s2 = Math.sqrt(+n3);
         e3 = bitFloor((e3 + 1) / 2) - (e3 < 0 || e3 % 2);
         if (s2 == 1 / 0) {
       if (r2.c[0]) {
         e3 = r2.e;
         s2 = e3 + dp;
-        if (s2 < 3)
-          s2 = 0;
+        if (s2 < 3) s2 = 0;
         for (; ; ) {
           t2 = r2;
           r2 = half.times(t2.plus(div(x2, t2, dp, 1)));
           if (coeffToString(t2.c).slice(0, s2) === (n3 = coeffToString(r2.c)).slice(0, s2)) {
-            if (r2.e < e3)
-              --s2;
+            if (r2.e < e3) --s2;
             n3 = n3.slice(s2 - 3, s2 + 1);
             if (n3 == "9999" || !rep && n3 == "4999") {
               if (!rep) {
         if (g1 > 0 && len > 0) {
           i3 = len % g1 || g1;
           intPart = intDigits.substr(0, i3);
-          for (; i3 < len; i3 += g1)
-            intPart += groupSeparator + intDigits.substr(i3, g1);
-          if (g22 > 0)
-            intPart += groupSeparator + intDigits.slice(i3);
-          if (isNeg)
-            intPart = "-" + intPart;
+          for (; i3 < len; i3 += g1) intPart += groupSeparator + intDigits.substr(i3, g1);
+          if (g22 > 0) intPart += groupSeparator + intDigits.slice(i3);
+          if (isNeg) intPart = "-" + intPart;
         }
         str = fractionPart ? intPart + (format3.decimalSeparator || "") + ((g22 = +format3.fractionGroupSize) ? fractionPart.replace(
           new RegExp("\\d{" + g22 + "}\\B", "g"),
           throw Error(bignumberError + "Argument " + (n3.isInteger() ? "out of range: " : "not an integer: ") + valueOf(n3));
         }
       }
-      if (!xc)
-        return new BigNumber2(x2);
+      if (!xc) return new BigNumber2(x2);
       d2 = new BigNumber2(ONE);
       n1 = d0 = new BigNumber2(ONE);
       d1 = n0 = new BigNumber2(ONE);
       for (; ; ) {
         q2 = div(n3, d2, 0, 1);
         d22 = d0.plus(q2.times(d1));
-        if (d22.comparedTo(md) == 1)
-          break;
+        if (d22.comparedTo(md) == 1) break;
         d0 = d1;
         d1 = d22;
         n1 = n0.plus(q2.times(d22 = n1));
       return +valueOf(this);
     };
     P2.toPrecision = function(sd, rm) {
-      if (sd != null)
-        intCheck(sd, 1, MAX);
+      if (sd != null) intCheck(sd, 1, MAX);
       return format2(this, sd, rm, 2);
     };
     P2.toString = function(b2) {
       if (e3 === null) {
         if (s2) {
           str = "Infinity";
-          if (s2 < 0)
-            str = "-" + str;
+          if (s2 < 0) str = "-" + str;
         } else {
           str = "NaN";
         }
           intCheck(b2, 2, ALPHABET.length, "Base");
           str = convertBase(toFixedPoint(coeffToString(n3.c), e3, "0"), 10, b2, s2, true);
         }
-        if (s2 < 0 && n3.c[0])
-          str = "-" + str;
+        if (s2 < 0 && n3.c[0]) str = "-" + str;
       }
       return str;
     };
     P2._isBigNumber = true;
     P2[Symbol.toStringTag] = "BigNumber";
     P2[Symbol.for("nodejs.util.inspect.custom")] = P2.valueOf;
-    if (configObject != null)
-      BigNumber2.set(configObject);
+    if (configObject != null) BigNumber2.set(configObject);
     return BigNumber2;
   }
   function bitFloor(n3) {
     for (; i3 < j2; ) {
       s2 = a2[i3++] + "";
       z2 = LOG_BASE - s2.length;
-      for (; z2--; s2 = "0" + s2)
-        ;
+      for (; z2--; s2 = "0" + s2) ;
       r2 += s2;
     }
-    for (j2 = r2.length; r2.charCodeAt(--j2) === 48; )
-      ;
+    for (j2 = r2.length; r2.charCodeAt(--j2) === 48; ) ;
     return r2.slice(0, j2 + 1 || 1);
   }
   function compare(x2, y2) {
     var a2, b2, xc = x2.c, yc = y2.c, i3 = x2.s, j2 = y2.s, k2 = x2.e, l2 = y2.e;
-    if (!i3 || !j2)
-      return null;
+    if (!i3 || !j2) return null;
     a2 = xc && !xc[0];
     b2 = yc && !yc[0];
-    if (a2 || b2)
-      return a2 ? b2 ? 0 : -j2 : i3;
-    if (i3 != j2)
-      return i3;
+    if (a2 || b2) return a2 ? b2 ? 0 : -j2 : i3;
+    if (i3 != j2) return i3;
     a2 = i3 < 0;
     b2 = k2 == l2;
-    if (!xc || !yc)
-      return b2 ? 0 : !xc ^ a2 ? 1 : -1;
-    if (!b2)
-      return k2 > l2 ^ a2 ? 1 : -1;
+    if (!xc || !yc) return b2 ? 0 : !xc ^ a2 ? 1 : -1;
+    if (!b2) return k2 > l2 ^ a2 ? 1 : -1;
     j2 = (k2 = xc.length) < (l2 = yc.length) ? k2 : l2;
-    for (i3 = 0; i3 < j2; i3++)
-      if (xc[i3] != yc[i3])
-        return xc[i3] > yc[i3] ^ a2 ? 1 : -1;
+    for (i3 = 0; i3 < j2; i3++) if (xc[i3] != yc[i3]) return xc[i3] > yc[i3] ^ a2 ? 1 : -1;
     return k2 == l2 ? 0 : k2 > l2 ^ a2 ? 1 : -1;
   }
   function intCheck(n3, min3, max3, name) {
   function toFixedPoint(str, e3, z2) {
     var len, zs;
     if (e3 < 0) {
-      for (zs = z2 + "."; ++e3; zs += z2)
-        ;
+      for (zs = z2 + "."; ++e3; zs += z2) ;
       str = zs + str;
     } else {
       len = str.length;
       if (++e3 > len) {
-        for (zs = z2, e3 -= len; --e3; zs += z2)
-          ;
+        for (zs = z2, e3 -= len; --e3; zs += z2) ;
         str += zs;
       } else if (e3 < len) {
         str = str.slice(0, e3) + "." + str.slice(e3);
       super(key);
     }
   };
+  var SplayTreeMapNode = class _SplayTreeMapNode extends SplayTreeNode {
+    constructor(key, value) {
+      super(key);
+      __publicField(this, "value");
+      this.value = value;
+    }
+    replaceValue(value) {
+      const node = new _SplayTreeMapNode(this.key, value);
+      node.left = this.left;
+      node.right = this.right;
+      return node;
+    }
+  };
   var SplayTree = class {
     constructor() {
       __publicField(this, "size", 0);
       };
     }
   };
-  var _a;
-  var _SplayTreeSet = class _SplayTreeSet extends SplayTree {
+  var _a, _b;
+  var SplayTreeMap = class extends SplayTree {
+    constructor(compare2, isValidKey) {
+      super();
+      __publicField(this, "root", null);
+      __publicField(this, "compare");
+      __publicField(this, "validKey");
+      __publicField(this, _a, "[object Map]");
+      this.compare = compare2 != null ? compare2 : this.defaultCompare();
+      this.validKey = isValidKey != null ? isValidKey : (a2) => a2 != null && a2 != void 0;
+    }
+    delete(key) {
+      if (!this.validKey(key))
+        return false;
+      return this._delete(key) != null;
+    }
+    forEach(f2) {
+      const nodes = new SplayTreeMapEntryIterableIterator(this.wrap());
+      let result;
+      while (result = nodes.next(), !result.done) {
+        f2(result.value[1], result.value[0], this);
+      }
+    }
+    get(key) {
+      if (!this.validKey(key))
+        return void 0;
+      if (this.root != null) {
+        const comp = this.splay(key);
+        if (comp == 0) {
+          return this.root.value;
+        }
+      }
+      return void 0;
+    }
+    hasValue(value) {
+      const initialSplayCount = this.splayCount;
+      const visit = (node) => {
+        while (node != null) {
+          if (node.value == value)
+            return true;
+          if (initialSplayCount != this.splayCount) {
+            throw "Concurrent modification during iteration.";
+          }
+          if (node.right != null && visit(node.right)) {
+            return true;
+          }
+          node = node.left;
+        }
+        return false;
+      };
+      return visit(this.root);
+    }
+    set(key, value) {
+      const comp = this.splay(key);
+      if (comp == 0) {
+        this.root = this.root.replaceValue(value);
+        this.splayCount += 1;
+        return this;
+      }
+      this.addNewRoot(new SplayTreeMapNode(key, value), comp);
+      return this;
+    }
+    setAll(other) {
+      other.forEach((value, key) => {
+        this.set(key, value);
+      });
+    }
+    setIfAbsent(key, ifAbsent) {
+      let comp = this.splay(key);
+      if (comp == 0) {
+        return this.root.value;
+      }
+      const modificationCount = this.modificationCount;
+      const splayCount = this.splayCount;
+      const value = ifAbsent();
+      if (modificationCount != this.modificationCount) {
+        throw "Concurrent modification during iteration.";
+      }
+      if (splayCount != this.splayCount) {
+        comp = this.splay(key);
+      }
+      this.addNewRoot(new SplayTreeMapNode(key, value), comp);
+      return value;
+    }
+    isEmpty() {
+      return this.root == null;
+    }
+    isNotEmpty() {
+      return !this.isEmpty();
+    }
+    firstKey() {
+      if (this.root == null)
+        return null;
+      return this._first().key;
+    }
+    lastKey() {
+      if (this.root == null)
+        return null;
+      return this._last().key;
+    }
+    lastKeyBefore(key) {
+      if (key == null)
+        throw "Invalid arguments(s)";
+      if (this.root == null)
+        return null;
+      const comp = this.splay(key);
+      if (comp < 0)
+        return this.root.key;
+      let node = this.root.left;
+      if (node == null)
+        return null;
+      let nodeRight = node.right;
+      while (nodeRight != null) {
+        node = nodeRight;
+        nodeRight = node.right;
+      }
+      return node.key;
+    }
+    firstKeyAfter(key) {
+      if (key == null)
+        throw "Invalid arguments(s)";
+      if (this.root == null)
+        return null;
+      const comp = this.splay(key);
+      if (comp > 0)
+        return this.root.key;
+      let node = this.root.right;
+      if (node == null)
+        return null;
+      let nodeLeft = node.left;
+      while (nodeLeft != null) {
+        node = nodeLeft;
+        nodeLeft = node.left;
+      }
+      return node.key;
+    }
+    update(key, update, ifAbsent) {
+      let comp = this.splay(key);
+      if (comp == 0) {
+        const modificationCount = this.modificationCount;
+        const splayCount = this.splayCount;
+        const newValue = update(this.root.value);
+        if (modificationCount != this.modificationCount) {
+          throw "Concurrent modification during iteration.";
+        }
+        if (splayCount != this.splayCount) {
+          this.splay(key);
+        }
+        this.root = this.root.replaceValue(newValue);
+        this.splayCount += 1;
+        return newValue;
+      }
+      if (ifAbsent != null) {
+        const modificationCount = this.modificationCount;
+        const splayCount = this.splayCount;
+        const newValue = ifAbsent();
+        if (modificationCount != this.modificationCount) {
+          throw "Concurrent modification during iteration.";
+        }
+        if (splayCount != this.splayCount) {
+          comp = this.splay(key);
+        }
+        this.addNewRoot(new SplayTreeMapNode(key, newValue), comp);
+        return newValue;
+      }
+      throw "Invalid argument (key): Key not in map.";
+    }
+    updateAll(update) {
+      const root3 = this.root;
+      if (root3 == null)
+        return;
+      const iterator = new SplayTreeMapEntryIterableIterator(this.wrap());
+      let node;
+      while (node = iterator.next(), !node.done) {
+        const newValue = update(...node.value);
+        iterator.replaceValue(newValue);
+      }
+    }
+    keys() {
+      return new SplayTreeKeyIterableIterator(this.wrap());
+    }
+    values() {
+      return new SplayTreeValueIterableIterator(this.wrap());
+    }
+    entries() {
+      return this[Symbol.iterator]();
+    }
+    [(_b = Symbol.iterator, _a = Symbol.toStringTag, _b)]() {
+      return new SplayTreeMapEntryIterableIterator(this.wrap());
+    }
+  };
+  var _a2, _b2;
+  var SplayTreeSet = class _SplayTreeSet extends SplayTree {
     constructor(compare2, isValidKey) {
       super();
       __publicField(this, "root", null);
       __publicField(this, "compare");
       __publicField(this, "validKey");
-      __publicField(this, _a, "[object Set]");
+      __publicField(this, _a2, "[object Set]");
       this.compare = compare2 != null ? compare2 : this.defaultCompare();
       this.validKey = isValidKey != null ? isValidKey : (v2) => v2 != null && v2 != void 0;
     }
     values() {
       return this[Symbol.iterator]();
     }
-    [Symbol.iterator]() {
+    [(_b2 = Symbol.iterator, _a2 = Symbol.toStringTag, _b2)]() {
       return new SplayTreeKeyIterableIterator(this.wrap());
     }
   };
-  _a = Symbol.toStringTag;
-  var SplayTreeSet = _SplayTreeSet;
   var SplayTreeIterableIterator = class {
     constructor(tree) {
       __publicField(this, "tree");
       return [node.key, node.key];
     }
   };
+  var SplayTreeValueIterableIterator = class extends SplayTreeIterableIterator {
+    constructor(map2) {
+      super(map2);
+    }
+    getValue(node) {
+      return node.value;
+    }
+  };
+  var SplayTreeMapEntryIterableIterator = class extends SplayTreeIterableIterator {
+    constructor(map2) {
+      super(map2);
+    }
+    getValue(node) {
+      return [node.key, node.value];
+    }
+    replaceValue(value) {
+      if (this.modificationCount != this.tree.getModificationCount()) {
+        throw "Concurrent modification during iteration.";
+      }
+      if (this.splayCount != this.tree.getSplayCount()) {
+        this.rebuildPath(this.path[this.path.length - 1].key);
+      }
+      const last = this.path.pop();
+      const newLast = last.replaceValue(value);
+      if (!this.path.length) {
+        this.tree.setRoot(newLast);
+      } else {
+        const parent = this.path[this.path.length - 1];
+        if (last === parent.left) {
+          parent.left = newLast;
+        } else {
+          parent.right = newLast;
+        }
+      }
+      this.path.push(newLast);
+      const count = this.tree.getSplayCount() + 1;
+      this.tree.setSplayCount(count);
+      this.splayCount = count;
+    }
+  };
 
   // node_modules/polyclip-ts/dist/identity.js
   var identity_default3 = (x2) => {
   var precision = set3();
 
   // node_modules/polyclip-ts/dist/bbox.js
-  var isInBbox = (bbox2, point2) => {
-    return bbox2.ll.x.isLessThanOrEqualTo(point2.x) && point2.x.isLessThanOrEqualTo(bbox2.ur.x) && bbox2.ll.y.isLessThanOrEqualTo(point2.y) && point2.y.isLessThanOrEqualTo(bbox2.ur.y);
+  var isInBbox = (bbox2, point) => {
+    return bbox2.ll.x.isLessThanOrEqualTo(point.x) && point.x.isLessThanOrEqualTo(bbox2.ur.x) && bbox2.ll.y.isLessThanOrEqualTo(point.y) && point.y.isLessThanOrEqualTo(bbox2.ur.y);
   };
   var getBboxOverlap = (b1, b2) => {
     if (b2.ur.x.isLessThan(b1.ll.x) || b1.ur.x.isLessThan(b2.ll.x) || b2.ur.y.isLessThan(b1.ll.y) || b1.ur.y.isLessThan(b2.ll.y))
   // node_modules/polyclip-ts/dist/sweep-event.js
   var SweepEvent = class _SweepEvent {
     // Warning: 'point' input will be modified and re-used (for performance)
-    constructor(point2, isLeft) {
+    constructor(point, isLeft) {
       __publicField(this, "point");
       __publicField(this, "isLeft");
       __publicField(this, "segment");
       __publicField(this, "otherSE");
       __publicField(this, "consumedBy");
-      if (point2.events === void 0)
-        point2.events = [this];
+      if (point.events === void 0)
+        point.events = [this];
       else
-        point2.events.push(this);
-      this.point = point2;
+        point.events.push(this);
+      this.point = point;
       this.isLeft = isLeft;
     }
     // for ordering sweep events in the sweep event queue
      *   0: point is colinear to segment
      *  -1: point lies below the segment (to the right of vertical)
      */
-    comparePoint(point2) {
-      return precision.orient(this.leftSE.point, point2, this.rightSE.point);
+    comparePoint(point) {
+      return precision.orient(this.leftSE.point, point, this.rightSE.point);
     }
     /**
      * Given another segment, returns the first non-trivial intersection
      *
      * Warning: input array of points is modified
      */
-    split(point2) {
+    split(point) {
       const newEvents = [];
-      const alreadyLinked = point2.events !== void 0;
-      const newLeftSE = new SweepEvent(point2, true);
-      const newRightSE = new SweepEvent(point2, false);
+      const alreadyLinked = point.events !== void 0;
+      const newLeftSE = new SweepEvent(point, true);
+      const newRightSE = new SweepEvent(point, false);
       const oldRightSE = this.rightSE;
       this.replaceRightSE(newRightSE);
       newEvents.push(newRightSE);
         if (typeof geomRing[i3][0] !== "number" || typeof geomRing[i3][1] !== "number") {
           throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
         }
-        const point2 = precision.snap({ x: new bignumber_default(geomRing[i3][0]), y: new bignumber_default(geomRing[i3][1]) });
-        if (point2.x.eq(prevPoint.x) && point2.y.eq(prevPoint.y))
+        const point = precision.snap({ x: new bignumber_default(geomRing[i3][0]), y: new bignumber_default(geomRing[i3][1]) });
+        if (point.x.eq(prevPoint.x) && point.y.eq(prevPoint.y))
           continue;
-        this.segments.push(Segment.fromRing(prevPoint, point2, this));
-        if (point2.x.isLessThan(this.bbox.ll.x))
-          this.bbox.ll.x = point2.x;
-        if (point2.y.isLessThan(this.bbox.ll.y))
-          this.bbox.ll.y = point2.y;
-        if (point2.x.isGreaterThan(this.bbox.ur.x))
-          this.bbox.ur.x = point2.x;
-        if (point2.y.isGreaterThan(this.bbox.ur.y))
-          this.bbox.ur.y = point2.y;
-        prevPoint = point2;
+        this.segments.push(Segment.fromRing(prevPoint, point, this));
+        if (point.x.isLessThan(this.bbox.ll.x))
+          this.bbox.ll.x = point.x;
+        if (point.y.isLessThan(this.bbox.ll.y))
+          this.bbox.ll.y = point.y;
+        if (point.x.isGreaterThan(this.bbox.ur.x))
+          this.bbox.ur.x = point.x;
+        if (point.y.isGreaterThan(this.bbox.ur.y))
+          this.bbox.ur.y = point.y;
+        prevPoint = point;
       }
       if (!firstPoint.x.eq(prevPoint.x) || !firstPoint.y.eq(prevPoint.y)) {
         this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
     }
     /* Returns the ring that encloses this one, if any */
     _calcEnclosingRing() {
-      var _a2, _b;
+      var _a3, _b3;
       let leftMostEvt = this.events[0];
       for (let i3 = 1, iMax = this.events.length; i3 < iMax; i3++) {
         const evt = this.events[i3];
         if (!prevPrevSeg)
           return prevSeg.ringOut;
         if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
-          if (((_a2 = prevPrevSeg.ringOut) == null ? void 0 : _a2.enclosingRing()) !== prevSeg.ringOut) {
+          if (((_a3 = prevPrevSeg.ringOut) == null ? void 0 : _a3.enclosingRing()) !== prevSeg.ringOut) {
             return prevSeg.ringOut;
           } else
-            return (_b = prevSeg.ringOut) == null ? void 0 : _b.enclosingRing();
+            return (_b3 = prevSeg.ringOut) == null ? void 0 : _b3.enclosingRing();
         }
         prevSeg = prevPrevSeg.prevInResult();
         prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
       ring.poly = this;
     }
     getGeom() {
-      const geom = [this.exteriorRing.getGeom()];
-      if (geom[0] === null)
+      const geom0 = this.exteriorRing.getGeom();
+      if (geom0 === null)
         return null;
+      const geom = [geom0];
       for (let i3 = 0, iMax = this.interiorRings.length; i3 < iMax; i3++) {
         const ringGeom = this.interiorRings[i3].getGeom();
         if (ringGeom === null)
       return geom;
     }
     _composePolys(rings) {
-      var _a2;
+      var _a3;
       const polys = [];
       for (let i3 = 0, iMax = rings.length; i3 < iMax; i3++) {
         const ring = rings[i3];
           const enclosingRing = ring.enclosingRing();
           if (!(enclosingRing == null ? void 0 : enclosingRing.poly))
             polys.push(new PolyOut(enclosingRing));
-          (_a2 = enclosingRing == null ? void 0 : enclosingRing.poly) == null ? void 0 : _a2.addInterior(ring);
+          (_a3 = enclosingRing == null ? void 0 : enclosingRing.poly) == null ? void 0 : _a3.addInterior(ring);
         }
       }
       return polys;
           feature3.properties = feature3.properties || {};
           let props = feature3.properties;
           let id2 = feature3.id || props.id;
-          if (!id2 || !/^\S+\.geojson$/i.test(id2))
-            return;
+          if (!id2 || !/^\S+\.geojson$/i.test(id2)) return;
           id2 = id2.toLowerCase();
           feature3.id = id2;
           props.id = id2;
     //
     resolveLocation(location) {
       const valid = this.validateLocation(location);
-      if (!valid)
-        return null;
+      if (!valid) return null;
       const id2 = valid.id;
       if (this._cache[id2]) {
         return Object.assign(valid, { feature: this._cache[id2] });
     resolveLocationSet(locationSet) {
       locationSet = locationSet || {};
       const valid = this.validateLocationSet(locationSet);
-      if (!valid)
-        return null;
+      if (!valid) return null;
       const id2 = valid.id;
       if (this._cache[id2]) {
         return Object.assign(valid, { feature: this._cache[id2] });
     }
   };
   function _clip(features, which) {
-    if (!Array.isArray(features) || !features.length)
-      return null;
+    if (!Array.isArray(features) || !features.length) return null;
     const fn = { UNION: union, DIFFERENCE: difference }[which];
     const args = features.map((feature3) => feature3.geometry.coordinates);
     const coords = fn.apply(null, args);
      * @param  `obj`  Object to check, it should have `locationSet` property
      */
     _validateLocationSet(obj) {
-      if (obj.locationSetID)
-        return;
+      if (obj.locationSetID) return;
       try {
         let locationSet = obj.locationSet;
         if (!locationSet) {
         }
         const locationSetID = _loco.validateLocationSet(locationSet).id;
         obj.locationSetID = locationSetID;
-        if (this._knownLocationSets.has(locationSetID))
-          return;
+        if (this._knownLocationSets.has(locationSetID)) return;
         let area = 0;
         (locationSet.include || []).forEach((location) => {
           const locationID = _loco.validateLocation(location).id;
      */
     _resolveLocationSet(obj) {
       this._validateLocationSet(obj);
-      if (this._resolved.has(obj.locationSetID))
-        return;
+      if (this._resolved.has(obj.locationSetID)) return;
       try {
         const result = _loco.resolveLocationSet(obj.locationSet);
         const locationSetID = result.id;
      * @param  `fc`  FeatureCollection-like Object containing custom locations
      */
     mergeCustomGeoJSON(fc) {
-      if (!fc || fc.type !== "FeatureCollection" || !Array.isArray(fc.features))
-        return;
+      if (!fc || fc.type !== "FeatureCollection" || !Array.isArray(fc.features)) return;
       fc.features.forEach((feature3) => {
         feature3.properties = feature3.properties || {};
         let props = feature3.properties;
         let id2 = feature3.id || props.id;
-        if (!id2 || !/^\S+\.geojson$/i.test(id2))
-          return;
+        if (!id2 || !/^\S+\.geojson$/i.test(id2)) return;
         id2 = id2.toLowerCase();
         feature3.id = id2;
         props.id = id2;
      * @return  Promise resolved true (this function used to be slow/async, now it's faster and sync)
      */
     mergeLocationSets(objects) {
-      if (!Array.isArray(objects))
-        return Promise.reject("nothing to do");
+      if (!Array.isArray(objects)) return Promise.reject("nothing to do");
       objects.forEach((obj) => this._validateLocationSet(obj));
       this._rebuildIndex();
       return Promise.resolve(objects);
       const hits = this._wp(loc, true) || [];
       const thiz = this;
       hits.forEach((prop) => {
-        if (prop.id[0] !== "+")
-          return;
+        if (prop.id[0] !== "+") return;
         const locationSetID = prop.id;
         const area = thiz._knownLocationSets.get(locationSetID);
         if (area) {
         }
       });
       hits.forEach((prop) => {
-        if (prop.id[0] === "+")
-          return;
+        if (prop.id[0] === "+") return;
         const locationID = prop.id;
         const included = thiz._locationIncludedIn.get(locationID);
         (included || []).forEach((locationSetID) => {
         });
       });
       hits.forEach((prop) => {
-        if (prop.id[0] === "+")
-          return;
+        if (prop.id[0] === "+") return;
         const locationID = prop.id;
         const excluded = thiz._locationExcludedIn.get(locationID);
         (excluded || []).forEach((locationSetID) => {
   // modules/util/detect.js
   var _detected;
   function utilDetect(refresh2) {
-    if (_detected && !refresh2)
-      return _detected;
+    if (_detected && !refresh2) return _detected;
     _detected = {};
     const ua = navigator.userAgent;
     let m2 = null;
         _detected.browser = m2[1];
         _detected.version = m2[2];
         m2 = ua.match(/version\/([\.\d]+)/i);
-        if (m2 !== null)
-          _detected.version = m2[1];
+        if (m2 !== null) _detected.version = m2[1];
       }
     }
     if (!_detected.browser) {
   function utilCleanTags(tags) {
     var out = {};
     for (var k2 in tags) {
-      if (!k2)
-        continue;
+      if (!k2) continue;
       var v2 = tags[k2];
       if (v2 !== void 0) {
         out[k2] = cleanValue(k2, v2);
       function skip(k4) {
         return /^(description|note|fixme|inscription)$/.test(k4);
       }
-      if (skip(k3))
-        return v3;
+      if (skip(k3)) return v3;
       var cleaned = v3.split(";").map(function(s2) {
         return s2.trim();
       }).join(keepSpaces(k3) ? "; " : ";");
       var i3, binding;
       for (i3 = 0; i3 < bindings.length; i3++) {
         binding = bindings[i3];
-        if (!binding.event.modifiers.shiftKey)
-          continue;
-        if (!!binding.capture !== isCapturing)
-          continue;
+        if (!binding.event.modifiers.shiftKey) continue;
+        if (!!binding.capture !== isCapturing) continue;
         if (matches(d3_event, binding, true)) {
           binding.callback(d3_event);
           didMatch = true;
           break;
         }
       }
-      if (didMatch)
-        return;
+      if (didMatch) return;
       for (i3 = 0; i3 < bindings.length; i3++) {
         binding = bindings[i3];
-        if (binding.event.modifiers.shiftKey)
-          continue;
-        if (!!binding.capture !== isCapturing)
-          continue;
+        if (binding.event.modifiers.shiftKey) continue;
+        if (!!binding.capture !== isCapturing) continue;
         if (matches(d3_event, binding, false)) {
           binding.callback(d3_event);
           break;
         if (!isMatch && (tryKeyCode || binding2.event.modifiers.altKey)) {
           isMatch = event.keyCode === binding2.event.keyCode;
         }
-        if (!isMatch)
-          return false;
+        if (!isMatch) return false;
         if (!(event.ctrlKey && event.altKey)) {
-          if (event.ctrlKey !== binding2.event.modifiers.ctrlKey)
-            return false;
-          if (event.altKey !== binding2.event.modifiers.altKey)
-            return false;
+          if (event.ctrlKey !== binding2.event.modifiers.ctrlKey) return false;
+          if (event.altKey !== binding2.event.modifiers.altKey) return false;
         }
-        if (event.metaKey !== binding2.event.modifiers.metaKey)
-          return false;
-        if (testShift && event.shiftKey !== binding2.event.modifiers.shiftKey)
-          return false;
+        if (event.metaKey !== binding2.event.modifiers.metaKey) return false;
+        if (testShift && event.shiftKey !== binding2.event.modifiers.shiftKey) return false;
         return true;
       }
     }
         _keybindings[id2] = binding;
         var matches = arr[i3].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
         for (var j2 = 0; j2 < matches.length; j2++) {
-          if (matches[j2] === "++")
-            matches[j2] = "+";
+          if (matches[j2] === "++") matches[j2] = "+";
           if (matches[j2] in utilKeybinding.modifierCodes) {
             var prop = utilKeybinding.modifierProperties[utilKeybinding.modifierCodes[matches[j2]]];
             binding.event.modifiers[prop] = true;
       document.cookie = name + "=1; expires=" + expires.toUTCString() + "; sameSite=strict";
     }
     mutex.lock = function() {
-      if (intervalID)
-        return true;
+      if (intervalID) return true;
       var cookie = document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + name + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1");
-      if (cookie)
-        return false;
+      if (cookie) return false;
       renew();
       intervalID = window.setInterval(renew, 4e3);
       return true;
     };
     mutex.unlock = function() {
-      if (!intervalID)
-        return;
+      if (!intervalID) return;
       document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict";
       clearInterval(intervalID);
       intervalID = null;
       }
       return false;
     }
-    function tiler9() {
+    function tiler8() {
       var z2 = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
       var z0 = clamp3(Math.round(z2), _zoomExtent[0], _zoomExtent[1]);
       var tileMin = 0;
       tiles.scale = k2;
       return tiles;
     }
-    tiler9.getTiles = function(projection2) {
+    tiler8.getTiles = function(projection2) {
       var origin = [
         projection2.scale() * Math.PI - projection2.translate()[0],
         projection2.scale() * Math.PI - projection2.translate()[1]
       ];
       this.size(projection2.clipExtent()[1]).scale(projection2.scale() * 2 * Math.PI).translate(projection2.translate());
-      var tiles = tiler9();
+      var tiles = tiler8();
       var ts = tiles.scale;
       return tiles.map(function(tile) {
         if (_skipNullIsland && nearNullIsland(tile)) {
         };
       }).filter(Boolean);
     };
-    tiler9.getGeoJSON = function(projection2) {
-      var features = tiler9.getTiles(projection2).map(function(tile) {
+    tiler8.getGeoJSON = function(projection2) {
+      var features = tiler8.getTiles(projection2).map(function(tile) {
         return {
           type: "Feature",
           properties: {
         features
       };
     };
-    tiler9.tileSize = function(val) {
-      if (!arguments.length)
-        return _tileSize;
+    tiler8.tileSize = function(val) {
+      if (!arguments.length) return _tileSize;
       _tileSize = val;
-      return tiler9;
+      return tiler8;
     };
-    tiler9.zoomExtent = function(val) {
-      if (!arguments.length)
-        return _zoomExtent;
+    tiler8.zoomExtent = function(val) {
+      if (!arguments.length) return _zoomExtent;
       _zoomExtent = val;
-      return tiler9;
+      return tiler8;
     };
-    tiler9.size = function(val) {
-      if (!arguments.length)
-        return _size;
+    tiler8.size = function(val) {
+      if (!arguments.length) return _size;
       _size = val;
-      return tiler9;
+      return tiler8;
     };
-    tiler9.scale = function(val) {
-      if (!arguments.length)
-        return _scale;
+    tiler8.scale = function(val) {
+      if (!arguments.length) return _scale;
       _scale = val;
-      return tiler9;
+      return tiler8;
     };
-    tiler9.translate = function(val) {
-      if (!arguments.length)
-        return _translate;
+    tiler8.translate = function(val) {
+      if (!arguments.length) return _translate;
       _translate = val;
-      return tiler9;
+      return tiler8;
     };
-    tiler9.margin = function(val) {
-      if (!arguments.length)
-        return _margin;
+    tiler8.margin = function(val) {
+      if (!arguments.length) return _margin;
       _margin = +val;
-      return tiler9;
+      return tiler8;
     };
-    tiler9.skipNullIsland = function(val) {
-      if (!arguments.length)
-        return _skipNullIsland;
+    tiler8.skipNullIsland = function(val) {
+      if (!arguments.length) return _skipNullIsland;
       _skipNullIsland = val;
-      return tiler9;
+      return tiler8;
     };
-    return tiler9;
+    return tiler8;
   }
 
   // modules/util/trigger_event.js
     localizer.scriptNames = () => _scriptNames;
     let _preferredLocaleCodes = [];
     localizer.preferredLocaleCodes = function(codes) {
-      if (!arguments.length)
-        return _preferredLocaleCodes;
+      if (!arguments.length) return _preferredLocaleCodes;
       if (typeof codes === "string") {
         _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
       } else {
     };
     var _loadPromise;
     localizer.ensureLoaded = () => {
-      if (_loadPromise)
-        return _loadPromise;
+      if (_loadPromise) return _loadPromise;
       let filesToFetch = [
         "languages",
         // load the list of languages
           _localeCodes.slice(0, fullCoverageIndex + 1).forEach(function(code) {
             let scopeId = Object.keys(localeDirs)[i3];
             let directory = Object.values(localeDirs)[i3];
-            if (index[code])
-              loadStringsPromises.push(localizer.loadLocale(code, scopeId, directory));
+            if (index[code]) loadStringsPromises.push(localizer.loadLocale(code, scopeId, directory));
           });
         });
         return Promise.all(loadStringsPromises);
       let toUse = [];
       for (let i3 in requestedLocales) {
         let locale2 = requestedLocales[i3];
-        if (supportedLocales[locale2])
-          toUse.push(locale2);
+        if (supportedLocales[locale2]) toUse.push(locale2);
         if (locale2.includes("-")) {
           let langPart = locale2.split("-")[0];
-          if (supportedLocales[langPart])
-            toUse.push(langPart);
+          if (supportedLocales[langPart]) toUse.push(langPart);
         }
       }
       return utilArrayUniq(toUse);
     }
     function updateForCurrentLocale() {
-      if (!_localeCode)
-        return;
+      if (!_localeCode) return;
       _languageCode = _localeCode.split("-")[0];
       const currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
       const hash = utilStringQs(window.location.hash);
         _textDirection = currentData && currentData.rtl ? "rtl" : "ltr";
       }
       let locale2 = _localeCode;
-      if (locale2.toLowerCase() === "en-us")
-        locale2 = "en";
+      if (locale2.toLowerCase() === "en-us") locale2 = "en";
       _languageNames = _localeStrings.general[locale2].languageNames || _localeStrings.general[_languageCode].languageNames;
       _scriptNames = _localeStrings.general[locale2].scriptNames || _localeStrings.general[_languageCode].scriptNames;
       _usesMetric = _localeCode.slice(-3).toLowerCase() !== "-us";
     }
     localizer.loadLocale = (locale2, scopeId, directory) => {
-      if (locale2.toLowerCase() === "en-us")
-        locale2 = "en";
+      if (locale2.toLowerCase() === "en-us") locale2 = "en";
       if (_localeStrings[scopeId] && _localeStrings[scopeId][locale2]) {
         return Promise.resolve(locale2);
       }
         fileMap[key] = "".concat(directory, "/").concat(locale2, ".min.json");
       }
       return _mainFileFetcher.get(key).then((d2) => {
-        if (!_localeStrings[scopeId])
-          _localeStrings[scopeId] = {};
+        if (!_localeStrings[scopeId]) _localeStrings[scopeId] = {};
         _localeStrings[scopeId][locale2] = d2[locale2];
         return locale2;
       });
       if (rules) {
         return rules.select(number3);
       }
-      if (number3 === 1)
-        return "one";
+      if (number3 === 1) return "one";
       return "other";
     }
     localizer.tInfo = function(origStringId, replacements, locale2) {
       locale2 = locale2 || _localeCode;
       let path = stringId.split(".").map((s2) => s2.replace(/<TX_DOT>/g, ".")).reverse();
       let stringsKey = locale2;
-      if (stringsKey.toLowerCase() === "en-us")
-        stringsKey = "en";
+      if (stringsKey.toLowerCase() === "en-us") stringsKey = "en";
       let result = _localeStrings && _localeStrings[scopeId] && _localeStrings[scopeId][stringsKey];
       while (result !== void 0 && path.length) {
         result = result[path.pop()];
         };
       }
       const missing = "Missing ".concat(locale2, " translation: ").concat(origStringId);
-      if (typeof console !== "undefined")
-        console.error(missing);
+      if (typeof console !== "undefined") console.error(missing);
       return {
         text: missing,
         locale: "en"
       ret.stringId = stringId;
       return ret;
     };
+    localizer.t.addOrUpdate = function(stringId, replacements, locale2) {
+      const ret = function(selection2) {
+        const info = localizer.tInfo(stringId, replacements, locale2);
+        const span = selection2.selectAll("span.localized-text").data([info]);
+        const enter = span.enter().append("span").classed("localized-text", true);
+        span.merge(enter).attr("lang", info.locale || "und").text((replacements && replacements.prefix || "") + info.text + (replacements && replacements.suffix || ""));
+      };
+      ret.stringId = stringId;
+      return ret;
+    };
     localizer.languageName = (code, options2) => {
       if (_languageNames && _languageNames[code]) {
         return _languageNames[code];
       }
-      if (options2 && options2.localOnly)
-        return null;
+      if (options2 && options2.localOnly) return null;
       const langInfo = _dataLanguages[code];
       if (langInfo) {
         if (langInfo.nativeName) {
     };
     localizer.floatParser = (locale2) => {
       const polyfill = (string) => +string.trim();
-      if (!("Intl" in window && "NumberFormat" in Intl))
-        return polyfill;
+      if (!("Intl" in window && "NumberFormat" in Intl)) return polyfill;
       const format2 = new Intl.NumberFormat(locale2, { maximumFractionDigits: 20 });
-      if (!("formatToParts" in format2))
-        return polyfill;
+      if (!("formatToParts" in format2)) return polyfill;
       const parts = format2.formatToParts(-12345.6);
       const numerals = Array.from({ length: 10 }).map((_2, i3) => format2.format(i3));
       const index = new Map(numerals.map((d2, i3) => [d2, i3]));
       const getIndex = (d2) => index.get(d2);
       return (string) => {
         string = string.trim();
-        if (literal)
-          string = string.replace(literal, "");
-        if (group)
-          string = string.replace(group, "");
-        if (decimal)
-          string = string.replace(decimal, ".");
+        if (literal) string = string.replace(literal, "");
+        if (group) string = string.replace(group, "");
+        if (decimal) string = string.replace(decimal, ".");
         string = string.replace(numeral, getIndex);
         return string ? +string : NaN;
       };
       }
       return (string) => {
         string = string.trim();
-        if (literal)
-          string = string.replace(literal, "");
-        if (group)
-          string = string.replace(group, "");
+        if (literal) string = string.replace(literal, "");
+        if (group) string = string.replace(group, "");
         const parts = string.split(decimal || ".");
         return parts && parts[1] && parts[1].length || 0;
       };
     let _memo = {};
     _this.collection = collection;
     _this.item = (id2) => {
-      if (_memo[id2])
-        return _memo[id2];
+      if (_memo[id2]) return _memo[id2];
       const found = _this.collection.find((d2) => d2.id === id2);
-      if (found)
-        _memo[id2] = found;
+      if (found) _memo[id2] = found;
       return found;
     };
     _this.index = (id2) => _this.collection.findIndex((d2) => d2.id === id2);
     };
     _this.fallback = (geometry) => {
       let id2 = geometry;
-      if (id2 === "vertex")
-        id2 = "point";
+      if (id2 === "vertex") id2 = "point";
       return _this.item(id2);
     };
     _this.search = (value, geometry, loc) => {
-      if (!value)
-        return _this;
+      if (!value) return _this;
       value = value.toLowerCase().trim();
       function leading(a2) {
         const index = a2.indexOf(value);
             aCompare = findMatchingAlias([aCompare].concat(a2[aliasesProp]()));
             bCompare = findMatchingAlias([bCompare].concat(b2[aliasesProp]()));
           }
-          if (value === aCompare)
-            return -1;
-          if (value === bCompare)
-            return 1;
+          if (value === aCompare) return -1;
+          if (value === bCompare) return 1;
           let i3 = b2.originalScore - a2.originalScore;
-          if (i3 !== 0)
-            return i3;
+          if (i3 !== 0) return i3;
           i3 = aCompare.indexOf(value) - bCompare.indexOf(value);
-          if (i3 !== 0)
-            return i3;
+          if (i3 !== 0) return i3;
           return aCompare.length - bCompare.length;
         };
       }
     _this.searchNameStripped = () => {
       if (!_searchNameStripped) {
         _searchNameStripped = _this.searchName();
-        if (_searchNameStripped.normalize)
-          _searchNameStripped = _searchNameStripped.normalize("NFD");
+        if (_searchNameStripped.normalize) _searchNameStripped = _searchNameStripped.normalize("NFD");
         _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, "");
       }
       return _searchNameStripped;
       return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty("area");
     };
     _this.addable = function(val) {
-      if (!arguments.length)
-        return _addable;
+      if (!arguments.length) return _addable;
       _addable = val;
       return _this;
     };
       }
       return utilArrayUniq(resolved);
       function inheritFields(parent, which2) {
-        if (!parent)
-          return [];
+        if (!parent) return [];
         if (which2 === "fields") {
           return parent.fields().filter(shouldInherit);
         } else if (which2 === "moreFields") {
       }
       function shouldInherit(f2) {
         if (f2.key && _this.tags[f2.key] !== void 0 && // inherit anyway if multiple values are allowed or just a checkbox
-        f2.type !== "multiCombo" && f2.type !== "semiCombo" && f2.type !== "manyCombo" && f2.type !== "check")
-          return false;
+        f2.type !== "multiCombo" && f2.type !== "semiCombo" && f2.type !== "manyCombo" && f2.type !== "check") return false;
         return true;
       }
     }
     function stripDiacritics(s2) {
-      if (s2.normalize)
-        s2 = s2.normalize("NFD");
+      if (s2.normalize) s2 = s2.normalize("NFD");
       s2 = s2.replace(/[\u0300-\u036f]/g, "");
       return s2;
     }
     let _geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
     let _loadPromise;
     _this.ensureLoaded = () => {
-      if (_loadPromise)
-        return _loadPromise;
+      if (_loadPromise) return _loadPromise;
       return _loadPromise = Promise.all([
         _mainFileFetcher.get("preset_categories"),
         _mainFileFetcher.get("preset_defaults"),
           let f2 = d2.fields[fieldID];
           if (f2) {
             f2 = presetField(fieldID, f2, _fields);
-            if (f2.locationSet)
-              newLocationSets.push(f2);
+            if (f2.locationSet) newLocationSets.push(f2);
             _fields[fieldID] = f2;
           } else {
             delete _fields[fieldID];
           if (p2) {
             const isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
             p2 = presetPreset(presetID, p2, isAddable, _fields, _presets);
-            if (p2.locationSet)
-              newLocationSets.push(p2);
+            if (p2.locationSet) newLocationSets.push(p2);
             _presets[presetID] = p2;
           } else {
             const existing = _presets[presetID];
           let c2 = d2.categories[categoryID];
           if (c2) {
             c2 = presetCategory(categoryID, c2, _presets);
-            if (c2.locationSet)
-              newLocationSets.push(c2);
+            if (c2.locationSet) newLocationSets.push(c2);
             _categories[categoryID] = c2;
           } else {
             delete _categories[categoryID];
       for (let k2 in tags) {
         let indexMatches = [];
         let valueIndex = keyIndex[k2];
-        if (!valueIndex)
-          continue;
+        if (!valueIndex) continue;
         let keyValueMatches = valueIndex[tags[k2]];
-        if (keyValueMatches)
-          indexMatches.push(...keyValueMatches);
+        if (keyValueMatches) indexMatches.push(...keyValueMatches);
         let keyStarMatches = valueIndex["*"];
-        if (keyStarMatches)
-          indexMatches.push(...keyStarMatches);
-        if (indexMatches.length === 0)
-          continue;
+        if (keyStarMatches) indexMatches.push(...keyStarMatches);
+        if (indexMatches.length === 0) continue;
         for (let i3 = 0; i3 < indexMatches.length; i3++) {
           const candidate = indexMatches[i3];
           const score = candidate.matchScore(tags);
       return bestMatch || _this.fallback(geometry);
     };
     _this.allowsVertex = (entity, resolver) => {
-      if (entity.type !== "node")
-        return false;
-      if (Object.keys(entity.tags).length === 0)
-        return true;
+      if (entity.type !== "node") return false;
+      if (Object.keys(entity.tags).length === 0) return true;
       return resolver.transient(entity, "vertexMatch", () => {
-        if (entity.isOnAddressLine(resolver))
-          return true;
+        if (entity.isOnAddressLine(resolver)) return true;
         const geometries = osmNodeGeometriesForTags(entity.tags);
-        if (geometries.vertex)
-          return true;
-        if (geometries.point)
-          return false;
+        if (geometries.vertex) return true;
+        if (geometries.point) return false;
         return true;
       });
     };
       presets.forEach((p2) => {
         const keys2 = p2.tags && Object.keys(p2.tags);
         const key = keys2 && keys2.length && keys2[0];
-        if (!key)
-          return;
-        if (ignore[key])
-          return;
+        if (!key) return;
+        if (ignore[key]) return;
         if (p2.geometry.indexOf("area") !== -1) {
           areaKeys[key] = areaKeys[key] || {};
         }
     };
     _this.lineTags = () => {
       return _this.collection.filter((lineTags, d2) => {
-        if (d2.suggestion || d2.replacement || d2.searchable === false)
-          return lineTags;
+        if (d2.suggestion || d2.replacement || d2.searchable === false) return lineTags;
         const keys2 = d2.tags && Object.keys(d2.tags);
         const key = keys2 && keys2.length && keys2[0];
-        if (!key)
-          return lineTags;
+        if (!key) return lineTags;
         if (d2.geometry.indexOf("line") !== -1) {
           lineTags[key] = lineTags[key] || [];
           lineTags[key].push(d2.tags);
     };
     _this.pointTags = () => {
       return _this.collection.reduce((pointTags, d2) => {
-        if (d2.suggestion || d2.replacement || d2.searchable === false)
-          return pointTags;
+        if (d2.suggestion || d2.replacement || d2.searchable === false) return pointTags;
         const keys2 = d2.tags && Object.keys(d2.tags);
         const key = keys2 && keys2.length && keys2[0];
-        if (!key)
-          return pointTags;
+        if (!key) return pointTags;
         if (d2.geometry.indexOf("point") !== -1) {
           pointTags[key] = pointTags[key] || {};
           pointTags[key][d2.tags[key]] = true;
     };
     _this.vertexTags = () => {
       return _this.collection.reduce((vertexTags, d2) => {
-        if (d2.suggestion || d2.replacement || d2.searchable === false)
-          return vertexTags;
+        if (d2.suggestion || d2.replacement || d2.searchable === false) return vertexTags;
         const keys2 = d2.tags && Object.keys(d2.tags);
         const key = keys2 && keys2.length && keys2[0];
-        if (!key)
-          return vertexTags;
+        if (!key) return vertexTags;
         if (d2.geometry.indexOf("vertex") !== -1) {
           vertexTags[key] = vertexTags[key] || {};
           vertexTags[key][d2.tags[key]] = true;
       if (_addablePresetIDs) {
         defaults = Array.from(_addablePresetIDs).map(function(id2) {
           var preset = _this.item(id2);
-          if (preset && preset.matchGeometry(geometry))
-            return preset;
+          if (preset && preset.matchGeometry(geometry)) return preset;
           return null;
         }).filter(Boolean);
       } else {
       return result;
     };
     _this.addablePresetIDs = function(val) {
-      if (!arguments.length)
-        return _addablePresetIDs;
-      if (Array.isArray(val))
-        val = new Set(val);
+      if (!arguments.length) return _addablePresetIDs;
+      if (Array.isArray(val)) val = new Set(val);
       _addablePresetIDs = val;
       if (_addablePresetIDs) {
         _this.collection.forEach((p2) => {
-          if (p2.addable)
-            p2.addable(_addablePresetIDs.has(p2.id));
+          if (p2.addable) p2.addable(_addablePresetIDs.has(p2.id));
         });
       } else {
         _this.collection.forEach((p2) => {
-          if (p2.addable)
-            p2.addable(true);
+          if (p2.addable) p2.addable(true);
         });
       }
       return _this;
     function ribbonItemForMinified(d2, source) {
       if (d2 && d2.pID) {
         const preset = _this.item(d2.pID);
-        if (!preset)
-          return null;
+        if (!preset) return null;
         return RibbonItem(preset, source);
       }
       return null;
       return ["point", "line", "area"].map((id2) => RibbonItem(_this.item(id2), "generic"));
     };
     _this.getAddable = () => {
-      if (!_addablePresetIDs)
-        return [];
+      if (!_addablePresetIDs) return [];
       return _addablePresetIDs.map((id2) => {
         const preset = _this.item(id2);
-        if (preset)
-          return RibbonItem(preset, "addable");
+        if (preset) return RibbonItem(preset, "addable");
         return null;
       }).filter(Boolean);
     };
       if (!_recents) {
         _recents = (JSON.parse(corePreferences("preset_recents")) || []).reduce((acc, d2) => {
           let item = ribbonItemForMinified(d2, "recent");
-          if (item && item.preset.addable())
-            acc.push(item);
+          if (item && item.preset.addable()) acc.push(item);
           return acc;
         }, []);
       }
       const recents = _this.getRecents();
       const beforeItem = _this.recentMatching(besidePreset);
       let toIndex = recents.indexOf(beforeItem);
-      if (after)
-        toIndex += 1;
+      if (after) toIndex += 1;
       const newItem = RibbonItem(preset, "recent");
       recents.splice(toIndex, 0, newItem);
       setRecents(recents);
       return null;
     };
     _this.moveItem = (items, fromIndex, toIndex) => {
-      if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length)
-        return null;
+      if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length) return null;
       items.splice(toIndex, 0, items.splice(fromIndex, 1)[0]);
       return items;
     };
       const fromIndex = recents.indexOf(item);
       const toIndex = recents.indexOf(beforeItem);
       const items = _this.moveItem(recents, fromIndex, toIndex);
-      if (items)
-        setRecents(items);
+      if (items) setRecents(items);
     };
     _this.setMostRecent = (preset) => {
-      if (preset.searchable === false)
-        return;
+      if (preset.searchable === false) return;
       let items = _this.getRecents();
       let item = _this.recentMatching(preset);
       if (item) {
       const favorites = _this.getFavorites();
       const beforeItem = _this.favoriteMatching(besidePreset);
       let toIndex = favorites.indexOf(beforeItem);
-      if (after)
-        toIndex += 1;
+      if (after) toIndex += 1;
       const newItem = RibbonItem(preset, "favorite");
       favorites.splice(toIndex, 0, newItem);
       setFavorites(favorites);
         }
         _favorites = rawFavorites.reduce((output, d2) => {
           const item = ribbonItemForMinified(d2, "favorite");
-          if (item && item.preset.addable())
-            output.push(item);
+          if (item && item.preset.addable()) output.push(item);
           return output;
         }, []);
       }
     return utilEntitySelector(Array.from(seen));
     function collectShallowDescendants(id2) {
       var entity = graph.hasEntity(id2);
-      if (!entity || entity.type !== "relation")
-        return;
+      if (!entity || entity.type !== "relation") return;
       entity.members.map(function(member) {
         return member.id;
       }).forEach(function(id3) {
     ids.forEach(collectDeepDescendants);
     return Array.from(seen);
     function collectDeepDescendants(id2) {
-      if (seen.has(id2))
-        return;
+      if (seen.has(id2)) return;
       seen.add(id2);
       var entity = graph.hasEntity(id2);
-      if (!entity || entity.type !== "relation")
-        return;
+      if (!entity || entity.type !== "relation") return;
       entity.members.map(function(member) {
         return member.id;
       }).forEach(collectDeepDescendants);
     ids.forEach(collectDeepDescendants);
     return utilEntitySelector(Array.from(returners));
     function collectDeepDescendants(id2) {
-      if (seen.has(id2))
-        return;
+      if (seen.has(id2)) return;
       seen.add(id2);
       if (!idsSet.has(id2)) {
         returners.add(id2);
       }
       var entity = graph.hasEntity(id2);
-      if (!entity || entity.type !== "relation")
-        return;
-      if (skipMultipolgonMembers && entity.isMultipolygon())
-        return;
+      if (!entity || entity.type !== "relation") return;
+      if (skipMultipolgonMembers && entity.isMultipolygon()) return;
       entity.members.map(function(member) {
         return member.id;
       }).forEach(collectDeepDescendants);
     ids.forEach(collectNodes);
     return Array.from(nodes);
     function collectNodes(id2) {
-      if (seen.has(id2))
-        return;
+      if (seen.has(id2)) return;
       seen.add(id2);
       var entity = graph.hasEntity(id2);
-      if (!entity)
-        return;
+      if (!entity) return;
       if (entity.type === "node") {
         nodes.add(entity);
       } else if (entity.type === "way") {
   function utilDisplayName(entity) {
     var localizedNameKey = "name:" + _mainLocalizer.languageCode().toLowerCase();
     var name = entity.tags[localizedNameKey] || entity.tags.name || "";
-    if (name)
-      return name;
+    if (name) return name;
     var tags = {
       direction: entity.tags.direction,
       from: entity.tags.from,
           }
         }
         var tagHash = key2 + "=" + value;
-        if (!tagCounts[tagHash])
-          tagCounts[tagHash] = 0;
+        if (!tagCounts[tagHash]) tagCounts[tagHash] = 0;
         tagCounts[tagHash] += 1;
       });
     });
     for (var key in tags) {
-      if (!Array.isArray(tags[key]))
-        continue;
+      if (!Array.isArray(tags[key])) continue;
       tags[key] = tags[key].sort(function(val12, val2) {
         var key2 = key2;
         var count2 = tagCounts[key2 + "=" + val2];
   }
   function utilStringQs(str) {
     var i3 = 0;
-    while (i3 < str.length && (str[i3] === "?" || str[i3] === "#"))
-      i3++;
+    while (i3 < str.length && (str[i3] === "?" || str[i3] === "#")) i3++;
     str = str.slice(i3);
     return str.split("&").reduce(function(obj, pair3) {
       var parts = pair3.split("=");
     var i3 = -1;
     var n3 = prefixes2.length;
     var s2 = document.body;
-    if (property in s2)
-      return property;
+    if (property in s2) return property;
     property = property.slice(0, 1).toUpperCase() + property.slice(1);
     while (++i3 < n3) {
       if (prefixes2[i3] + property in s2) {
   function utilEditDistance(a2, b2) {
     a2 = (0, import_diacritics.remove)(a2.toLowerCase());
     b2 = (0, import_diacritics.remove)(b2.toLowerCase());
-    if (a2.length === 0)
-      return b2.length;
-    if (b2.length === 0)
-      return a2.length;
+    if (a2.length === 0) return b2.length;
+    if (b2.length === 0) return a2.length;
     var matrix = [];
     var i3, j2;
     for (i3 = 0; i3 <= b2.length; i3++) {
         errors[i3] = err;
         results[i3] = data;
         remaining--;
-        if (!remaining)
-          callback(errors, results);
+        if (!remaining) callback(errors, results);
       });
     });
   }
     return index % length2;
   }
   function utilFunctor(value) {
-    if (typeof value === "function")
-      return value;
+    if (typeof value === "function") return value;
     return function() {
       return value;
     };
     return NaN;
   }
   function compareNumericIDs(left, right) {
-    if (isNaN(left) && isNaN(right))
-      return -1;
-    if (isNaN(left))
-      return 1;
-    if (isNaN(right))
-      return -1;
-    if (Math.sign(left) !== Math.sign(right))
-      return -Math.sign(left);
-    if (Math.sign(left) < 0)
-      return Math.sign(right - left);
+    if (isNaN(left) && isNaN(right)) return -1;
+    if (isNaN(left)) return 1;
+    if (isNaN(right)) return -1;
+    if (Math.sign(left) !== Math.sign(right)) return -Math.sign(left);
+    if (Math.sign(left) < 0) return Math.sign(right - left);
     return Math.sign(left - right);
   }
   function utilCompareIDs(left, right) {
       val = val.toString();
     }
     val = val.trim();
-    if (val.normalize)
-      val = val.normalize("NFC");
+    if (val.normalize) val = val.normalize("NFC");
     return utilUnicodeCharsTruncated(val, maxChars);
   }
 
   // modules/osm/entity.js
   function osmEntity(attrs) {
-    if (this instanceof osmEntity)
-      return;
+    if (this instanceof osmEntity) return;
     if (attrs && attrs.type) {
       return osmEntity[attrs.type].apply(this, arguments);
     } else if (attrs && attrs.id) {
       if (debug) {
         Object.freeze(this);
         Object.freeze(this.tags);
-        if (this.loc)
-          Object.freeze(this.loc);
-        if (this.nodes)
-          Object.freeze(this.nodes);
-        if (this.members)
-          Object.freeze(this.members);
+        if (this.loc) Object.freeze(this.loc);
+        if (this.nodes) Object.freeze(this.nodes);
+        if (this.members) Object.freeze(this.members);
       }
       return this;
     },
     copy: function(resolver, copies) {
-      if (copies[this.id])
-        return copies[this.id];
+      if (copies[this.id]) return copies[this.id];
       var copy2 = osmEntity(this, { id: void 0, user: void 0, version: void 0 });
       copies[this.id] = copy2;
       return copy2;
     },
     deprecatedTags: function(dataDeprecated) {
       var tags = this.tags;
-      if (Object.keys(tags).length === 0)
-        return [];
+      if (Object.keys(tags).length === 0) return [];
       var deprecated = [];
       dataDeprecated.forEach(function(d2) {
         var oldKeys = Object.keys(d2.old);
         if (d2.replace) {
           var hasExistingValues = Object.keys(d2.replace).some(function(replaceKey) {
-            if (!tags[replaceKey] || d2.old[replaceKey])
-              return false;
+            if (!tags[replaceKey] || d2.old[replaceKey]) return false;
             var replaceValue = d2.replace[replaceKey];
-            if (replaceValue === "*")
-              return false;
-            if (replaceValue === tags[replaceKey])
-              return false;
+            if (replaceValue === "*") return false;
+            if (replaceValue === tags[replaceKey]) return false;
             return true;
           });
-          if (hasExistingValues)
-            return;
+          if (hasExistingValues) return;
         }
         var matchesDeprecatedTags = oldKeys.every(function(oldKey) {
-          if (!tags[oldKey])
-            return false;
-          if (d2.old[oldKey] === "*")
-            return true;
-          if (d2.old[oldKey] === tags[oldKey])
-            return true;
+          if (!tags[oldKey]) return false;
+          if (d2.old[oldKey] === "*") return true;
+          if (d2.old[oldKey] === tags[oldKey]) return true;
           var vals = tags[oldKey].split(";").filter(Boolean);
           if (vals.length === 0) {
             return false;
 
   // modules/osm/lanes.js
   function osmLanes(entity) {
-    if (entity.type !== "way")
-      return null;
-    if (!entity.tags.highway)
-      return null;
+    if (entity.type !== "way") return null;
+    if (!entity.tags.highway) return null;
     var tags = entity.tags;
     var isOneWay = entity.isOneWay();
     var laneCount = getLaneCount(tags, isOneWay);
   }
   function parseMaxspeed(tags) {
     var maxspeed = tags.maxspeed;
-    if (!maxspeed)
-      return;
+    if (!maxspeed) return;
     var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
-    if (!maxspeedRegex.test(maxspeed))
-      return;
+    if (!maxspeedRegex.test(maxspeed)) return;
     return parseInt(maxspeed, 10);
   }
   function parseLaneDirections(tags, isOneWay, laneCount) {
     };
   }
   function parseTurnLanes(tag2) {
-    if (!tag2)
-      return;
+    if (!tag2) return;
     var validValues = [
       "left",
       "slight_left",
       "none"
     ];
     return tag2.split("|").map(function(s2) {
-      if (s2 === "")
-        s2 = "none";
+      if (s2 === "") s2 = "none";
       return s2.split(";").map(function(d2) {
         return validValues.indexOf(d2) === -1 ? "unknown" : d2;
       });
     });
   }
   function parseMaxspeedLanes(tag2, maxspeed) {
-    if (!tag2)
-      return;
+    if (!tag2) return;
     return tag2.split("|").map(function(s2) {
-      if (s2 === "none")
-        return s2;
+      if (s2 === "none") return s2;
       var m2 = parseInt(s2, 10);
-      if (s2 === "" || m2 === maxspeed)
-        return null;
+      if (s2 === "" || m2 === maxspeed) return null;
       return isNaN(m2) ? "unknown" : m2;
     });
   }
   function parseMiscLanes(tag2) {
-    if (!tag2)
-      return;
+    if (!tag2) return;
     var validValues = [
       "yes",
       "no",
       "designated"
     ];
     return tag2.split("|").map(function(s2) {
-      if (s2 === "")
-        s2 = "no";
+      if (s2 === "") s2 = "no";
       return validValues.indexOf(s2) === -1 ? "unknown" : s2;
     });
   }
   function parseBicycleWay(tag2) {
-    if (!tag2)
-      return;
+    if (!tag2) return;
     var validValues = [
       "yes",
       "no",
       "lane"
     ];
     return tag2.split("|").map(function(s2) {
-      if (s2 === "")
-        s2 = "no";
+      if (s2 === "") s2 = "no";
       return validValues.indexOf(s2) === -1 ? "unknown" : s2;
     });
   }
   function mapToLanesObj(lanesObj, data, key) {
     if (data.forward) {
       data.forward.forEach(function(l2, i3) {
-        if (!lanesObj.forward[i3])
-          lanesObj.forward[i3] = {};
+        if (!lanesObj.forward[i3]) lanesObj.forward[i3] = {};
         lanesObj.forward[i3][key] = l2;
       });
     }
     if (data.backward) {
       data.backward.forEach(function(l2, i3) {
-        if (!lanesObj.backward[i3])
-          lanesObj.backward[i3] = {};
+        if (!lanesObj.backward[i3]) lanesObj.backward[i3] = {};
         lanesObj.backward[i3][key] = l2;
       });
     }
     if (data.unspecified) {
       data.unspecified.forEach(function(l2, i3) {
-        if (!lanesObj.unspecified[i3])
-          lanesObj.unspecified[i3] = {};
+        if (!lanesObj.unspecified[i3]) lanesObj.unspecified[i3] = {};
         lanesObj.unspecified[i3][key] = l2;
       });
     }
     type: "way",
     nodes: [],
     copy: function(resolver, copies) {
-      if (copies[this.id])
-        return copies[this.id];
+      if (copies[this.id]) return copies[this.id];
       var copy2 = osmEntity.prototype.copy.call(this, resolver, copies);
       var nodes = this.nodes.map(function(id2) {
         return resolver.entity(id2).copy(resolver, copies).id;
       return this.nodes.indexOf(node) >= 0;
     },
     affix: function(node) {
-      if (this.nodes[0] === node)
-        return "prefix";
-      if (this.nodes[this.nodes.length - 1] === node)
-        return "suffix";
+      if (this.nodes[0] === node) return "prefix";
+      if (this.nodes[this.nodes.length - 1] === node) return "suffix";
     },
     layer: function() {
       if (isFinite(this.tags.layer)) {
         return Math.max(-10, Math.min(+this.tags.layer, 10));
       }
-      if (this.tags.covered === "yes")
-        return -1;
-      if (this.tags.location === "overground")
-        return 1;
-      if (this.tags.location === "underground")
-        return -1;
-      if (this.tags.location === "underwater")
-        return -10;
-      if (this.tags.power === "line")
-        return 10;
-      if (this.tags.power === "minor_line")
-        return 10;
-      if (this.tags.aerialway)
-        return 10;
-      if (this.tags.bridge)
-        return 1;
-      if (this.tags.cutting)
-        return -1;
-      if (this.tags.tunnel)
-        return -1;
-      if (this.tags.waterway)
-        return -1;
-      if (this.tags.man_made === "pipeline")
-        return -10;
-      if (this.tags.boundary)
-        return -10;
+      if (this.tags.covered === "yes") return -1;
+      if (this.tags.location === "overground") return 1;
+      if (this.tags.location === "underground") return -1;
+      if (this.tags.location === "underwater") return -10;
+      if (this.tags.power === "line") return 10;
+      if (this.tags.power === "minor_line") return 10;
+      if (this.tags.aerialway) return 10;
+      if (this.tags.bridge) return 1;
+      if (this.tags.cutting) return -1;
+      if (this.tags.tunnel) return -1;
+      if (this.tags.waterway) return -1;
+      if (this.tags.man_made === "pipeline") return -10;
+      if (this.tags.boundary) return -10;
       return 0;
     },
     // the approximate width of the line based on its tags except its `width` tag
           corridor: 2,
           steps: 2,
           path: 1.5,
-          footway: 1.5
+          footway: 1.5,
+          ladder: 0.5
         },
         railway: {
           // width includes ties and rail bed, not just track gauge
           var width = averageWidths[key][this.tags[key]];
           if (key === "highway") {
             var laneCount = this.tags.lanes && parseInt(this.tags.lanes, 10);
-            if (!laneCount)
-              laneCount = this.isOneWay() ? 1 : 2;
+            if (!laneCount) laneCount = this.isOneWay() ? 1 : 2;
             return width * laneCount;
           }
           return width;
       return this.nodes.length > 1 && this.first() === this.last();
     },
     isConvex: function(resolver) {
-      if (!this.isClosed() || this.isDegenerate())
-        return null;
+      if (!this.isClosed() || this.isDegenerate()) return null;
       var nodes = utilArrayUniq(resolver.childNodes(this));
       var coords = nodes.map(function(n3) {
         return n3.loc;
       return osmTagSuggestingArea(this.tags);
     },
     isArea: function() {
-      if (this.tags.area === "yes")
-        return true;
-      if (!this.isClosed() || this.tags.area === "no")
-        return false;
+      if (this.tags.area === "yes") return true;
+      if (!this.isClosed() || this.tags.area === "no") return false;
       return this.tagSuggestingArea() !== null;
     },
     isDegenerate: function() {
     areAdjacent: function(n1, n22) {
       for (var i3 = 0; i3 < this.nodes.length; i3++) {
         if (this.nodes[i3] === n1) {
-          if (this.nodes[i3 - 1] === n22)
-            return true;
-          if (this.nodes[i3 + 1] === n22)
-            return true;
+          if (this.nodes[i3 - 1] === n22) return true;
+          if (this.nodes[i3 + 1] === n22) return true;
         }
       }
       return false;
     },
     // If this way is not closed, append the beginning node to the end of the nodelist to close it.
     close: function() {
-      if (this.isClosed() || !this.nodes.length)
-        return this;
+      if (this.isClosed() || !this.nodes.length) return this;
       var nodes = this.nodes.slice();
       nodes = nodes.filter(noRepeatNodes);
       nodes.push(nodes[0]);
     },
     // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
     unclose: function() {
-      if (!this.isClosed())
-        return this;
+      if (!this.isClosed()) return this;
       var nodes = this.nodes.slice();
       var connector = this.first();
       var i3 = nodes.length - 1;
         var i3 = 1;
         while (i3 < nodes.length && nodes.length > 2 && nodes[i3] === connector) {
           nodes.splice(i3, 1);
-          if (index > i3)
-            index--;
+          if (index > i3) index--;
         }
         i3 = nodes.length - 1;
         while (i3 > 0 && nodes.length > 1 && nodes[i3] === connector) {
           nodes.splice(i3, 1);
-          if (index > i3)
-            index--;
+          if (index > i3) index--;
           i3 = nodes.length - 1;
         }
       }
         var i3 = 1;
         while (i3 < nodes.length && nodes.length > 2 && nodes[i3] === connector) {
           nodes.splice(i3, 1);
-          if (index > i3)
-            index--;
+          if (index > i3) index--;
         }
         i3 = nodes.length - 1;
         while (i3 > 0 && nodes.length > 1 && nodes[i3] === connector) {
           nodes.splice(i3, 1);
-          if (index === i3)
-            index = 0;
+          if (index === i3) index = 0;
           i3 = nodes.length - 1;
         }
       }
       var wayMembers = [];
       for (i3 = 0; i3 < members.length; i3++) {
         item = members[i3];
-        if (item.index === -1)
-          continue;
+        if (item.index === -1) continue;
         wayMembers.push(utilObjectOmit(item, ["index"]));
       }
       var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
           newPreset.fields(loc).concat(newPreset.moreFields(loc)).filter((f2) => f2.matchGeometry(geometry)).map((f2) => f2.key).filter(Boolean).forEach((key) => preserveKeys.push(key));
         }
       }
-      if (oldPreset)
-        tags = oldPreset.unsetTags(tags, geometry, preserveKeys, false, loc);
-      if (newPreset)
-        tags = newPreset.setTags(tags, geometry, skipFieldDefaults, loc);
+      if (oldPreset) tags = oldPreset.unsetTags(tags, geometry, preserveKeys, false, loc);
+      if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults, loc);
       return graph.replace(entity.update({ tags }));
     };
   }
           }
         }
       }
-      if (val === "")
-        return [];
+      if (val === "") return [];
       var values = val.split(";");
       var results = [];
       values.forEach(function(v2) {
         }
         var lookBackward = this.tags["traffic_sign:backward"] || v2 === "backward" || v2 === "both" || v2 === "all";
         var lookForward = this.tags["traffic_sign:forward"] || v2 === "forward" || v2 === "both" || v2 === "all";
-        if (!lookForward && !lookBackward)
-          return;
+        if (!lookForward && !lookBackward) return;
         var nodeIds = {};
         resolver.parentWays(this).forEach(function(parent) {
           var nodes = parent.nodes;
         var parents = resolver.parentWays(this);
         if (parents.length > 1) {
           for (var i3 in parents) {
-            if (parents[i3].geometry(resolver) === "line" && parents[i3].hasInterestingTags())
-              return true;
+            if (parents[i3].geometry(resolver) === "line" && parents[i3].hasInterestingTags()) return true;
           }
         } else if (parents.length === 1) {
           var way = parents[0];
           }, this)
         }
       };
-      if (changeset_id)
-        r2.node["@changeset"] = changeset_id;
+      if (changeset_id) r2.node["@changeset"] = changeset_id;
       return r2;
     },
     asGeoJSON: function() {
   function actionCircularize(wayId, projection2, maxAngle) {
     maxAngle = (maxAngle || 20) * Math.PI / 180;
     var action = function(graph, t2) {
-      if (t2 === null || !isFinite(t2))
-        t2 = 1;
+      if (t2 === null || !isFinite(t2)) t2 = 1;
       t2 = Math.min(Math.max(+t2, 0), 1);
       var way = graph.entity(wayId);
       var origNodes = {};
       graph.childNodes(way).forEach(function(node2) {
-        if (!origNodes[node2.id])
-          origNodes[node2.id] = node2;
+        if (!origNodes[node2.id]) origNodes[node2.id] = node2;
       });
       if (!way.isConvex(graph)) {
         graph = action.makeConvex(graph);
           var parentWays = graph.parentWays(keyNodes[i3]);
           for (j2 = 0; j2 < parentWays.length; j2++) {
             var sharedWay = parentWays[j2];
-            if (sharedWay === way)
-              continue;
+            if (sharedWay === way) continue;
             if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
               var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id);
               var endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id);
           indexRange += nodes.length;
         }
         for (j2 = 1; j2 < indexRange; j2++) {
-          var point2 = geoVecInterp(hull[i3], hull[i3 + 1], j2 / indexRange);
-          var node = nodes[(j2 + startIndex) % nodes.length].move(projection2.invert(point2));
+          var point = geoVecInterp(hull[i3], hull[i3 + 1], j2 / indexRange);
+          var node = nodes[(j2 + startIndex) % nodes.length].move(projection2.invert(point));
           graph = graph.replace(node);
         }
       }
   // modules/actions/delete_way.js
   function actionDeleteWay(wayID) {
     function canDeleteNode(node, graph) {
-      if (graph.parentWays(node).length || graph.parentRelations(node).length)
-        return false;
+      if (graph.parentWays(node).length || graph.parentRelations(node).length) return false;
       var geometries = osmNodeGeometriesForTags(node.tags);
-      if (geometries.point)
-        return false;
-      if (geometries.vertex)
-        return true;
+      if (geometries.point) return false;
+      if (geometries.vertex) return true;
       return !node.hasInterestingTags();
     }
     var action = function(graph) {
       survivor = graph.entity(utilOldestID(interestingIDs.length > 0 ? interestingIDs : nodeIDs));
       for (i3 = 0; i3 < nodeIDs.length; i3++) {
         node = graph.entity(nodeIDs[i3]);
-        if (node.id === survivor.id)
-          continue;
+        if (node.id === survivor.id) continue;
         parents = graph.parentWays(node);
         for (j2 = 0; j2 < parents.length; j2++) {
           graph = graph.replace(parents[j2].replaceNode(node.id, survivor.id));
       restrictionIDs = utilArrayUniq(restrictionIDs);
       for (i3 = 0; i3 < restrictionIDs.length; i3++) {
         relation = graph.entity(restrictionIDs[i3]);
-        if (!relation.isComplete(graph))
-          continue;
+        if (!relation.isComplete(graph)) continue;
         var memberWays = relation.members.filter(function(m2) {
           return m2.type === "way";
         }).map(function(m2) {
         for (j2 = 0; j2 < memberWays.length; j2++) {
           way = memberWays[j2].update({});
           for (k2 = 0; k2 < nodeIDs.length; k2++) {
-            if (nodeIDs[k2] === survivor.id)
-              continue;
+            if (nodeIDs[k2] === survivor.id) continue;
             if (way.areAdjacent(nodeIDs[k2], survivor.id)) {
               way = way.removeNode(nodeIDs[k2]);
             } else {
       }
       function collectNodes(member, collection) {
         var entity = graph.hasEntity(member.id);
-        if (!entity)
-          return;
+        if (!entity) return;
         var role2 = member.role || "";
         if (!collection[role2]) {
           collection[role2] = [];
     };
     action.disabled = function(graph) {
       var connections = action.connections(graph);
-      if (connections.length === 0)
-        return "not_connected";
+      if (connections.length === 0) return "not_connected";
       var parentWays = graph.parentWays(graph.entity(nodeId));
       var seenRelationIds = {};
       var sharedRelation;
           }
         });
       });
-      if (sharedRelation)
-        return "relation";
+      if (sharedRelation) return "relation";
     };
     action.limitWays = function(val) {
-      if (!arguments.length)
-        return wayIds;
+      if (!arguments.length) return wayIds;
       wayIds = val;
       return action;
     };
           continue;
         }
         if (isBuilding) {
-          if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/))
-            continue;
+          if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
         }
         if (isIndoorArea && key === "indoor") {
           continue;
       }) });
       graph = graph.replace(survivor);
       joined.forEach(function(way) {
-        if (way.id === survivorID)
-          return;
+        if (way.id === survivorID) return;
         graph.parentRelations(way).forEach(function(parent) {
           graph = graph.replace(parent.replaceMember(way, survivor));
         });
         graph = actionDeleteWay(way.id)(graph);
       });
       function checkForSimpleMultipolygon() {
-        if (!survivor.isClosed())
-          return;
+        if (!survivor.isClosed()) return;
         var multipolygons = graph.parentMultipolygons(survivor).filter(function(multipolygon2) {
           return multipolygon2.members.length === 1;
         });
-        if (multipolygons.length !== 1)
-          return;
+        if (multipolygons.length !== 1) return;
         var multipolygon = multipolygons[0];
         for (var key in survivor.tags) {
           if (multipolygon.tags[key] && // don't collapse if tags cannot be cleanly merged
-          multipolygon.tags[key] !== survivor.tags[key])
-            return;
+          multipolygon.tags[key] !== survivor.tags[key]) return;
         }
         survivor = survivor.mergeTags(multipolygon.tags);
         graph = graph.replace(survivor);
       var geometries = groupEntitiesByGeometry(graph);
       var target = geometries.area[0] || geometries.line[0];
       var points = geometries.point;
-      points.forEach(function(point2) {
-        target = target.mergeTags(point2.tags);
+      points.forEach(function(point) {
+        target = target.mergeTags(point.tags);
         graph = graph.replace(target);
-        graph.parentRelations(point2).forEach(function(parent) {
-          graph = graph.replace(parent.replaceMember(point2, target));
+        graph.parentRelations(point).forEach(function(parent) {
+          graph = graph.replace(parent.replaceMember(point, target));
         });
         var nodes = utilArrayUniq(graph.childNodes(target));
-        var removeNode = point2;
-        if (!point2.isNew()) {
+        var removeNode = point;
+        if (!point.isNew()) {
           var inserted = false;
           var canBeReplaced = function(node2) {
             return !(graph.parentWays(node2).length > 1 || graph.parentRelations(node2).length);
           };
           var replaceNode = function(node2) {
-            graph = graph.replace(point2.update({ tags: node2.tags, loc: node2.loc }));
-            target = target.replaceNode(node2.id, point2.id);
+            graph = graph.replace(point.update({ tags: node2.tags, loc: node2.loc }));
+            target = target.replaceNode(node2.id, point.id);
             graph = graph.replace(target);
             removeNode = node2;
             inserted = true;
               break;
             }
           }
-          if (!inserted && point2.hasInterestingTags()) {
+          if (!inserted && point.hasInterestingTags()) {
             for (i3 = 0; i3 < nodes.length; i3++) {
               node = nodes[i3];
               if (canBeReplaced(node) && !node.hasInterestingTags()) {
             if (!inserted) {
               for (i3 = 0; i3 < nodes.length; i3++) {
                 node = nodes[i3];
-                if (canBeReplaced(node) && utilCompareIDs(point2.id, node.id) < 0) {
+                if (canBeReplaced(node) && utilCompareIDs(point.id, node.id) < 0) {
                   replaceNode(node);
                   break;
                 }
   // modules/actions/merge_nodes.js
   function actionMergeNodes(nodeIDs, loc) {
     function chooseLoc(graph) {
-      if (!nodeIDs.length)
-        return null;
+      if (!nodeIDs.length) return null;
       var sum = [0, 0];
       var interestingCount = 0;
       var interestingLoc;
       return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
     }
     var action = function(graph) {
-      if (nodeIDs.length < 2)
-        return graph;
+      if (nodeIDs.length < 2) return graph;
       var toLoc = loc;
       if (!toLoc) {
         toLoc = chooseLoc(graph);
       return actionConnect(nodeIDs)(graph);
     };
     action.disabled = function(graph) {
-      if (nodeIDs.length < 2)
-        return "not_eligible";
+      if (nodeIDs.length < 2) return "not_eligible";
       for (var i3 = 0; i3 < nodeIDs.length; i3++) {
         var entity = graph.entity(nodeIDs[i3]);
-        if (entity.type !== "node")
-          return "not_eligible";
+        if (entity.type !== "node") return "not_eligible";
       }
       return actionConnect(nodeIDs).disabled(graph);
     };
         var groups = {};
         for (var i3 = 0; i3 < x2.length; i3++) {
           var tagName = Object.keys(x2[i3])[0];
-          if (!groups[tagName])
-            groups[tagName] = [];
+          if (!groups[tagName]) groups[tagName] = [];
           groups[tagName].push(x2[i3][tagName]);
         }
         var ordered = {};
         order.forEach(function(o2) {
-          if (groups[o2])
-            ordered[o2] = groups[o2];
+          if (groups[o2]) ordered[o2] = groups[o2];
         });
         return ordered;
       }
         var processing = [];
         var sorted = {};
         var relations = changes2.relation;
-        if (!relations)
-          return changes2;
+        if (!relations) return changes2;
         for (var i3 = 0; i3 < relations.length; i3++) {
           var relation = relations[i3];
           if (!sorted[relation["@id"]]) {
   osmRelation.creationOrder = function(a2, b2) {
     var aId = parseInt(osmEntity.id.toOSM(a2.id), 10);
     var bId = parseInt(osmEntity.id.toOSM(b2.id), 10);
-    if (aId < 0 || bId < 0)
-      return aId - bId;
+    if (aId < 0 || bId < 0) return aId - bId;
     return bId - aId;
   };
   Object.assign(osmRelation.prototype, {
     type: "relation",
     members: [],
     copy: function(resolver, copies) {
-      if (copies[this.id])
-        return copies[this.id];
+      if (copies[this.id]) return copies[this.id];
       var copy2 = osmEntity.prototype.copy.call(this, resolver, copies);
       var members = this.members.map(function(member) {
         return Object.assign({}, member, { id: resolver.entity(member.id).copy(resolver, copies).id });
     },
     extent: function(resolver, memo) {
       return resolver.transient(this, "extent", function() {
-        if (memo && memo[this.id])
-          return geoExtent();
+        if (memo && memo[this.id]) return geoExtent();
         memo = memo || {};
         memo[this.id] = true;
         var extent = geoExtent();
     // By default, adding a duplicate member (by id and role) is prevented.
     // Return an updated relation.
     replaceMember: function(needle, replacement, keepDuplicates) {
-      if (!this.memberById(needle.id))
-        return this;
+      if (!this.memberById(needle.id)) return this;
       var members = [];
       for (var i3 = 0; i3 < this.members.length; i3++) {
         var member = this.members[i3];
       return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
     },
     isValidRestriction: function() {
-      if (!this.isRestriction())
-        return false;
+      if (!this.isRestriction()) return false;
       var froms = this.members.filter(function(m2) {
         return m2.role === "from";
       });
       var tos = this.members.filter(function(m2) {
         return m2.role === "to";
       });
-      if (froms.length !== 1 && this.tags.restriction !== "no_entry")
-        return false;
+      if (froms.length !== 1 && this.tags.restriction !== "no_entry") return false;
       if (froms.some(function(m2) {
         return m2.type !== "way";
-      }))
-        return false;
-      if (tos.length !== 1 && this.tags.restriction !== "no_exit")
-        return false;
+      })) return false;
+      if (tos.length !== 1 && this.tags.restriction !== "no_exit") return false;
       if (tos.some(function(m2) {
         return m2.type !== "way";
-      }))
-        return false;
-      if (vias.length === 0)
-        return false;
+      })) return false;
+      if (vias.length === 0) return false;
       if (vias.length > 1 && vias.some(function(m2) {
         return m2.type !== "way";
-      }))
-        return false;
+      })) return false;
       return true;
     },
     isConnectivity: function() {
 
   // modules/actions/split.js
   function actionSplit(nodeIds, newWayIds) {
-    if (typeof nodeIds === "string")
-      nodeIds = [nodeIds];
+    if (typeof nodeIds === "string") nodeIds = [nodeIds];
     var _wayIDs;
     var _keepHistoryOn = "longest";
     const circularJunctions = ["roundabout", "circular"];
     }
     function splitWayMember(graph, relationId, wayA, wayB) {
       function connects(way1, way2) {
-        if (way1.nodes.length < 2 || way2.nodes.length < 2)
-          return false;
+        if (way1.nodes.length < 2 || way2.nodes.length < 2) return false;
         if (circularJunctions.includes(way1.tags.junction) && way1.isClosed()) {
           return way1.nodes.some((nodeId) => nodeId === way2.nodes[0] || nodeId === way2.nodes[way2.nodes.length - 1]);
         } else if (circularJunctions.includes(way2.tags.junction) && way2.isClosed()) {
           return way2.nodes.some((nodeId) => nodeId === way1.nodes[0] || nodeId === way1.nodes[way1.nodes.length - 1]);
         }
-        if (way1.nodes[0] === way2.nodes[0])
-          return true;
-        if (way1.nodes[0] === way2.nodes[way2.nodes.length - 1])
-          return true;
-        if (way1.nodes[way1.nodes.length - 1] === way2.nodes[way2.nodes.length - 1])
-          return true;
-        if (way1.nodes[way1.nodes.length - 1] === way2.nodes[0])
-          return true;
+        if (way1.nodes[0] === way2.nodes[0]) return true;
+        if (way1.nodes[0] === way2.nodes[way2.nodes.length - 1]) return true;
+        if (way1.nodes[way1.nodes.length - 1] === way2.nodes[way2.nodes.length - 1]) return true;
+        if (way1.nodes[way1.nodes.length - 1] === way2.nodes[0]) return true;
         return false;
       }
       let relation = graph.entity(relationId);
       }
       return splittableParents;
       function isSplittable(parent) {
-        if (_wayIDs && _wayIDs.indexOf(parent.id) === -1)
-          return false;
-        if (parent.isClosed())
-          return true;
+        if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false;
+        if (parent.isClosed()) return true;
         for (var i3 = 1; i3 < parent.nodes.length - 1; i3++) {
-          if (parent.nodes[i3] === nodeId)
-            return true;
+          if (parent.nodes[i3] === nodeId) return true;
         }
         return false;
       }
       }
     };
     action.limitWays = function(val) {
-      if (!arguments.length)
-        return _wayIDs;
+      if (!arguments.length) return _wayIDs;
       _wayIDs = val;
       return action;
     };
     action.keepHistoryOn = function(val) {
-      if (!arguments.length)
-        return _keepHistoryOn;
+      if (!arguments.length) return _keepHistoryOn;
       _keepHistoryOn = val;
       return action;
     };
 
   // modules/core/graph.js
   function coreGraph(other, mutable) {
-    if (!(this instanceof coreGraph))
-      return new coreGraph(other, mutable);
+    if (!(this instanceof coreGraph)) return new coreGraph(other, mutable);
     if (other instanceof coreGraph) {
       var base = other.base();
       this.entities = Object.assign(Object.create(base.entities), other.entities);
       });
     },
     childNodes: function(entity) {
-      if (this._childNodes[entity.id])
-        return this._childNodes[entity.id];
-      if (!entity.nodes)
-        return [];
+      if (this._childNodes[entity.id]) return this._childNodes[entity.id];
+      if (!entity.nodes) return [];
       var nodes = [];
       for (var i3 = 0; i3 < entity.nodes.length; i3++) {
         nodes[i3] = this.entity(entity.nodes[i3]);
       }
-      if (debug)
-        Object.freeze(nodes);
+      if (debug) Object.freeze(nodes);
       this._childNodes[entity.id] = nodes;
       return this._childNodes[entity.id];
     },
       var i3, j2, k2, id2;
       for (i3 = 0; i3 < entities.length; i3++) {
         var entity = entities[i3];
-        if (!entity.visible || !force && base.entities[entity.id])
-          continue;
+        if (!entity.visible || !force && base.entities[entity.id]) continue;
         base.entities[entity.id] = entity;
         this._updateCalculated(void 0, entity, base.parentWays, base.parentRels);
         if (entity.type === "way") {
       }
     },
     replace: function(entity) {
-      if (this.entities[entity.id] === entity)
-        return this;
+      if (this.entities[entity.id] === entity) return this;
       return this.update(function() {
         this._updateCalculated(this.entities[entity.id], entity);
         this.entities[entity.id] = entity;
     revert: function(id2) {
       var baseEntity = this.base().entities[id2];
       var headEntity = this.entities[id2];
-      if (headEntity === baseEntity)
-        return this;
+      if (headEntity === baseEntity) return this;
       return this.update(function() {
         this._updateCalculated(headEntity, baseEntity);
         delete this.entities[id2];
       for (var i3 = 0; i3 < arguments.length; i3++) {
         arguments[i3].call(graph, graph);
       }
-      if (this.frozen)
-        graph.frozen = true;
+      if (this.frozen) graph.frozen = true;
       return graph;
     },
     // Obliterates any existing entities
       });
     }
     function isRoad(way2) {
-      if (way2.isArea() || way2.isDegenerate())
-        return false;
+      if (way2.isArea() || way2.isDegenerate()) return false;
       var roads = {
         "motorway": true,
         "motorway_link": true,
       var hasWays = false;
       for (i3 = 0; i3 < checkWays.length; i3++) {
         way = checkWays[i3];
-        if (!isRoad(way) && !memberOfRestriction(way))
-          continue;
+        if (!isRoad(way) && !memberOfRestriction(way)) continue;
         ways.push(way);
         hasWays = true;
         nodes = utilArrayUniq(graph.childNodes(way));
         for (j2 = 0; j2 < nodes.length; j2++) {
           node = nodes[j2];
-          if (node === vertex)
-            continue;
-          if (vertices.indexOf(node) !== -1)
-            continue;
-          if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance)
-            continue;
+          if (node === vertex) continue;
+          if (vertices.indexOf(node) !== -1) continue;
+          if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue;
           var hasParents = false;
           parents = graph.parentWays(node);
           for (k2 = 0; k2 < parents.length; k2++) {
             parent = parents[k2];
-            if (parent === way)
-              continue;
-            if (ways.indexOf(parent) !== -1)
-              continue;
-            if (!isRoad(parent))
-              continue;
+            if (parent === way) continue;
+            if (ways.indexOf(parent) !== -1) continue;
+            if (!isRoad(parent)) continue;
             hasParents = true;
             break;
           }
       ways
     };
     intersection2.turns = function(fromWayId, maxViaWay) {
-      if (!fromWayId)
-        return [];
-      if (!maxViaWay)
-        maxViaWay = 0;
+      if (!fromWayId) return [];
+      if (!maxViaWay) maxViaWay = 0;
       var vgraph2 = intersection2.graph;
       var keyVertexIds = intersection2.vertices.map(function(v2) {
         return v2.id;
       });
       var start2 = vgraph2.entity(fromWayId);
-      if (!start2 || !(start2.__from || start2.__via))
-        return [];
+      if (!start2 || !(start2.__from || start2.__via)) return [];
       var maxPathLength = maxViaWay * 2 + 3;
       var turns = [];
       step(start2);
       return turns;
       function step(entity, currPath, currRestrictions, matchedRestriction) {
         currPath = (currPath || []).slice();
-        if (currPath.length >= maxPathLength)
-          return;
+        if (currPath.length >= maxPathLength) return;
         currPath.push(entity.id);
         currRestrictions = (currRestrictions || []).slice();
         if (entity.type === "node") {
         var nextWays = [];
         for (i4 = 0; i4 < parents2.length; i4++) {
           var way2 = parents2[i4];
-          if (way2.__oneWay && way2.nodes[0] !== entity.id)
-            continue;
-          if (currPath.indexOf(way2.id) !== -1 && currPath.length >= 3)
-            continue;
+          if (way2.__oneWay && way2.nodes[0] !== entity.id) continue;
+          if (currPath.indexOf(way2.id) !== -1 && currPath.length >= 3) continue;
           var restrict = null;
           for (j3 = 0; j3 < currRestrictions.length; j3++) {
             var restriction = currRestrictions[j3];
                 restrict = { id: restriction.id, direct: false, from: f2.id, no: true, end: true };
               }
             }
-            if (restrict && restrict.direct)
-              break;
+            if (restrict && restrict.direct) break;
           }
           nextWays.push({ way: way2, restrict });
         }
             }
             turns.push(osmTurn(turn));
           }
-          if (currPath[0] === currPath[2])
-            return;
+          if (currPath[0] === currPath[2]) return;
         }
-        if (matchedRestriction && matchedRestriction.end)
-          return;
+        if (matchedRestriction && matchedRestriction.end) return;
         var n1 = vgraph2.entity(entity.first());
         var n22 = vgraph2.entity(entity.last());
         var dist = geoSphericalDistance(n1.loc, n22.loc);
         var nextNodes = [];
         if (currPath.length > 1) {
-          if (dist > maxDistance)
-            return;
-          if (!entity.__via)
-            return;
+          if (dist > maxDistance) return;
+          if (!entity.__via) return;
         }
         if (!entity.__oneWay && // bidirectional..
         keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
         }
         nextNodes.forEach(function(nextNode) {
           var fromRestrictions = vgraph2.parentRelations(entity).filter(function(r2) {
-            if (!r2.isRestriction())
-              return false;
+            if (!r2.isRestriction()) return false;
             var f2 = r2.memberByRole("from");
-            if (!f2 || f2.id !== entity.id)
-              return false;
+            if (!f2 || f2.id !== entity.id) return false;
             var isOnly = /^only_/.test(r2.tags.restriction);
-            if (!isOnly)
-              return true;
+            if (!isOnly) return true;
             var isOnlyVia = false;
             var v2 = r2.membersByRole("via");
             if (v2.length === 1 && v2[0].type === "node") {
               isOnlyVia = v2[0].id === nextNode.id;
             } else {
               for (var i5 = 0; i5 < v2.length; i5++) {
-                if (v2[i5].type !== "way")
-                  continue;
+                if (v2[i5].type !== "way") continue;
                 var viaWay = vgraph2.entity(v2[i5].id);
                 if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
                   isOnlyVia = true;
         });
       }
       function pathToTurn(path) {
-        if (path.length < 3)
-          return;
+        if (path.length < 3) return;
         var fromWayId2, fromNodeId, fromVertexId;
         var toWayId, toNodeId, toVertexId;
         var viaWayIds, viaNodeId, isUturn;
         toWayId = path[path.length - 1];
         if (path.length === 3 && fromWayId2 === toWayId) {
           var way2 = vgraph2.entity(fromWayId2);
-          if (way2.__oneWay)
-            return null;
+          if (way2.__oneWay) return null;
           isUturn = true;
           viaNodeId = fromVertexId = toVertexId = path[1];
           fromNodeId = toNodeId = adjacentNode(fromWayId2, viaNodeId);
       }));
       var contained = polygons.map(function(w2, i3) {
         return polygons.map(function(d2, n3) {
-          if (i3 === n3)
-            return null;
+          if (i3 === n3) return null;
           return geoPolygonContainsPolygon(
             d2.nodes.map(function(n4) {
               return n4.loc;
       while (hunks.length) {
         const nextHunk = hunks[0];
         const nextHunkStart = nextHunk.oStart;
-        if (nextHunkStart > regionEnd)
-          break;
+        if (nextHunkStart > regionEnd) break;
         regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
         regionHunks.push(hunks.shift());
       }
       stringSeparator: /\s+/
     };
     options2 = Object.assign(defaults, options2);
-    if (typeof a2 === "string")
-      a2 = a2.split(options2.stringSeparator);
-    if (typeof o2 === "string")
-      o2 = o2.split(options2.stringSeparator);
-    if (typeof b2 === "string")
-      b2 = b2.split(options2.stringSeparator);
+    if (typeof a2 === "string") a2 = a2.split(options2.stringSeparator);
+    if (typeof o2 === "string") o2 = o2.split(options2.stringSeparator);
+    if (typeof b2 === "string") b2 = b2.split(options2.stringSeparator);
     let results = [];
     const regions = diff3MergeRegions(a2, o2, b2);
     let okBuffer = [];
       okBuffer = [];
     }
     function isFalseConflict(a3, b3) {
-      if (a3.length !== b3.length)
-        return false;
+      if (a3.length !== b3.length) return false;
       for (let i3 = 0; i3 < a3.length; i3++) {
-        if (a3[i3] !== b3[i3])
-          return false;
+        if (a3[i3] !== b3[i3]) return false;
       }
       return true;
     }
           } else {
             _conflicts.push(_t.html("merge_remote_changes.conflict.deleted", { user: { html: user(remote.user) } }));
           }
-          if (_conflicts.length !== ccount)
-            break;
+          if (_conflicts.length !== ccount) break;
           updates.replacements.push(target);
         }
       }
     var _delta = tryDelta;
     function setupCache(graph) {
       function canMove(nodeID) {
-        if (moveIDs.indexOf(nodeID) !== -1)
-          return true;
+        if (moveIDs.indexOf(nodeID) !== -1) return true;
         var parents = graph.parentWays(graph.entity(nodeID));
-        if (parents.length < 3)
-          return true;
+        if (parents.length < 3) return true;
         var parentsMoving = parents.every(function(way) {
           return cache.moving[way.id];
         });
-        if (!parentsMoving)
-          delete cache.moving[nodeID];
+        if (!parentsMoving) delete cache.moving[nodeID];
         return parentsMoving;
       }
       function cacheEntities(ids) {
         for (var i3 = 0; i3 < ids.length; i3++) {
           var id2 = ids[i3];
-          if (cache.moving[id2])
-            continue;
+          if (cache.moving[id2]) continue;
           cache.moving[id2] = true;
           var entity = graph.hasEntity(id2);
-          if (!entity)
-            continue;
+          if (!entity) continue;
           if (entity.type === "node") {
             cache.nodes.push(id2);
             cache.startLoc[id2] = entity.loc;
           for (var j2 = 0; j2 < childNodes.length; j2++) {
             var node = childNodes[j2];
             var parents = graph.parentWays(node);
-            if (parents.length !== 2)
-              continue;
+            if (parents.length !== 2) continue;
             var moved = graph.entity(id2);
             var unmoved = null;
             for (var k2 = 0; k2 < parents.length; k2++) {
                 break;
               }
             }
-            if (!unmoved)
-              continue;
-            if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2)
-              continue;
-            if (moved.isArea() || unmoved.isArea())
-              continue;
+            if (!unmoved) continue;
+            if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2) continue;
+            if (moved.isArea() || unmoved.isArea()) continue;
             cache.intersections.push({
               nodeId: node.id,
               movedId: moved.id,
       }
       var prev = graph.hasEntity(way.nodes[prevIndex]);
       var next = graph.hasEntity(way.nodes[nextIndex]);
-      if (!prev || !next)
-        return graph;
+      if (!prev || !next) return graph;
       var key = wayId + "_" + nodeId;
       var orig = cache.replacedVertex[key];
       if (!orig) {
       }
       orig = orig.move(end);
       var angle2 = Math.abs(geoAngle(orig, prev, projection2) - geoAngle(orig, next, projection2)) * 180 / Math.PI;
-      if (angle2 > 175 && angle2 < 185)
-        return graph;
+      if (angle2 > 175 && angle2 < 185) return graph;
       var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection2);
       var p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection2);
       var d1 = geoPathLength(p1);
       var d2 = geoPathLength(p2);
       var insertAt = d1 <= d2 ? movedIndex : nextIndex;
-      if (way.isClosed() && insertAt === 0)
-        insertAt = len;
+      if (way.isClosed() && insertAt === 0) insertAt = len;
       way = way.addNode(orig.id, insertAt);
       return graph.replace(orig).replace(way);
     }
       var way2 = graph.entity(intersection2.unmovedId);
       var isEP1 = intersection2.movedIsEP;
       var isEP2 = intersection2.unmovedIsEP;
-      if (isEP1 && isEP2)
-        return graph;
+      if (isEP1 && isEP2) return graph;
       var nodes1 = graph.childNodes(way1).filter(function(n3) {
         return n3 !== vertex;
       });
       var nodes2 = graph.childNodes(way2).filter(function(n3) {
         return n3 !== vertex;
       });
-      if (way1.isClosed() && way1.first() === vertex.id)
-        nodes1.push(nodes1[0]);
-      if (way2.isClosed() && way2.first() === vertex.id)
-        nodes2.push(nodes2[0]);
+      if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
+      if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
       var edge1 = !isEP1 && geoChooseEdge(nodes1, projection2(vertex.loc), projection2);
       var edge2 = !isEP2 && geoChooseEdge(nodes2, projection2(vertex.loc), projection2);
       var loc;
           loc = geoVecInterp(edge1.loc, edge2.loc, 0.5);
           edge1 = geoChooseEdge(nodes1, projection2(loc), projection2);
           edge2 = geoChooseEdge(nodes2, projection2(loc), projection2);
-          if (Math.abs(edge1.distance - edge2.distance) < epsilon3)
-            break;
+          if (Math.abs(edge1.distance - edge2.distance) < epsilon3) break;
         }
       } else if (!isEP1) {
         loc = edge1.loc;
       }
       for (var i3 = 0; i3 < cache.intersections.length; i3++) {
         var obj = cache.intersections[i3];
-        if (obj.movedIsEP && obj.unmovedIsEP)
-          continue;
-        if (!obj.movedIsEP)
-          continue;
+        if (obj.movedIsEP && obj.unmovedIsEP) continue;
+        if (!obj.movedIsEP) continue;
         var node = graph.entity(obj.nodeId);
         var start2 = projection2(node.loc);
         var end = geoVecAdd(start2, _delta);
         });
         var hits = geoPathIntersections(movedPath, unmovedPath);
         for (var j2 = 0; i3 < hits.length; i3++) {
-          if (geoVecEqual(hits[j2], end))
-            continue;
+          if (geoVecEqual(hits[j2], end)) continue;
           var edge = geoChooseEdge(unmovedNodes, end, projection2);
           _delta = geoVecSubtract(projection2(edge.loc), start2);
         }
       }
     }
     var action = function(graph) {
-      if (_delta[0] === 0 && _delta[1] === 0)
-        return graph;
+      if (_delta[0] === 0 && _delta[1] === 0) return graph;
       setupCache(graph);
       if (cache.intersections.length) {
         limitDelta(graph);
   // modules/actions/move_node.js
   function actionMoveNode(nodeID, toLoc) {
     var action = function(graph, t2) {
-      if (t2 === null || !isFinite(t2))
-        t2 = 1;
+      if (t2 === null || !isFinite(t2)) t2 = 1;
       t2 = Math.min(Math.max(+t2, 0), 1);
       var node = graph.entity(nodeID);
       return graph.replace(
     var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
     var upperThreshold = Math.cos(threshold * Math.PI / 180);
     var action = function(graph, t2) {
-      if (t2 === null || !isFinite(t2))
-        t2 = 1;
+      if (t2 === null || !isFinite(t2)) t2 = 1;
       t2 = Math.min(Math.max(+t2, 0), 1);
       var way = graph.entity(wayID);
       way = way.removeNode("");
       graph = graph.replace(way);
       var isClosed = way.isClosed();
       var nodes = graph.childNodes(way).slice();
-      if (isClosed)
-        nodes.pop();
+      if (isClosed) nodes.pop();
       if (vertexID !== void 0) {
         nodes = nodeSubset(nodes, vertexID, isClosed);
-        if (nodes.length !== 3)
-          return graph;
+        if (nodes.length !== 3) return graph;
       }
       var nodeCount = {};
       var points = [];
       var corner = { i: 0, dotp: 1 };
-      var node, point2, loc, score, motions, i3, j2;
+      var node, point, loc, score, motions, i3, j2;
       for (i3 = 0; i3 < nodes.length; i3++) {
         node = nodes[i3];
         nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
         var straights = [];
         var simplified = [];
         for (i3 = 0; i3 < points.length; i3++) {
-          point2 = points[i3];
+          point = points[i3];
           var dotp = 0;
           if (isClosed || i3 > 0 && i3 < points.length - 1) {
             var a2 = points[(i3 - 1 + points.length) % points.length];
             var b2 = points[(i3 + 1) % points.length];
-            dotp = Math.abs(geoOrthoNormalizedDotProduct(a2.coord, b2.coord, point2.coord));
+            dotp = Math.abs(geoOrthoNormalizedDotProduct(a2.coord, b2.coord, point.coord));
           }
           if (dotp > upperThreshold) {
-            straights.push(point2);
+            straights.push(point);
           } else {
-            simplified.push(point2);
+            simplified.push(point);
           }
         }
         var bestPoints = clonePoints(simplified);
         var bestCoords = bestPoints.map(function(p2) {
           return p2.coord;
         });
-        if (isClosed)
-          bestCoords.push(bestCoords[0]);
+        if (isClosed) bestCoords.push(bestCoords[0]);
         for (i3 = 0; i3 < bestPoints.length; i3++) {
-          point2 = bestPoints[i3];
-          if (!geoVecEqual(originalPoints[i3].coord, point2.coord)) {
-            node = graph.entity(point2.id);
-            loc = projection2.invert(point2.coord);
+          point = bestPoints[i3];
+          if (!geoVecEqual(originalPoints[i3].coord, point.coord)) {
+            node = graph.entity(point.id);
+            loc = projection2.invert(point.coord);
             graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t2)));
           }
         }
         for (i3 = 0; i3 < straights.length; i3++) {
-          point2 = straights[i3];
-          if (nodeCount[point2.id] > 1)
-            continue;
-          node = graph.entity(point2.id);
+          point = straights[i3];
+          if (nodeCount[point.id] > 1) continue;
+          node = graph.entity(point.id);
           if (t2 === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
             graph = actionDeleteNode(node.id)(graph);
           } else {
-            var choice = geoVecProject(point2.coord, bestCoords);
+            var choice = geoVecProject(point.coord, bestCoords);
             if (choice) {
               loc = projection2.invert(choice.target);
               graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t2)));
           return { id: p2.id, coord: [p2.coord[0], p2.coord[1]] };
         });
       }
-      function calcMotion(point3, i4, array2) {
-        if (!isClosed && (i4 === 0 || i4 === array2.length - 1))
-          return [0, 0];
-        if (nodeCount[array2[i4].id] > 1)
-          return [0, 0];
+      function calcMotion(point2, i4, array2) {
+        if (!isClosed && (i4 === 0 || i4 === array2.length - 1)) return [0, 0];
+        if (nodeCount[array2[i4].id] > 1) return [0, 0];
         var a3 = array2[(i4 - 1 + array2.length) % array2.length].coord;
-        var origin = point3.coord;
+        var origin = point2.coord;
         var b3 = array2[(i4 + 1) % array2.length].coord;
         var p2 = geoVecSubtract(a3, origin);
         var q2 = geoVecSubtract(b3, origin);
       graph = graph.replace(way);
       var isClosed = way.isClosed();
       var nodes = graph.childNodes(way).slice();
-      if (isClosed)
-        nodes.pop();
+      if (isClosed) nodes.pop();
       var allowStraightAngles = false;
       if (vertexID !== void 0) {
         allowStraightAngles = true;
         nodes = nodeSubset(nodes, vertexID, isClosed);
-        if (nodes.length !== 3)
-          return "end_vertex";
+        if (nodes.length !== 3) return "end_vertex";
       }
       var coords = nodes.map(function(n3) {
         return projection2(n3.loc);
     var action = function(graph) {
       return graph.update(function(graph2) {
         utilGetAllNodes(rotateIds, graph2).forEach(function(node) {
-          var point2 = geoRotate([projection2(node.loc)], angle2, pivot)[0];
-          graph2 = graph2.replace(node.move(projection2.invert(point2)));
+          var point = geoRotate([projection2(node.loc)], angle2, pivot)[0];
+          graph2 = graph2.replace(node.move(projection2.invert(point)));
         });
       });
     };
   function actionScale(ids, pivotLoc, scaleFactor, projection2) {
     return function(graph) {
       return graph.update(function(graph2) {
-        let point2, radial;
+        let point, radial;
         utilGetAllNodes(ids, graph2).forEach(function(node) {
-          point2 = projection2(node.loc);
+          point = projection2(node.loc);
           radial = [
-            point2[0] - pivotLoc[0],
-            point2[1] - pivotLoc[1]
+            point[0] - pivotLoc[0],
+            point[1] - pivotLoc[1]
           ];
-          point2 = [
+          point = [
             pivotLoc[0] + scaleFactor * radial[0],
             pivotLoc[1] + scaleFactor * radial[1]
           ];
-          graph2 = graph2.replace(node.move(projection2.invert(point2)));
+          graph2 = graph2.replace(node.move(projection2.invert(point)));
         });
       });
     };
       return [p2, q2];
     }
     var action = function(graph, t2) {
-      if (t2 === null || !isFinite(t2))
-        t2 = 1;
+      if (t2 === null || !isFinite(t2)) t2 = 1;
       t2 = Math.min(Math.max(+t2, 0), 1);
       var nodes = nodeIDs.map(function(id2) {
         return graph.entity(id2);
       var endPoint = endpoints[1];
       for (var i3 = 0; i3 < points.length; i3++) {
         var node = nodes[i3];
-        var point2 = points[i3];
-        var u2 = positionAlongWay(point2, startPoint, endPoint);
-        var point22 = geoVecInterp(startPoint, endPoint, u2);
-        var loc2 = projection2.invert(point22);
+        var point = points[i3];
+        var u2 = positionAlongWay(point, startPoint, endPoint);
+        var point2 = geoVecInterp(startPoint, endPoint, u2);
+        var loc2 = projection2.invert(point2);
         graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t2)));
       }
       return graph;
       var endPoint = endpoints[1];
       var maxDistance = 0;
       for (var i3 = 0; i3 < points.length; i3++) {
-        var point2 = points[i3];
-        var u2 = positionAlongWay(point2, startPoint, endPoint);
+        var point = points[i3];
+        var u2 = positionAlongWay(point, startPoint, endPoint);
         var p2 = geoVecInterp(startPoint, endPoint, u2);
-        var dist = geoVecLength(p2, point2);
+        var dist = geoVecLength(p2, point);
         if (!isNaN(dist) && dist > maxDistance) {
           maxDistance = dist;
         }
       return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
     }
     var action = function(graph, t2) {
-      if (t2 === null || !isFinite(t2))
-        t2 = 1;
+      if (t2 === null || !isFinite(t2)) t2 = 1;
       t2 = Math.min(Math.max(+t2, 0), 1);
       var nodes = allNodes(graph);
       var points = nodes.map(function(n3) {
       var i3;
       for (i3 = 1; i3 < points.length - 1; i3++) {
         var node = nodes[i3];
-        var point2 = points[i3];
+        var point = points[i3];
         if (t2 < 1 || shouldKeepNode(node, graph)) {
-          var u2 = positionAlongWay(point2, startPoint, endPoint);
+          var u2 = positionAlongWay(point, startPoint, endPoint);
           var p2 = geoVecInterp(startPoint, endPoint, u2);
           var loc2 = projection2.invert(p2);
           graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t2)));
       }
       var maxDistance = 0;
       for (i3 = 1; i3 < points.length - 1; i3++) {
-        var point2 = points[i3];
-        var u2 = positionAlongWay(point2, startPoint, endPoint);
+        var point = points[i3];
+        var u2 = positionAlongWay(point, startPoint, endPoint);
         var p2 = geoVecInterp(startPoint, endPoint, u2);
-        var dist = geoVecLength(p2, point2);
+        var dist = geoVecLength(p2, point);
         if (isNaN(dist) || dist > threshold) {
           return "too_bendy";
         } else if (dist > maxDistance) {
   function actionReflect(reflectIds, projection2) {
     var _useLongAxis = true;
     var action = function(graph, t2) {
-      if (t2 === null || !isFinite(t2))
-        t2 = 1;
+      if (t2 === null || !isFinite(t2)) t2 = 1;
       t2 = Math.min(Math.max(+t2, 0), 1);
       var nodes = utilGetAllNodes(reflectIds, graph);
       var points = nodes.map(function(n3) {
       return graph;
     };
     action.useLongAxis = function(val) {
-      if (!arguments.length)
-        return _useLongAxis;
+      if (!arguments.length) return _useLongAxis;
       _useLongAxis = val;
       return action;
     };
       var transferValue;
       var semiIndex;
       for (var oldTagKey in oldTags) {
-        if (!(oldTagKey in tags))
-          continue;
+        if (!(oldTagKey in tags)) continue;
         if (oldTags[oldTagKey] === "*") {
           transferValue = tags[oldTagKey];
           delete tags[oldTagKey];
       select_default2(window).on(_pointerPrefix + "up.hover pointercancel.hover", pointerout, true).on("keydown.hover", keydown).on("keyup.hover", keyup);
       function eventTarget(d3_event) {
         var datum2 = d3_event.target && d3_event.target.__data__;
-        if (typeof datum2 !== "object")
-          return null;
+        if (typeof datum2 !== "object") return null;
         if (!(datum2 instanceof osmEntity) && datum2.properties && datum2.properties.entity instanceof osmEntity) {
           return datum2.properties.entity;
         }
         return datum2;
       }
       function pointerover(d3_event) {
-        if (context.mode().id.indexOf("drag") === -1 && (!d3_event.pointerType || d3_event.pointerType === "mouse") && d3_event.buttons)
-          return;
+        if (context.mode().id.indexOf("drag") === -1 && (!d3_event.pointerType || d3_event.pointerType === "mouse") && d3_event.buttons) return;
         var target = eventTarget(d3_event);
         if (target && _targets.indexOf(target) === -1) {
           _targets.push(target);
       select_default2(window).on(_pointerPrefix + "up.hover pointercancel.hover", null, true).on("keydown.hover", null).on("keyup.hover", null);
     };
     behavior.altDisables = function(val) {
-      if (!arguments.length)
-        return _altDisables;
+      if (!arguments.length) return _altDisables;
       _altDisables = val;
       return behavior;
     };
     behavior.ignoreVertex = function(val) {
-      if (!arguments.length)
-        return _ignoreVertex;
+      if (!arguments.length) return _ignoreVertex;
       _ignoreVertex = val;
       return behavior;
     };
     function datum2(d3_event) {
       var mode = context.mode();
       var isNote = mode && mode.id.indexOf("note") !== -1;
-      if (d3_event.altKey || isNote)
-        return {};
+      if (d3_event.altKey || isNote) return {};
       var element;
       if (d3_event.type === "keydown") {
         element = _lastMouse && _lastMouse.target;
       return d2 && d2.properties && d2.properties.target ? d2 : {};
     }
     function pointerdown(d3_event) {
-      if (_downPointer)
-        return;
+      if (_downPointer) return;
       var pointerLocGetter = utilFastMouse(this);
       _downPointer = {
         id: d3_event.pointerId || "mouse",
       dispatch14.call("down", this, d3_event, datum2(d3_event));
     }
     function pointerup(d3_event) {
-      if (!_downPointer || _downPointer.id !== (d3_event.pointerId || "mouse"))
-        return;
+      if (!_downPointer || _downPointer.id !== (d3_event.pointerId || "mouse")) return;
       var downPointer = _downPointer;
       _downPointer = null;
       _lastPointerUpEvent = d3_event;
-      if (downPointer.isCancelled)
-        return;
+      if (downPointer.isCancelled) return;
       var t2 = +/* @__PURE__ */ new Date();
       var p2 = downPointer.pointerLocGetter(d3_event);
       var dist = geoVecLength(downPointer.downLoc, p2);
           dispatch14.call("downcancel", this);
         }
       }
-      if (d3_event.pointerType && d3_event.pointerType !== "mouse" || d3_event.buttons || _downPointer)
-        return;
-      if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== "mouse" && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100)
-        return;
+      if (d3_event.pointerType && d3_event.pointerType !== "mouse" || d3_event.buttons || _downPointer) return;
+      if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== "mouse" && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
       _lastMouse = d3_event;
       dispatch14.call("move", this, d3_event, datum2(d3_event));
     }
           _disableSpace = false;
         }
       }
-      if (_disableSpace || _mouseLeave || !_lastMouse)
-        return;
+      if (_disableSpace || _mouseLeave || !_lastMouse) return;
       _lastSpace = currSpace;
       _disableSpace = true;
       select_default2(window).on("keyup.space-block", function() {
   }
   function clamper(a2, b2) {
     var t2;
-    if (a2 > b2)
-      t2 = a2, a2 = b2, b2 = t2;
+    if (a2 > b2) t2 = a2, a2 = b2, b2 = t2;
     return function(x2) {
       return Math.max(a2, Math.min(b2, x2));
     };
   }
   function bimap(domain, range3, interpolate) {
     var d0 = domain[0], d1 = domain[1], r0 = range3[0], r1 = range3[1];
-    if (d1 < d0)
-      d0 = normalize(d1, d0), r0 = interpolate(r1, r0);
-    else
-      d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
+    if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);
+    else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
     return function(x2) {
       return r0(d0(x2));
     };
     var domain = unit, range3 = unit, interpolate = value_default, transform2, untransform, unknown, clamp3 = identity3, piecewise, output, input;
     function rescale() {
       var n3 = Math.min(domain.length, range3.length);
-      if (clamp3 !== identity3)
-        clamp3 = clamper(domain[0], domain[n3 - 1]);
+      if (clamp3 !== identity3) clamp3 = clamper(domain[0], domain[n3 - 1]);
       piecewise = n3 > 2 ? polymap : bimap;
       output = input = null;
       return scale;
     return Math.abs(x2 = Math.round(x2)) >= 1e21 ? x2.toLocaleString("en").replace(/,/g, "") : x2.toString(10);
   }
   function formatDecimalParts(x2, p2) {
-    if ((i3 = (x2 = p2 ? x2.toExponential(p2 - 1) : x2.toExponential()).indexOf("e")) < 0)
-      return null;
+    if ((i3 = (x2 = p2 ? x2.toExponential(p2 - 1) : x2.toExponential()).indexOf("e")) < 0) return null;
     var i3, coefficient = x2.slice(0, i3);
     return [
       coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
     return function(value, width) {
       var i3 = value.length, t2 = [], j2 = 0, g3 = grouping[0], length2 = 0;
       while (i3 > 0 && g3 > 0) {
-        if (length2 + g3 + 1 > width)
-          g3 = Math.max(1, width - length2);
+        if (length2 + g3 + 1 > width) g3 = Math.max(1, width - length2);
         t2.push(value.substring(i3 -= g3, i3 + g3));
-        if ((length2 += g3 + 1) > width)
-          break;
+        if ((length2 += g3 + 1) > width) break;
         g3 = grouping[j2 = (j2 + 1) % grouping.length];
       }
       return t2.reverse().join(thousands);
   // node_modules/d3-format/src/formatSpecifier.js
   var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
   function formatSpecifier(specifier) {
-    if (!(match = re.exec(specifier)))
-      throw new Error("invalid format: " + specifier);
+    if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
     var match;
     return new FormatSpecifier({
       fill: match[1],
 
   // node_modules/d3-format/src/formatTrim.js
   function formatTrim_default(s2) {
-    out:
-      for (var n3 = s2.length, i3 = 1, i0 = -1, i1; i3 < n3; ++i3) {
-        switch (s2[i3]) {
-          case ".":
-            i0 = i1 = i3;
-            break;
-          case "0":
-            if (i0 === 0)
-              i0 = i3;
-            i1 = i3;
-            break;
-          default:
-            if (!+s2[i3])
-              break out;
-            if (i0 > 0)
-              i0 = 0;
-            break;
-        }
+    out: for (var n3 = s2.length, i3 = 1, i0 = -1, i1; i3 < n3; ++i3) {
+      switch (s2[i3]) {
+        case ".":
+          i0 = i1 = i3;
+          break;
+        case "0":
+          if (i0 === 0) i0 = i3;
+          i1 = i3;
+          break;
+        default:
+          if (!+s2[i3]) break out;
+          if (i0 > 0) i0 = 0;
+          break;
       }
+    }
     return i0 > 0 ? s2.slice(0, i0) + s2.slice(i1 + 1) : s2;
   }
 
   var prefixExponent;
   function formatPrefixAuto_default(x2, p2) {
     var d2 = formatDecimalParts(x2, p2);
-    if (!d2)
-      return x2 + "";
+    if (!d2) return x2 + "";
     var coefficient = d2[0], exponent = d2[1], i3 = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1, n3 = coefficient.length;
     return i3 === n3 ? coefficient : i3 > n3 ? coefficient + new Array(i3 - n3 + 1).join("0") : i3 > 0 ? coefficient.slice(0, i3) + "." + coefficient.slice(i3) : "0." + new Array(1 - i3).join("0") + formatDecimalParts(x2, Math.max(0, p2 + i3 - 1))[0];
   }
   // node_modules/d3-format/src/formatRounded.js
   function formatRounded_default(x2, p2) {
     var d2 = formatDecimalParts(x2, p2);
-    if (!d2)
-      return x2 + "";
+    if (!d2) return x2 + "";
     var coefficient = d2[0], exponent = d2[1];
     return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1) : coefficient + new Array(exponent - coefficient.length + 2).join("0");
   }
     function newFormat(specifier) {
       specifier = formatSpecifier(specifier);
       var fill = specifier.fill, align = specifier.align, sign2 = specifier.sign, symbol = specifier.symbol, zero3 = specifier.zero, width = specifier.width, comma = specifier.comma, precision3 = specifier.precision, trim = specifier.trim, type2 = specifier.type;
-      if (type2 === "n")
-        comma = true, type2 = "g";
-      else if (!formatTypes_default[type2])
-        precision3 === void 0 && (precision3 = 12), trim = true, type2 = "g";
-      if (zero3 || fill === "0" && align === "=")
-        zero3 = true, fill = "0", align = "=";
+      if (type2 === "n") comma = true, type2 = "g";
+      else if (!formatTypes_default[type2]) precision3 === void 0 && (precision3 = 12), trim = true, type2 = "g";
+      if (zero3 || fill === "0" && align === "=") zero3 = true, fill = "0", align = "=";
       var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type2) ? "0" + type2.toLowerCase() : "", suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type2) ? percent : "";
       var formatType = formatTypes_default[type2], maybeSuffix = /[defgprs%]/.test(type2);
       precision3 = precision3 === void 0 ? 6 : /[gprs]/.test(type2) ? Math.max(1, Math.min(21, precision3)) : Math.max(0, Math.min(20, precision3));
           value = +value;
           var valueNegative = value < 0 || 1 / value < 0;
           value = isNaN(value) ? nan : formatType(Math.abs(value), precision3);
-          if (trim)
-            value = formatTrim_default(value);
-          if (valueNegative && +value === 0 && sign2 !== "+")
-            valueNegative = false;
+          if (trim) value = formatTrim_default(value);
+          if (valueNegative && +value === 0 && sign2 !== "+") valueNegative = false;
           valuePrefix = (valueNegative ? sign2 === "(" ? sign2 : minus : sign2 === "-" || sign2 === "(" ? "" : sign2) + valuePrefix;
           valueSuffix = (type2 === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign2 === "(" ? ")" : "");
           if (maybeSuffix) {
             }
           }
         }
-        if (comma && !zero3)
-          value = group(value, Infinity);
+        if (comma && !zero3) value = group(value, Infinity);
         var length2 = valuePrefix.length + value.length + valueSuffix.length, padding = length2 < width ? new Array(width - length2 + 1).join(fill) : "";
-        if (comma && zero3)
-          value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
+        if (comma && zero3) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
         switch (align) {
           case "<":
             value = valuePrefix + value + valueSuffix + padding;
     switch (specifier.type) {
       case "s": {
         var value = Math.max(Math.abs(start2), Math.abs(stop));
-        if (specifier.precision == null && !isNaN(precision3 = precisionPrefix_default(step, value)))
-          specifier.precision = precision3;
+        if (specifier.precision == null && !isNaN(precision3 = precisionPrefix_default(step, value))) specifier.precision = precision3;
         return formatPrefix(specifier, value);
       }
       case "":
       case "g":
       case "p":
       case "r": {
-        if (specifier.precision == null && !isNaN(precision3 = precisionRound_default(step, Math.max(Math.abs(start2), Math.abs(stop)))))
-          specifier.precision = precision3 - (specifier.type === "e");
+        if (specifier.precision == null && !isNaN(precision3 = precisionRound_default(step, Math.max(Math.abs(start2), Math.abs(stop))))) specifier.precision = precision3 - (specifier.type === "e");
         break;
       }
       case "f":
       case "%": {
-        if (specifier.precision == null && !isNaN(precision3 = precisionFixed_default(step)))
-          specifier.precision = precision3 - (specifier.type === "%") * 2;
+        if (specifier.precision == null && !isNaN(precision3 = precisionFixed_default(step))) specifier.precision = precision3 - (specifier.type === "%") * 2;
         break;
       }
     }
       return tickFormat(d2[0], d2[d2.length - 1], count == null ? 10 : count, specifier);
     };
     scale.nice = function(count) {
-      if (count == null)
-        count = 10;
+      if (count == null) count = 10;
       var d2 = domain();
       var i0 = 0;
       var i1 = d2.length - 1;
     function rescale() {
       var i3 = -1;
       domain = new Array(n3);
-      while (++i3 < n3)
-        domain[i3] = ((i3 + 1) * x12 - (i3 - n3) * x05) / (n3 + 1);
+      while (++i3 < n3) domain[i3] = ((i3 + 1) * x12 - (i3 - n3) * x05) / (n3 + 1);
       return scale;
     }
     scale.domain = function(_2) {
   function behaviorOperation(context) {
     var _operation;
     function keypress(d3_event) {
-      if (!context.map().withinEditableZoom())
-        return;
-      if (_operation.availableForKeypress && !_operation.availableForKeypress())
-        return;
+      if (!context.map().withinEditableZoom()) return;
+      if (_operation.availableForKeypress && !_operation.availableForKeypress()) return;
       d3_event.preventDefault();
       var disabled = _operation.disabled();
       if (disabled) {
         context.ui().flash.duration(4e3).iconName("#iD-operation-" + _operation.id).iconClass("operation disabled").label(_operation.tooltip())();
       } else {
         context.ui().flash.duration(2e3).iconName("#iD-operation-" + _operation.id).iconClass("operation").label(_operation.annotation() || _operation.title)();
-        if (_operation.point)
-          _operation.point(null);
+        if (_operation.point) _operation.point(null);
         _operation();
       }
     }
       context.keybinding().off(_operation.keys);
     };
     behavior.which = function(_2) {
-      if (!arguments.length)
-        return _operation;
+      if (!arguments.length) return _operation;
       _operation = _2;
       return behavior;
     };
     });
     function getAction(entityID) {
       var entity = context.entity(entityID);
-      if (entity.type !== "way" || new Set(entity.nodes).size <= 1)
-        return null;
+      if (entity.type !== "way" || new Set(entity.nodes).size <= 1) return null;
       if (!_extent) {
         _extent = entity.extent(context.graph());
       } else {
       return actionCircularize(entityID, context.projection);
     }
     var operation2 = function() {
-      if (!_actions.length)
-        return;
+      if (!_actions.length) return;
       var combinedAction = function(graph, t2) {
         _actions.forEach(function(action) {
           if (!action.disabled(graph)) {
       return _actions.length && selectedIDs.length === _actions.length;
     };
     operation2.disabled = function() {
-      if (!_actions.length)
-        return "";
+      if (!_actions.length) return "";
       var actionDisableds = _actions.map(function(action) {
         return action.disabled(context.graph());
       }).filter(Boolean);
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = _coords.filter(function(loc) {
       return code;
     }
     if (detected.os === "win") {
-      if (code === "\u2318\u21E7Z")
-        return "Ctrl+Y";
+      if (code === "\u2318\u21E7Z") return "Ctrl+Y";
     }
     var result = "", replacements = {
       "\u2318": "Ctrl",
     return result;
   };
   uiCmd.display = function(code) {
-    if (code.length !== 1)
-      return code;
+    if (code.length !== 1) return code;
     var detected = utilDetect();
     var mac = detected.os === "mac";
     var replacements = {
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = coords.filter(function(loc) {
       }
       function protectedMember(id2) {
         var entity = context.entity(id2);
-        if (entity.type !== "way")
-          return false;
+        if (entity.type !== "way") return false;
         var parents = context.graph().parentRelations(entity);
         for (var i3 = 0; i3 < parents.length; i3++) {
           var parent = parents[i3];
         _extent = _extent.extend(entity.extent(context.graph()));
       }
       if (entity.type === "way" && new Set(entity.nodes).size > 2) {
-        if (_type && _type !== "feature")
-          return null;
+        if (_type && _type !== "feature") return null;
         _type = "feature";
         return actionOrthogonalize(entityID, context.projection);
       } else if (geometry === "vertex") {
-        if (_type && _type !== "corner")
-          return null;
+        if (_type && _type !== "corner") return null;
         _type = "corner";
         var graph = context.graph();
         var parents = graph.parentWays(entity);
       return null;
     }
     var operation2 = function() {
-      if (!_actions.length)
-        return;
+      if (!_actions.length) return;
       var combinedAction = function(graph, t2) {
         _actions.forEach(function(action) {
           if (!action.disabled(graph)) {
       return _actions.length && selectedIDs.length === _actions.length;
     };
     operation2.disabled = function() {
-      if (!_actions.length)
-        return "";
+      if (!_actions.length) return "";
       var actionDisableds = _actions.map(function(action) {
         return action.disabled(context.graph());
       }).filter(Boolean);
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = _coords.filter(function(loc) {
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = coords.filter(function(loc) {
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = coords.filter(function(loc) {
       }
       var currMouse = context.map().mouse(d3_event);
       var currAngle = Math.atan2(currMouse[1] - _pivot[1], currMouse[0] - _pivot[0]);
-      if (typeof _prevAngle === "undefined")
-        _prevAngle = currAngle;
+      if (typeof _prevAngle === "undefined") _prevAngle = currAngle;
       var delta = currAngle - _prevAngle;
       fn(actionRotate(entityIDs, _pivot, delta, projection2));
       _prevTransform = currTransform;
       context.enter(modeSelect(context, entityIDs));
     }
     function cancel() {
-      if (_prevGraph)
-        context.pop();
+      if (_prevGraph) context.pop();
       context.enter(modeSelect(context, entityIDs));
     }
     function undone() {
         downEvent = d3_event;
       });
       select_default2(window).on(_pointerPrefix + "move.modeRotate", doRotate, true).on(_pointerPrefix + "up.modeRotate", function(d3_event) {
-        if (!downEvent)
-          return;
+        if (!downEvent) return;
         var mapNode = context.container().select(".main-map").node();
         var pointGetter = utilFastMouse(mapNode);
         var p1 = pointGetter(downEvent);
         var p2 = pointGetter(d3_event);
         var dist = geoVecLength(p1, p2);
-        if (dist <= _tolerancePx)
-          finish(d3_event);
+        if (dist <= _tolerancePx) finish(d3_event);
         downEvent = null;
       }, true);
       context.history().on("undone.modeRotate", undone);
       context.features().forceVisible([]);
     };
     mode.selectedIDs = function() {
-      if (!arguments.length)
-        return entityIDs;
+      if (!arguments.length) return entityIDs;
       return mode;
     };
     return mode;
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = coords.filter(function(loc) {
       _prevGraph = context.graph();
     }
     function startNudge(nudge) {
-      if (_nudgeInterval)
-        window.clearInterval(_nudgeInterval);
+      if (_nudgeInterval) window.clearInterval(_nudgeInterval);
       _nudgeInterval = window.setInterval(function() {
         context.map().pan(nudge);
         doMove(nudge);
     }
     function cancel() {
       if (baseGraph) {
-        while (context.graph() !== baseGraph)
-          context.pop();
+        while (context.graph() !== baseGraph) context.pop();
         context.enter(modeBrowse(context));
       } else {
-        if (_prevGraph)
-          context.pop();
+        if (_prevGraph) context.pop();
         context.enter(modeSelect(context, entityIDs));
       }
       stopNudge();
         downEvent = d3_event;
       });
       select_default2(window).on(_pointerPrefix + "move.modeMove", move, true).on(_pointerPrefix + "up.modeMove", function(d3_event) {
-        if (!downEvent)
-          return;
+        if (!downEvent) return;
         var mapNode = context.container().select(".main-map").node();
         var pointGetter = utilFastMouse(mapNode);
         var p1 = pointGetter(downEvent);
         var p2 = pointGetter(d3_event);
         var dist = geoVecLength(p1, p2);
-        if (dist <= _tolerancePx)
-          finish(d3_event);
+        if (dist <= _tolerancePx) finish(d3_event);
         downEvent = null;
       }, true);
       context.history().on("undone.modeMove", undone);
       context.features().forceVisible([]);
     };
     mode.selectedIDs = function() {
-      if (!arguments.length)
-        return entityIDs;
+      if (!arguments.length) return entityIDs;
       return mode;
     };
     return mode;
   // modules/behavior/paste.js
   function behaviorPaste(context) {
     function doPaste(d3_event) {
-      if (!context.map().withinEditableZoom())
-        return;
+      if (!context.map().withinEditableZoom()) return;
       d3_event.preventDefault();
       var baseGraph = context.graph();
       var mouse = context.map().mouse();
       var projection2 = context.projection;
       var viewport = geoExtent(projection2.clipExtent()).polygon();
-      if (!geoPointInPolygon(mouse, viewport))
-        return;
+      if (!geoPointInPolygon(mouse, viewport)) return;
       var oldIDs = context.copyIDs();
-      if (!oldIDs.length)
-        return;
+      if (!oldIDs.length) return;
       var extent = geoExtent();
       var oldGraph = context.copyGraph();
       var newIDs = [];
       };
     };
     function pointerdown(d3_event) {
-      if (_pointerId)
-        return;
+      if (_pointerId) return;
       _pointerId = d3_event.pointerId || "mouse";
       _targetNode = this;
       var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
       }
       d3_event.stopPropagation();
       function pointermove(d3_event2) {
-        if (_pointerId !== (d3_event2.pointerId || "mouse"))
-          return;
+        if (_pointerId !== (d3_event2.pointerId || "mouse")) return;
         var p2 = pointerLocGetter(d3_event2);
         if (!started) {
           var dist = geoVecLength(startOrigin, p2);
           var tolerance = d3_event2.pointerType === "pen" ? _penTolerancePx : _tolerancePx;
-          if (dist < tolerance)
-            return;
+          if (dist < tolerance) return;
           started = true;
           dispatch14.call("start", this, d3_event2, _targetEntity);
         } else {
         }
       }
       function pointerup(d3_event2) {
-        if (_pointerId !== (d3_event2.pointerId || "mouse"))
-          return;
+        if (_pointerId !== (d3_event2.pointerId || "mouse")) return;
         _pointerId = null;
         if (started) {
           dispatch14.call("end", this, d3_event2, _targetEntity);
       selection2.on(_pointerPrefix + "down.drag" + _selector, null);
     };
     behavior.selector = function(_2) {
-      if (!arguments.length)
-        return _selector;
+      if (!arguments.length) return _selector;
       _selector = _2;
       return behavior;
     };
     behavior.origin = function(_2) {
-      if (!arguments.length)
-        return _origin;
+      if (!arguments.length) return _origin;
       _origin = _2;
       return behavior;
     };
       return behavior;
     };
     behavior.targetNode = function(_2) {
-      if (!arguments.length)
-        return _targetNode;
+      if (!arguments.length) return _targetNode;
       _targetNode = _2;
       return behavior;
     };
     behavior.targetEntity = function(_2) {
-      if (!arguments.length)
-        return _targetEntity;
+      if (!arguments.length) return _targetEntity;
       _targetEntity = _2;
       return behavior;
     };
     behavior.surface = function(_2) {
-      if (!arguments.length)
-        return _surface;
+      if (!arguments.length) return _surface;
       _surface = _2;
       return behavior;
     };
     var _startLoc;
     var _lastLoc;
     function startNudge(d3_event, entity, nudge) {
-      if (_nudgeInterval)
-        window.clearInterval(_nudgeInterval);
+      if (_nudgeInterval) window.clearInterval(_nudgeInterval);
       _nudgeInterval = window.setInterval(function() {
         context.map().pan(nudge);
         doMove(d3_event, entity, nudge);
       return _t("operations.connect.annotation.from_" + nodeGeometry + ".to_" + targetGeometry);
     }
     function shouldSnapToNode(target) {
-      if (!_activeEntity)
-        return false;
+      if (!_activeEntity) return false;
       return _activeEntity.geometry(context.graph()) !== "vertex" || (target.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(target, context.graph()));
     }
     function origin(entity) {
         var activeIndex = null;
         var relations = graph.parentRelations(parent);
         for (j2 = 0; j2 < relations.length; j2++) {
-          if (!relations[j2].isMultipolygon())
-            continue;
+          if (!relations[j2].isMultipolygon()) continue;
           var rings = osmJoinWays(relations[j2].members, graph);
           for (k2 = 0; k2 < rings.length; k2++) {
             nodes = rings[k2].nodes;
             });
           }
           for (k2 = 0; k2 < rings.length; k2++) {
-            if (k2 === activeIndex)
-              continue;
+            if (k2 === activeIndex) continue;
             if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k2].nodes, entity.id)) {
               return "multipolygonRing";
             }
       }
       return false;
     }
-    function move(d3_event, entity, point2) {
-      if (_isCancelled)
-        return;
+    function move(d3_event, entity, point) {
+      if (_isCancelled) return;
       d3_event.stopPropagation();
       context.surface().classed("nope-disabled", d3_event.altKey);
-      _lastLoc = context.projection.invert(point2);
+      _lastLoc = context.projection.invert(point);
       doMove(d3_event, entity);
-      var nudge = geoViewportEdge(point2, context.map().dimensions());
+      var nudge = geoViewportEdge(point, context.map().dimensions());
       if (nudge) {
         startNudge(d3_event, entity, nudge);
       } else {
       }
     }
     function end(d3_event, entity) {
-      if (_isCancelled)
-        return;
+      if (_isCancelled) return;
       var wasPoint = entity.geometry(context.graph()) === "point";
       var d2 = datum2(d3_event);
       var nope = d2 && d2.properties && d2.properties.nope || context.surface().classed("nope");
     function _actionBounceBack(nodeID, toLoc) {
       var moveNode = actionMoveNode(nodeID, toLoc);
       var action = function(graph, t2) {
-        if (t2 === 1)
-          context.pop();
+        if (t2 === 1) context.pop();
         return moveNode(graph, t2);
       };
       action.transitionable = true;
       stopNudge();
     };
     mode.selectedIDs = function() {
-      if (!arguments.length)
-        return _activeEntity ? [_activeEntity.id] : [];
+      if (!arguments.length) return _activeEntity ? [_activeEntity.id] : [];
       return mode;
     };
     mode.activeID = function() {
-      if (!arguments.length)
-        return _activeEntity && _activeEntity.id;
+      if (!arguments.length) return _activeEntity && _activeEntity.id;
       return mode;
     };
     mode.restoreSelectedIDs = function(_2) {
-      if (!arguments.length)
-        return _restoreSelectedIDs;
+      if (!arguments.length) return _restoreSelectedIDs;
       _restoreSelectedIDs = _2;
       return mode;
     };
     return mode;
   }
 
-  // modules/services/keepRight.js
-  var import_rbush = __toESM(require_rbush_min());
+  // node_modules/quickselect/index.js
+  function quickselect2(arr, k2, left, right, compare2) {
+    quickselectStep(arr, k2, left || 0, right || arr.length - 1, compare2 || defaultCompare);
+  }
+  function quickselectStep(arr, k2, left, right, compare2) {
+    while (right > left) {
+      if (right - left > 600) {
+        var n3 = right - left + 1;
+        var m2 = k2 - left + 1;
+        var z2 = Math.log(n3);
+        var s2 = 0.5 * Math.exp(2 * z2 / 3);
+        var sd = 0.5 * Math.sqrt(z2 * s2 * (n3 - s2) / n3) * (m2 - n3 / 2 < 0 ? -1 : 1);
+        var newLeft = Math.max(left, Math.floor(k2 - m2 * s2 / n3 + sd));
+        var newRight = Math.min(right, Math.floor(k2 + (n3 - m2) * s2 / n3 + sd));
+        quickselectStep(arr, k2, newLeft, newRight, compare2);
+      }
+      var t2 = arr[k2];
+      var i3 = left;
+      var j2 = right;
+      swap2(arr, left, k2);
+      if (compare2(arr[right], t2) > 0) swap2(arr, left, right);
+      while (i3 < j2) {
+        swap2(arr, i3, j2);
+        i3++;
+        j2--;
+        while (compare2(arr[i3], t2) < 0) i3++;
+        while (compare2(arr[j2], t2) > 0) j2--;
+      }
+      if (compare2(arr[left], t2) === 0) swap2(arr, left, j2);
+      else {
+        j2++;
+        swap2(arr, j2, right);
+      }
+      if (j2 <= k2) left = j2 + 1;
+      if (k2 <= j2) right = j2 - 1;
+    }
+  }
+  function swap2(arr, i3, j2) {
+    var tmp = arr[i3];
+    arr[i3] = arr[j2];
+    arr[j2] = tmp;
+  }
+  function defaultCompare(a2, b2) {
+    return a2 < b2 ? -1 : a2 > b2 ? 1 : 0;
+  }
+
+  // node_modules/rbush/index.js
+  var RBush = class {
+    constructor(maxEntries = 9) {
+      this._maxEntries = Math.max(4, maxEntries);
+      this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
+      this.clear();
+    }
+    all() {
+      return this._all(this.data, []);
+    }
+    search(bbox2) {
+      let node = this.data;
+      const result = [];
+      if (!intersects(bbox2, node)) return result;
+      const toBBox = this.toBBox;
+      const nodesToSearch = [];
+      while (node) {
+        for (let i3 = 0; i3 < node.children.length; i3++) {
+          const child = node.children[i3];
+          const childBBox = node.leaf ? toBBox(child) : child;
+          if (intersects(bbox2, childBBox)) {
+            if (node.leaf) result.push(child);
+            else if (contains(bbox2, childBBox)) this._all(child, result);
+            else nodesToSearch.push(child);
+          }
+        }
+        node = nodesToSearch.pop();
+      }
+      return result;
+    }
+    collides(bbox2) {
+      let node = this.data;
+      if (!intersects(bbox2, node)) return false;
+      const nodesToSearch = [];
+      while (node) {
+        for (let i3 = 0; i3 < node.children.length; i3++) {
+          const child = node.children[i3];
+          const childBBox = node.leaf ? this.toBBox(child) : child;
+          if (intersects(bbox2, childBBox)) {
+            if (node.leaf || contains(bbox2, childBBox)) return true;
+            nodesToSearch.push(child);
+          }
+        }
+        node = nodesToSearch.pop();
+      }
+      return false;
+    }
+    load(data) {
+      if (!(data && data.length)) return this;
+      if (data.length < this._minEntries) {
+        for (let i3 = 0; i3 < data.length; i3++) {
+          this.insert(data[i3]);
+        }
+        return this;
+      }
+      let node = this._build(data.slice(), 0, data.length - 1, 0);
+      if (!this.data.children.length) {
+        this.data = node;
+      } else if (this.data.height === node.height) {
+        this._splitRoot(this.data, node);
+      } else {
+        if (this.data.height < node.height) {
+          const tmpNode = this.data;
+          this.data = node;
+          node = tmpNode;
+        }
+        this._insert(node, this.data.height - node.height - 1, true);
+      }
+      return this;
+    }
+    insert(item) {
+      if (item) this._insert(item, this.data.height - 1);
+      return this;
+    }
+    clear() {
+      this.data = createNode([]);
+      return this;
+    }
+    remove(item, equalsFn) {
+      if (!item) return this;
+      let node = this.data;
+      const bbox2 = this.toBBox(item);
+      const path = [];
+      const indexes = [];
+      let i3, parent, goingUp;
+      while (node || path.length) {
+        if (!node) {
+          node = path.pop();
+          parent = path[path.length - 1];
+          i3 = indexes.pop();
+          goingUp = true;
+        }
+        if (node.leaf) {
+          const index = findItem(item, node.children, equalsFn);
+          if (index !== -1) {
+            node.children.splice(index, 1);
+            path.push(node);
+            this._condense(path);
+            return this;
+          }
+        }
+        if (!goingUp && !node.leaf && contains(node, bbox2)) {
+          path.push(node);
+          indexes.push(i3);
+          i3 = 0;
+          parent = node;
+          node = node.children[0];
+        } else if (parent) {
+          i3++;
+          node = parent.children[i3];
+          goingUp = false;
+        } else node = null;
+      }
+      return this;
+    }
+    toBBox(item) {
+      return item;
+    }
+    compareMinX(a2, b2) {
+      return a2.minX - b2.minX;
+    }
+    compareMinY(a2, b2) {
+      return a2.minY - b2.minY;
+    }
+    toJSON() {
+      return this.data;
+    }
+    fromJSON(data) {
+      this.data = data;
+      return this;
+    }
+    _all(node, result) {
+      const nodesToSearch = [];
+      while (node) {
+        if (node.leaf) result.push(...node.children);
+        else nodesToSearch.push(...node.children);
+        node = nodesToSearch.pop();
+      }
+      return result;
+    }
+    _build(items, left, right, height) {
+      const N2 = right - left + 1;
+      let M2 = this._maxEntries;
+      let node;
+      if (N2 <= M2) {
+        node = createNode(items.slice(left, right + 1));
+        calcBBox(node, this.toBBox);
+        return node;
+      }
+      if (!height) {
+        height = Math.ceil(Math.log(N2) / Math.log(M2));
+        M2 = Math.ceil(N2 / Math.pow(M2, height - 1));
+      }
+      node = createNode([]);
+      node.leaf = false;
+      node.height = height;
+      const N22 = Math.ceil(N2 / M2);
+      const N1 = N22 * Math.ceil(Math.sqrt(M2));
+      multiSelect(items, left, right, N1, this.compareMinX);
+      for (let i3 = left; i3 <= right; i3 += N1) {
+        const right2 = Math.min(i3 + N1 - 1, right);
+        multiSelect(items, i3, right2, N22, this.compareMinY);
+        for (let j2 = i3; j2 <= right2; j2 += N22) {
+          const right3 = Math.min(j2 + N22 - 1, right2);
+          node.children.push(this._build(items, j2, right3, height - 1));
+        }
+      }
+      calcBBox(node, this.toBBox);
+      return node;
+    }
+    _chooseSubtree(bbox2, node, level, path) {
+      while (true) {
+        path.push(node);
+        if (node.leaf || path.length - 1 === level) break;
+        let minArea = Infinity;
+        let minEnlargement = Infinity;
+        let targetNode;
+        for (let i3 = 0; i3 < node.children.length; i3++) {
+          const child = node.children[i3];
+          const area = bboxArea(child);
+          const enlargement = enlargedArea(bbox2, child) - area;
+          if (enlargement < minEnlargement) {
+            minEnlargement = enlargement;
+            minArea = area < minArea ? area : minArea;
+            targetNode = child;
+          } else if (enlargement === minEnlargement) {
+            if (area < minArea) {
+              minArea = area;
+              targetNode = child;
+            }
+          }
+        }
+        node = targetNode || node.children[0];
+      }
+      return node;
+    }
+    _insert(item, level, isNode) {
+      const bbox2 = isNode ? item : this.toBBox(item);
+      const insertPath = [];
+      const node = this._chooseSubtree(bbox2, this.data, level, insertPath);
+      node.children.push(item);
+      extend2(node, bbox2);
+      while (level >= 0) {
+        if (insertPath[level].children.length > this._maxEntries) {
+          this._split(insertPath, level);
+          level--;
+        } else break;
+      }
+      this._adjustParentBBoxes(bbox2, insertPath, level);
+    }
+    // split overflowed node into two
+    _split(insertPath, level) {
+      const node = insertPath[level];
+      const M2 = node.children.length;
+      const m2 = this._minEntries;
+      this._chooseSplitAxis(node, m2, M2);
+      const splitIndex = this._chooseSplitIndex(node, m2, M2);
+      const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
+      newNode.height = node.height;
+      newNode.leaf = node.leaf;
+      calcBBox(node, this.toBBox);
+      calcBBox(newNode, this.toBBox);
+      if (level) insertPath[level - 1].children.push(newNode);
+      else this._splitRoot(node, newNode);
+    }
+    _splitRoot(node, newNode) {
+      this.data = createNode([node, newNode]);
+      this.data.height = node.height + 1;
+      this.data.leaf = false;
+      calcBBox(this.data, this.toBBox);
+    }
+    _chooseSplitIndex(node, m2, M2) {
+      let index;
+      let minOverlap = Infinity;
+      let minArea = Infinity;
+      for (let i3 = m2; i3 <= M2 - m2; i3++) {
+        const bbox1 = distBBox(node, 0, i3, this.toBBox);
+        const bbox2 = distBBox(node, i3, M2, this.toBBox);
+        const overlap = intersectionArea(bbox1, bbox2);
+        const area = bboxArea(bbox1) + bboxArea(bbox2);
+        if (overlap < minOverlap) {
+          minOverlap = overlap;
+          index = i3;
+          minArea = area < minArea ? area : minArea;
+        } else if (overlap === minOverlap) {
+          if (area < minArea) {
+            minArea = area;
+            index = i3;
+          }
+        }
+      }
+      return index || M2 - m2;
+    }
+    // sorts node children by the best axis for split
+    _chooseSplitAxis(node, m2, M2) {
+      const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
+      const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
+      const xMargin = this._allDistMargin(node, m2, M2, compareMinX);
+      const yMargin = this._allDistMargin(node, m2, M2, compareMinY);
+      if (xMargin < yMargin) node.children.sort(compareMinX);
+    }
+    // total margin of all possible split distributions where each node is at least m full
+    _allDistMargin(node, m2, M2, compare2) {
+      node.children.sort(compare2);
+      const toBBox = this.toBBox;
+      const leftBBox = distBBox(node, 0, m2, toBBox);
+      const rightBBox = distBBox(node, M2 - m2, M2, toBBox);
+      let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
+      for (let i3 = m2; i3 < M2 - m2; i3++) {
+        const child = node.children[i3];
+        extend2(leftBBox, node.leaf ? toBBox(child) : child);
+        margin += bboxMargin(leftBBox);
+      }
+      for (let i3 = M2 - m2 - 1; i3 >= m2; i3--) {
+        const child = node.children[i3];
+        extend2(rightBBox, node.leaf ? toBBox(child) : child);
+        margin += bboxMargin(rightBBox);
+      }
+      return margin;
+    }
+    _adjustParentBBoxes(bbox2, path, level) {
+      for (let i3 = level; i3 >= 0; i3--) {
+        extend2(path[i3], bbox2);
+      }
+    }
+    _condense(path) {
+      for (let i3 = path.length - 1, siblings; i3 >= 0; i3--) {
+        if (path[i3].children.length === 0) {
+          if (i3 > 0) {
+            siblings = path[i3 - 1].children;
+            siblings.splice(siblings.indexOf(path[i3]), 1);
+          } else this.clear();
+        } else calcBBox(path[i3], this.toBBox);
+      }
+    }
+  };
+  function findItem(item, items, equalsFn) {
+    if (!equalsFn) return items.indexOf(item);
+    for (let i3 = 0; i3 < items.length; i3++) {
+      if (equalsFn(item, items[i3])) return i3;
+    }
+    return -1;
+  }
+  function calcBBox(node, toBBox) {
+    distBBox(node, 0, node.children.length, toBBox, node);
+  }
+  function distBBox(node, k2, p2, toBBox, destNode) {
+    if (!destNode) destNode = createNode(null);
+    destNode.minX = Infinity;
+    destNode.minY = Infinity;
+    destNode.maxX = -Infinity;
+    destNode.maxY = -Infinity;
+    for (let i3 = k2; i3 < p2; i3++) {
+      const child = node.children[i3];
+      extend2(destNode, node.leaf ? toBBox(child) : child);
+    }
+    return destNode;
+  }
+  function extend2(a2, b2) {
+    a2.minX = Math.min(a2.minX, b2.minX);
+    a2.minY = Math.min(a2.minY, b2.minY);
+    a2.maxX = Math.max(a2.maxX, b2.maxX);
+    a2.maxY = Math.max(a2.maxY, b2.maxY);
+    return a2;
+  }
+  function compareNodeMinX(a2, b2) {
+    return a2.minX - b2.minX;
+  }
+  function compareNodeMinY(a2, b2) {
+    return a2.minY - b2.minY;
+  }
+  function bboxArea(a2) {
+    return (a2.maxX - a2.minX) * (a2.maxY - a2.minY);
+  }
+  function bboxMargin(a2) {
+    return a2.maxX - a2.minX + (a2.maxY - a2.minY);
+  }
+  function enlargedArea(a2, b2) {
+    return (Math.max(b2.maxX, a2.maxX) - Math.min(b2.minX, a2.minX)) * (Math.max(b2.maxY, a2.maxY) - Math.min(b2.minY, a2.minY));
+  }
+  function intersectionArea(a2, b2) {
+    const minX = Math.max(a2.minX, b2.minX);
+    const minY = Math.max(a2.minY, b2.minY);
+    const maxX = Math.min(a2.maxX, b2.maxX);
+    const maxY = Math.min(a2.maxY, b2.maxY);
+    return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
+  }
+  function contains(a2, b2) {
+    return a2.minX <= b2.minX && a2.minY <= b2.minY && b2.maxX <= a2.maxX && b2.maxY <= a2.maxY;
+  }
+  function intersects(a2, b2) {
+    return b2.minX <= a2.maxX && b2.minY <= a2.maxY && b2.maxX >= a2.minX && b2.maxY >= a2.minY;
+  }
+  function createNode(children2) {
+    return {
+      children: children2,
+      height: 1,
+      leaf: true,
+      minX: Infinity,
+      minY: Infinity,
+      maxX: -Infinity,
+      maxY: -Infinity
+    };
+  }
+  function multiSelect(arr, left, right, n3, compare2) {
+    const stack = [left, right];
+    while (stack.length) {
+      right = stack.pop();
+      left = stack.pop();
+      if (right - left <= n3) continue;
+      const mid = left + Math.ceil((right - left) / n3 / 2) * n3;
+      quickselect2(arr, mid, left, right, compare2);
+      stack.push(left, mid, mid, right);
+    }
+  }
 
   // node_modules/d3-fetch/src/text.js
   function responseText(response) {
-    if (!response.ok)
-      throw new Error(response.status + " " + response.statusText);
+    if (!response.ok) throw new Error(response.status + " " + response.statusText);
     return response.text();
   }
   function text_default3(input, init2) {
 
   // node_modules/d3-fetch/src/json.js
   function responseJson(response) {
-    if (!response.ok)
-      throw new Error(response.status + " " + response.statusText);
-    if (response.status === 204 || response.status === 205)
-      return;
+    if (!response.ok) throw new Error(response.status + " " + response.statusText);
+    if (response.status === 204 || response.status === 205) return;
     return response.json();
   }
   function json_default(input, init2) {
     }
   }
   function tokenReplacements(d2) {
-    if (!(d2 instanceof QAItem))
-      return;
+    if (!(d2 instanceof QAItem)) return;
     const replacements = {};
     const issueTemplate = _krData.errorTypes[d2.whichType];
     if (!issueTemplate) {
       console.log("  ", d2.description);
       return;
     }
-    if (!issueTemplate.regex)
-      return;
+    if (!issueTemplate.regex) return;
     const errorRegex = new RegExp(issueTemplate.regex, "i");
     const errorMatch = errorRegex.exec(d2.description);
     if (!errorMatch) {
       capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare2]);
     }
     switch (idType) {
+      // link a string like "this node"
       case "this":
-        capture = linkErrorObject2(capture);
+        capture = linkErrorObject(capture);
         break;
       case "url":
         capture = linkURL(capture);
         break;
+      // link an entity ID
       case "n":
       case "w":
       case "r":
-        capture = linkEntity2(idType + capture);
+        capture = linkEntity(idType + capture);
         break;
+      // some errors have more complex ID lists/variance
       case "20":
         capture = parse20(capture);
         break;
         break;
     }
     return capture;
-    function linkErrorObject2(d2) {
+    function linkErrorObject(d2) {
       return { html: '<a class="error_object_link">'.concat(d2, "</a>") };
     }
-    function linkEntity2(d2) {
+    function linkEntity(d2) {
       return { html: '<a class="error_entity_link">'.concat(d2, "</a>") };
     }
     function linkURL(d2) {
       let newList = [];
       const items = capture2.split(", ");
       items.forEach((item) => {
-        let id2 = linkEntity2("n" + item.slice(1));
+        let id2 = linkEntity("n" + item.slice(1));
         newList.push(id2);
       });
       return newList.join(", ");
         const match = item.match(/\#(\d+)\((.+)\)?/);
         if (match !== null && match.length > 2) {
           newList.push(
-            linkEntity2("w" + match[1]) + " " + _t("QA.keepRight.errorTypes.231.layer", { layer: match[2] })
+            linkEntity("w" + match[1]) + " " + _t("QA.keepRight.errorTypes.231.layer", { layer: match[2] })
           );
         }
       });
         const role = '"'.concat(item[0], '"');
         const idType2 = item[1].slice(0, 1);
         let id2 = item[2].slice(1);
-        id2 = linkEntity2(idType2 + id2);
+        id2 = linkEntity(idType2 + id2);
         newList.push("".concat(role, " ").concat(item[1], " ").concat(id2));
       });
       return newList.join(", ");
     }
     function parse370(capture2) {
-      if (!capture2)
-        return "";
+      if (!capture2) return "";
       const match = capture2.match(/\(including the name (\'.+\')\)/);
       if (match && match.length) {
         return _t("QA.keepRight.errorTypes.370.including_the_name", { name: match[1] });
       let newList = [];
       const items = capture2.split(",");
       items.forEach((item) => {
-        const id2 = linkEntity2("n" + item.slice(1));
+        const id2 = linkEntity("n" + item.slice(1));
         newList.push(id2);
       });
       return newList.join(", ");
         inflightTile: {},
         inflightPost: {},
         closed: {},
-        rtree: new import_rbush.default()
+        rtree: new RBush()
       };
     },
     // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
       const tiles = tiler.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection2);
       abortUnwantedRequests(_cache, tiles);
       tiles.forEach((tile) => {
-        if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id])
-          return;
+        if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
         const [left, top, right, bottom] = tile.extent.rectangle();
         const params = Object.assign({}, options2, { left, bottom, right, top });
         const url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
             newState: void 0
           }));
         }
-        if (callback)
-          callback(null, d2);
+        if (callback) callback(null, d2);
       });
     },
     // Get all cached QAItems covering the viewport
     },
     // Replace a single QAItem in the cache
     replaceItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
+      if (!(item instanceof QAItem) || !item.id) return;
       _cache.data[item.id] = item;
       updateRtree(encodeIssueRtree(item), true);
       return item;
     },
     // Remove a single QAItem from the cache
     removeItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
+      if (!(item instanceof QAItem) || !item.id) return;
       delete _cache.data[item.id];
       updateRtree(encodeIssueRtree(item), false);
     },
     }
   };
 
-  // modules/services/improveOSM.js
-  var import_rbush2 = __toESM(require_rbush_min());
-  var tiler2 = utilTiler();
-  var dispatch3 = dispatch_default("loaded");
-  var _tileZoom2 = 14;
-  var _impOsmUrls = {
-    ow: "https://grab.community.improve-osm.org/directionOfFlowService",
-    mr: "https://grab.community.improve-osm.org/missingGeoService",
-    tr: "https://grab.community.improve-osm.org/turnRestrictionService"
-  };
-  var _impOsmData = { icons: {} };
-  var _cache2;
-  function abortRequest2(i3) {
-    Object.values(i3).forEach((controller) => {
-      if (controller) {
-        controller.abort();
-      }
-    });
-  }
-  function abortUnwantedRequests2(cache, tiles) {
-    Object.keys(cache.inflightTile).forEach((k2) => {
-      const wanted = tiles.find((tile) => k2 === tile.id);
-      if (!wanted) {
-        abortRequest2(cache.inflightTile[k2]);
-        delete cache.inflightTile[k2];
-      }
-    });
-  }
-  function encodeIssueRtree2(d2) {
-    return { minX: d2.loc[0], minY: d2.loc[1], maxX: d2.loc[0], maxY: d2.loc[1], data: d2 };
-  }
-  function updateRtree2(item, replace) {
-    _cache2.rtree.remove(item, (a2, b2) => a2.data.id === b2.data.id);
-    if (replace) {
-      _cache2.rtree.insert(item);
-    }
-  }
-  function linkErrorObject(d2) {
-    return { html: '<a class="error_object_link">'.concat(d2, "</a>") };
-  }
-  function linkEntity(d2) {
-    return { html: '<a class="error_entity_link">'.concat(d2, "</a>") };
-  }
-  function pointAverage(points) {
-    if (points.length) {
-      const sum = points.reduce(
-        (acc, point2) => geoVecAdd(acc, [point2.lon, point2.lat]),
-        [0, 0]
-      );
-      return geoVecScale(sum, 1 / points.length);
-    } else {
-      return [0, 0];
-    }
-  }
-  function relativeBearing(p1, p2) {
-    let angle2 = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
-    if (angle2 < 0) {
-      angle2 += 2 * Math.PI;
-    }
-    return angle2 * 180 / Math.PI;
-  }
-  function cardinalDirection(bearing) {
-    const dir = 45 * Math.round(bearing / 45);
-    const compass = {
-      0: "north",
-      45: "northeast",
-      90: "east",
-      135: "southeast",
-      180: "south",
-      225: "southwest",
-      270: "west",
-      315: "northwest",
-      360: "north"
-    };
-    return _t("QA.improveOSM.directions.".concat(compass[dir]));
-  }
-  function preventCoincident(loc, bumpUp) {
-    let coincident = false;
-    do {
-      let delta = coincident ? [1e-5, 0] : bumpUp ? [0, 1e-5] : [0, 0];
-      loc = geoVecAdd(loc, delta);
-      let bbox2 = geoExtent(loc).bbox();
-      coincident = _cache2.rtree.search(bbox2).length;
-    } while (coincident);
-    return loc;
-  }
-  var improveOSM_default = {
-    title: "improveOSM",
-    init() {
-      _mainFileFetcher.get("qa_data").then((d2) => _impOsmData = d2.improveOSM);
-      if (!_cache2) {
-        this.reset();
-      }
-      this.event = utilRebind(this, dispatch3, "on");
-    },
-    reset() {
-      if (_cache2) {
-        Object.values(_cache2.inflightTile).forEach(abortRequest2);
-      }
-      _cache2 = {
-        data: {},
-        loadedTile: {},
-        inflightTile: {},
-        inflightPost: {},
-        closed: {},
-        rtree: new import_rbush2.default()
-      };
-    },
-    loadIssues(projection2) {
-      const options2 = {
-        client: "iD",
-        status: "OPEN",
-        zoom: "19"
-        // Use a high zoom so that clusters aren't returned
-      };
-      const tiles = tiler2.zoomExtent([_tileZoom2, _tileZoom2]).getTiles(projection2);
-      abortUnwantedRequests2(_cache2, tiles);
-      tiles.forEach((tile) => {
-        if (_cache2.loadedTile[tile.id] || _cache2.inflightTile[tile.id])
-          return;
-        const [east, north, west, south] = tile.extent.rectangle();
-        const params = Object.assign({}, options2, { east, south, west, north });
-        const requests = {};
-        Object.keys(_impOsmUrls).forEach((k2) => {
-          const kParams = Object.assign(
-            {},
-            params,
-            k2 === "mr" ? { type: "PARKING,ROAD,BOTH,PATH" } : { confidenceLevel: "C1" }
-          );
-          const url = "".concat(_impOsmUrls[k2], "/search?") + utilQsString(kParams);
-          const controller = new AbortController();
-          requests[k2] = controller;
-          json_default(url, { signal: controller.signal }).then((data) => {
-            delete _cache2.inflightTile[tile.id][k2];
-            if (!Object.keys(_cache2.inflightTile[tile.id]).length) {
-              delete _cache2.inflightTile[tile.id];
-              _cache2.loadedTile[tile.id] = true;
-            }
-            if (data.roadSegments) {
-              data.roadSegments.forEach((feature3) => {
-                const { points, wayId, fromNodeId, toNodeId } = feature3;
-                const itemId = "".concat(wayId).concat(fromNodeId).concat(toNodeId);
-                let mid = points.length / 2;
-                let loc;
-                if (mid % 1 === 0) {
-                  loc = pointAverage([points[mid - 1], points[mid]]);
-                } else {
-                  mid = points[Math.floor(mid)];
-                  loc = [mid.lon, mid.lat];
-                }
-                loc = preventCoincident(loc, false);
-                let d2 = new QAItem(loc, this, k2, itemId, {
-                  issueKey: k2,
-                  // used as a category
-                  identifier: {
-                    // used to post changes
-                    wayId,
-                    fromNodeId,
-                    toNodeId
-                  },
-                  objectId: wayId,
-                  objectType: "way"
-                });
-                d2.replacements = {
-                  percentage: feature3.percentOfTrips,
-                  num_trips: feature3.numberOfTrips,
-                  highway: linkErrorObject(_t("QA.keepRight.error_parts.highway")),
-                  from_node: linkEntity("n" + feature3.fromNodeId),
-                  to_node: linkEntity("n" + feature3.toNodeId)
-                };
-                _cache2.data[d2.id] = d2;
-                _cache2.rtree.insert(encodeIssueRtree2(d2));
-              });
-            }
-            if (data.tiles) {
-              data.tiles.forEach((feature3) => {
-                const { type: type2, x: x2, y: y2, numberOfTrips } = feature3;
-                const geoType = type2.toLowerCase();
-                const itemId = "".concat(geoType).concat(x2).concat(y2).concat(numberOfTrips);
-                let loc = pointAverage(feature3.points);
-                loc = preventCoincident(loc, false);
-                let d2 = new QAItem(loc, this, "".concat(k2, "-").concat(geoType), itemId, {
-                  issueKey: k2,
-                  identifier: { x: x2, y: y2 }
-                });
-                d2.replacements = {
-                  num_trips: numberOfTrips,
-                  geometry_type: _t("QA.improveOSM.geometry_types.".concat(geoType))
-                };
-                if (numberOfTrips === -1) {
-                  d2.desc = _t("QA.improveOSM.error_types.mr.description_alt", d2.replacements);
-                }
-                _cache2.data[d2.id] = d2;
-                _cache2.rtree.insert(encodeIssueRtree2(d2));
-              });
-            }
-            if (data.entities) {
-              data.entities.forEach((feature3) => {
-                const { point: point2, id: id2, segments, numberOfPasses, turnType } = feature3;
-                const itemId = "".concat(id2.replace(/[,:+#]/g, "_"));
-                const loc = preventCoincident([point2.lon, point2.lat], true);
-                const ids = id2.split(",");
-                const from_way = ids[0];
-                const via_node = ids[3];
-                const to_way = ids[2].split(":")[1];
-                let d2 = new QAItem(loc, this, k2, itemId, {
-                  issueKey: k2,
-                  identifier: id2,
-                  objectId: via_node,
-                  objectType: "node"
-                });
-                const [p1, p2] = segments[0].points;
-                const dir_of_travel = cardinalDirection(relativeBearing(p1, p2));
-                d2.replacements = {
-                  num_passed: numberOfPasses,
-                  num_trips: segments[0].numberOfTrips,
-                  turn_restriction: turnType.toLowerCase(),
-                  from_way: linkEntity("w" + from_way),
-                  to_way: linkEntity("w" + to_way),
-                  travel_direction: dir_of_travel,
-                  junction: linkErrorObject(_t("QA.keepRight.error_parts.this_node"))
-                };
-                _cache2.data[d2.id] = d2;
-                _cache2.rtree.insert(encodeIssueRtree2(d2));
-                dispatch3.call("loaded");
-              });
-            }
-          }).catch(() => {
-            delete _cache2.inflightTile[tile.id][k2];
-            if (!Object.keys(_cache2.inflightTile[tile.id]).length) {
-              delete _cache2.inflightTile[tile.id];
-              _cache2.loadedTile[tile.id] = true;
-            }
-          });
-        });
-        _cache2.inflightTile[tile.id] = requests;
-      });
-    },
-    getComments(item) {
-      if (item.comments) {
-        return Promise.resolve(item);
-      }
-      const key = item.issueKey;
-      let qParams = {};
-      if (key === "ow") {
-        qParams = item.identifier;
-      } else if (key === "mr") {
-        qParams.tileX = item.identifier.x;
-        qParams.tileY = item.identifier.y;
-      } else if (key === "tr") {
-        qParams.targetId = item.identifier;
-      }
-      const url = "".concat(_impOsmUrls[key], "/retrieveComments?") + utilQsString(qParams);
-      const cacheComments = (data) => {
-        item.comments = data.comments ? data.comments.reverse() : [];
-        this.replaceItem(item);
-      };
-      return json_default(url).then(cacheComments).then(() => item);
-    },
-    postUpdate(d2, callback) {
-      if (!osm_default.authenticated()) {
-        return callback({ message: "Not Authenticated", status: -3 }, d2);
-      }
-      if (_cache2.inflightPost[d2.id]) {
-        return callback({ message: "Error update already inflight", status: -2 }, d2);
-      }
-      osm_default.userDetails(sendPayload.bind(this));
-      function sendPayload(err, user) {
-        if (err) {
-          return callback(err, d2);
-        }
-        const key = d2.issueKey;
-        const url = "".concat(_impOsmUrls[key], "/comment");
-        const payload = {
-          username: user.display_name,
-          targetIds: [d2.identifier]
-        };
-        if (d2.newStatus) {
-          payload.status = d2.newStatus;
-          payload.text = "status changed";
-        }
-        if (d2.newComment) {
-          payload.text = d2.newComment;
-        }
-        const controller = new AbortController();
-        _cache2.inflightPost[d2.id] = controller;
-        const options2 = {
-          method: "POST",
-          signal: controller.signal,
-          body: JSON.stringify(payload)
-        };
-        json_default(url, options2).then(() => {
-          delete _cache2.inflightPost[d2.id];
-          if (!d2.newStatus) {
-            const now3 = /* @__PURE__ */ new Date();
-            let comments = d2.comments ? d2.comments : [];
-            comments.push({
-              username: payload.username,
-              text: payload.text,
-              timestamp: now3.getTime() / 1e3
-            });
-            this.replaceItem(d2.update({
-              comments,
-              newComment: void 0
-            }));
-          } else {
-            this.removeItem(d2);
-            if (d2.newStatus === "SOLVED") {
-              if (!(d2.issueKey in _cache2.closed)) {
-                _cache2.closed[d2.issueKey] = 0;
-              }
-              _cache2.closed[d2.issueKey] += 1;
-            }
-          }
-          if (callback)
-            callback(null, d2);
-        }).catch((err2) => {
-          delete _cache2.inflightPost[d2.id];
-          if (callback)
-            callback(err2.message);
-        });
-      }
-    },
-    // Get all cached QAItems covering the viewport
-    getItems(projection2) {
-      const viewport = projection2.clipExtent();
-      const min3 = [viewport[0][0], viewport[1][1]];
-      const max3 = [viewport[1][0], viewport[0][1]];
-      const bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
-      return _cache2.rtree.search(bbox2).map((d2) => d2.data);
-    },
-    // Get a QAItem from cache
-    // NOTE: Don't change method name until UI v3 is merged
-    getError(id2) {
-      return _cache2.data[id2];
-    },
-    // get the name of the icon to display for this item
-    getIcon(itemType) {
-      return _impOsmData.icons[itemType];
-    },
-    // Replace a single QAItem in the cache
-    replaceItem(issue) {
-      if (!(issue instanceof QAItem) || !issue.id)
-        return;
-      _cache2.data[issue.id] = issue;
-      updateRtree2(encodeIssueRtree2(issue), true);
-      return issue;
-    },
-    // Remove a single QAItem from the cache
-    removeItem(issue) {
-      if (!(issue instanceof QAItem) || !issue.id)
-        return;
-      delete _cache2.data[issue.id];
-      updateRtree2(encodeIssueRtree2(issue), false);
-    },
-    // Used to populate `closed:improveosm:*` changeset tags
-    getClosedCounts() {
-      return _cache2.closed;
-    }
-  };
-
-  // modules/services/osmose.js
-  var import_rbush3 = __toESM(require_rbush_min());
-
   // node_modules/marked/lib/marked.esm.js
   function _getDefaults() {
     return {
     }
     return html3;
   }
-  var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
-  function unescape2(html3) {
-    return html3.replace(unescapeTest, (_2, n3) => {
-      n3 = n3.toLowerCase();
-      if (n3 === "colon")
-        return ":";
-      if (n3.charAt(0) === "#") {
-        return n3.charAt(1) === "x" ? String.fromCharCode(parseInt(n3.substring(2), 16)) : String.fromCharCode(+n3.substring(1));
-      }
-      return "";
-    });
-  }
   var caret = /(^|[^\[])\^/g;
   function edit(regex, opt) {
     let source = typeof regex === "string" ? regex : regex.source;
   function cleanUrl(href) {
     try {
       href = encodeURI(href).replace(/%25/g, "%");
-    } catch (e3) {
+    } catch {
       return null;
     }
     return href;
       if (cap) {
         return {
           type: "hr",
-          raw: cap[0]
+          raw: rtrim(cap[0], "\n")
         };
       }
     }
     blockquote(src) {
       const cap = this.rules.block.blockquote.exec(src);
       if (cap) {
-        let text = cap[0].replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, "\n    $1");
-        text = rtrim(text.replace(/^ *>[ \t]?/gm, ""), "\n");
-        const top = this.lexer.state.top;
-        this.lexer.state.top = true;
-        const tokens = this.lexer.blockTokens(text);
-        this.lexer.state.top = top;
+        let lines = rtrim(cap[0], "\n").split("\n");
+        let raw = "";
+        let text = "";
+        const tokens = [];
+        while (lines.length > 0) {
+          let inBlockquote = false;
+          const currentLines = [];
+          let i3;
+          for (i3 = 0; i3 < lines.length; i3++) {
+            if (/^ {0,3}>/.test(lines[i3])) {
+              currentLines.push(lines[i3]);
+              inBlockquote = true;
+            } else if (!inBlockquote) {
+              currentLines.push(lines[i3]);
+            } else {
+              break;
+            }
+          }
+          lines = lines.slice(i3);
+          const currentRaw = currentLines.join("\n");
+          const currentText = currentRaw.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, "\n    $1").replace(/^ {0,3}>[ \t]?/gm, "");
+          raw = raw ? "".concat(raw, "\n").concat(currentRaw) : currentRaw;
+          text = text ? "".concat(text, "\n").concat(currentText) : currentText;
+          const top = this.lexer.state.top;
+          this.lexer.state.top = true;
+          this.lexer.blockTokens(currentText, tokens, true);
+          this.lexer.state.top = top;
+          if (lines.length === 0) {
+            break;
+          }
+          const lastToken = tokens[tokens.length - 1];
+          if ((lastToken == null ? void 0 : lastToken.type) === "code") {
+            break;
+          } else if ((lastToken == null ? void 0 : lastToken.type) === "blockquote") {
+            const oldToken = lastToken;
+            const newText = oldToken.raw + "\n" + lines.join("\n");
+            const newToken = this.blockquote(newText);
+            tokens[tokens.length - 1] = newToken;
+            raw = raw.substring(0, raw.length - oldToken.raw.length) + newToken.raw;
+            text = text.substring(0, text.length - oldToken.text.length) + newToken.text;
+            break;
+          } else if ((lastToken == null ? void 0 : lastToken.type) === "list") {
+            const oldToken = lastToken;
+            const newText = oldToken.raw + "\n" + lines.join("\n");
+            const newToken = this.list(newText);
+            tokens[tokens.length - 1] = newToken;
+            raw = raw.substring(0, raw.length - lastToken.raw.length) + newToken.raw;
+            text = text.substring(0, text.length - oldToken.raw.length) + newToken.raw;
+            lines = newText.substring(tokens[tokens.length - 1].raw.length).split("\n");
+            continue;
+          }
+        }
         return {
           type: "blockquote",
-          raw: cap[0],
+          raw,
           tokens,
           text
         };
           bull = isordered ? bull : "[*+-]";
         }
         const itemRegex = new RegExp("^( {0,3}".concat(bull, ")((?:[    ][^\\n]*)?(?:\\n|$))"));
-        let raw = "";
-        let itemContents = "";
         let endsWithBlankLine = false;
         while (src) {
           let endEarly = false;
+          let raw = "";
+          let itemContents = "";
           if (!(cap = itemRegex.exec(src))) {
             break;
           }
           src = src.substring(raw.length);
           let line = cap[2].split("\n", 1)[0].replace(/^\t+/, (t2) => " ".repeat(3 * t2.length));
           let nextLine = src.split("\n", 1)[0];
+          let blankLine = !line.trim();
           let indent = 0;
           if (this.options.pedantic) {
             indent = 2;
             itemContents = line.trimStart();
+          } else if (blankLine) {
+            indent = cap[1].length + 1;
           } else {
             indent = cap[2].search(/[^ ]/);
             indent = indent > 4 ? 1 : indent;
             itemContents = line.slice(indent);
             indent += cap[1].length;
           }
-          let blankLine = false;
-          if (!line && /^ *$/.test(nextLine)) {
+          if (blankLine && /^ *$/.test(nextLine)) {
             raw += nextLine + "\n";
             src = src.substring(nextLine.length + 1);
             endEarly = true;
           });
           list2.raw += raw;
         }
-        list2.items[list2.items.length - 1].raw = raw.trimEnd();
-        list2.items[list2.items.length - 1].text = itemContents.trimEnd();
+        list2.items[list2.items.length - 1].raw = list2.items[list2.items.length - 1].raw.trimEnd();
+        list2.items[list2.items.length - 1].text = list2.items[list2.items.length - 1].text.trimEnd();
         list2.raw = list2.raw.trimEnd();
         for (let i3 = 0; i3 < list2.items.length; i3++) {
           this.lexer.state.top = false;
           item.align.push(null);
         }
       }
-      for (const header of headers) {
+      for (let i3 = 0; i3 < headers.length; i3++) {
         item.header.push({
-          text: header,
-          tokens: this.lexer.inline(header)
+          text: headers[i3],
+          tokens: this.lexer.inline(headers[i3]),
+          header: true,
+          align: item.align[i3]
         });
       }
       for (const row of rows) {
-        item.rows.push(splitCells(row, item.header.length).map((cell) => {
+        item.rows.push(splitCells(row, item.header.length).map((cell, i3) => {
           return {
             text: cell,
-            tokens: this.lexer.inline(cell)
+            tokens: this.lexer.inline(cell),
+            header: false,
+            align: item.align[i3]
           };
         }));
       }
       }
     }
     url(src) {
-      var _a2, _b;
+      var _a3, _b3;
       let cap;
       if (cap = this.rules.inline.url.exec(src)) {
         let text, href;
           let prevCapZero;
           do {
             prevCapZero = cap[0];
-            cap[0] = (_b = (_a2 = this.rules.inline._backpedal.exec(cap[0])) == null ? void 0 : _a2[0]) != null ? _b : "";
+            cap[0] = (_b3 = (_a3 = this.rules.inline._backpedal.exec(cap[0])) == null ? void 0 : _a3[0]) != null ? _b3 : "";
           } while (prevCapZero !== cap[0]);
           text = escape$1(cap[0]);
           if (cap[1] === "www.") {
       this.inlineQueue = [];
       return this.tokens;
     }
-    blockTokens(src, tokens = []) {
+    blockTokens(src, tokens = [], lastParagraphClipped = false) {
       if (this.options.pedantic) {
         src = src.replace(/\t/g, "    ").replace(/^ +$/gm, "");
       } else {
       let token;
       let lastToken;
       let cutSrc;
-      let lastParagraphClipped;
       while (src) {
         if (this.options.extensions && this.options.extensions.block && this.options.extensions.block.some((extTokenizer) => {
           if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
         }
         if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
           lastToken = tokens[tokens.length - 1];
-          if (lastParagraphClipped && lastToken.type === "paragraph") {
+          if (lastParagraphClipped && (lastToken == null ? void 0 : lastToken.type) === "paragraph") {
             lastToken.raw += "\n" + token.raw;
             lastToken.text += "\n" + token.text;
             this.inlineQueue.pop();
     }
   };
   var _Renderer = class {
+    // set by the parser
     constructor(options2) {
       __publicField(this, "options");
+      __publicField(this, "parser");
       this.options = options2 || _defaults;
     }
-    code(code, infostring, escaped) {
-      var _a2;
-      const lang = (_a2 = (infostring || "").match(/^\S*/)) == null ? void 0 : _a2[0];
-      code = code.replace(/\n$/, "") + "\n";
-      if (!lang) {
+    space(token) {
+      return "";
+    }
+    code({ text, lang, escaped }) {
+      var _a3;
+      const langString = (_a3 = (lang || "").match(/^\S*/)) == null ? void 0 : _a3[0];
+      const code = text.replace(/\n$/, "") + "\n";
+      if (!langString) {
         return "<pre><code>" + (escaped ? code : escape$1(code, true)) + "</code></pre>\n";
       }
-      return '<pre><code class="language-' + escape$1(lang) + '">' + (escaped ? code : escape$1(code, true)) + "</code></pre>\n";
+      return '<pre><code class="language-' + escape$1(langString) + '">' + (escaped ? code : escape$1(code, true)) + "</code></pre>\n";
     }
-    blockquote(quote) {
-      return "<blockquote>\n".concat(quote, "</blockquote>\n");
+    blockquote({ tokens }) {
+      const body = this.parser.parse(tokens);
+      return "<blockquote>\n".concat(body, "</blockquote>\n");
     }
-    html(html3, block2) {
-      return html3;
+    html({ text }) {
+      return text;
     }
-    heading(text, level, raw) {
-      return "<h".concat(level, ">").concat(text, "</h").concat(level, ">\n");
+    heading({ tokens, depth }) {
+      return "<h".concat(depth, ">").concat(this.parser.parseInline(tokens), "</h").concat(depth, ">\n");
     }
-    hr() {
+    hr(token) {
       return "<hr>\n";
     }
-    list(body, ordered, start2) {
+    list(token) {
+      const ordered = token.ordered;
+      const start2 = token.start;
+      let body = "";
+      for (let j2 = 0; j2 < token.items.length; j2++) {
+        const item = token.items[j2];
+        body += this.listitem(item);
+      }
       const type2 = ordered ? "ol" : "ul";
-      const startatt = ordered && start2 !== 1 ? ' start="' + start2 + '"' : "";
-      return "<" + type2 + startatt + ">\n" + body + "</" + type2 + ">\n";
-    }
-    listitem(text, task, checked) {
-      return "<li>".concat(text, "</li>\n");
+      const startAttr = ordered && start2 !== 1 ? ' start="' + start2 + '"' : "";
+      return "<" + type2 + startAttr + ">\n" + body + "</" + type2 + ">\n";
+    }
+    listitem(item) {
+      let itemBody = "";
+      if (item.task) {
+        const checkbox = this.checkbox({ checked: !!item.checked });
+        if (item.loose) {
+          if (item.tokens.length > 0 && item.tokens[0].type === "paragraph") {
+            item.tokens[0].text = checkbox + " " + item.tokens[0].text;
+            if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === "text") {
+              item.tokens[0].tokens[0].text = checkbox + " " + item.tokens[0].tokens[0].text;
+            }
+          } else {
+            item.tokens.unshift({
+              type: "text",
+              raw: checkbox + " ",
+              text: checkbox + " "
+            });
+          }
+        } else {
+          itemBody += checkbox + " ";
+        }
+      }
+      itemBody += this.parser.parse(item.tokens, !!item.loose);
+      return "<li>".concat(itemBody, "</li>\n");
     }
-    checkbox(checked) {
+    checkbox({ checked }) {
       return "<input " + (checked ? 'checked="" ' : "") + 'disabled="" type="checkbox">';
     }
-    paragraph(text) {
-      return "<p>".concat(text, "</p>\n");
+    paragraph({ tokens }) {
+      return "<p>".concat(this.parser.parseInline(tokens), "</p>\n");
     }
-    table(header, body) {
+    table(token) {
+      let header = "";
+      let cell = "";
+      for (let j2 = 0; j2 < token.header.length; j2++) {
+        cell += this.tablecell(token.header[j2]);
+      }
+      header += this.tablerow({ text: cell });
+      let body = "";
+      for (let j2 = 0; j2 < token.rows.length; j2++) {
+        const row = token.rows[j2];
+        cell = "";
+        for (let k2 = 0; k2 < row.length; k2++) {
+          cell += this.tablecell(row[k2]);
+        }
+        body += this.tablerow({ text: cell });
+      }
       if (body)
         body = "<tbody>".concat(body, "</tbody>");
       return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n";
     }
-    tablerow(content) {
-      return "<tr>\n".concat(content, "</tr>\n");
+    tablerow({ text }) {
+      return "<tr>\n".concat(text, "</tr>\n");
     }
-    tablecell(content, flags) {
-      const type2 = flags.header ? "th" : "td";
-      const tag2 = flags.align ? "<".concat(type2, ' align="').concat(flags.align, '">') : "<".concat(type2, ">");
+    tablecell(token) {
+      const content = this.parser.parseInline(token.tokens);
+      const type2 = token.header ? "th" : "td";
+      const tag2 = token.align ? "<".concat(type2, ' align="').concat(token.align, '">') : "<".concat(type2, ">");
       return tag2 + content + "</".concat(type2, ">\n");
     }
     /**
      * span level renderer
      */
-    strong(text) {
-      return "<strong>".concat(text, "</strong>");
+    strong({ tokens }) {
+      return "<strong>".concat(this.parser.parseInline(tokens), "</strong>");
     }
-    em(text) {
-      return "<em>".concat(text, "</em>");
+    em({ tokens }) {
+      return "<em>".concat(this.parser.parseInline(tokens), "</em>");
     }
-    codespan(text) {
+    codespan({ text }) {
       return "<code>".concat(text, "</code>");
     }
-    br() {
+    br(token) {
       return "<br>";
     }
-    del(text) {
-      return "<del>".concat(text, "</del>");
+    del({ tokens }) {
+      return "<del>".concat(this.parser.parseInline(tokens), "</del>");
     }
-    link(href, title, text) {
+    link({ href, title, tokens }) {
+      const text = this.parser.parseInline(tokens);
       const cleanHref = cleanUrl(href);
       if (cleanHref === null) {
         return text;
       out += ">" + text + "</a>";
       return out;
     }
-    image(href, title, text) {
+    image({ href, title, text }) {
       const cleanHref = cleanUrl(href);
       if (cleanHref === null) {
         return text;
       out += ">";
       return out;
     }
-    text(text) {
-      return text;
+    text(token) {
+      return "tokens" in token && token.tokens ? this.parser.parseInline(token.tokens) : token.text;
     }
   };
   var _TextRenderer = class {
     // no need for block level renderers
-    strong(text) {
+    strong({ text }) {
       return text;
     }
-    em(text) {
+    em({ text }) {
       return text;
     }
-    codespan(text) {
+    codespan({ text }) {
       return text;
     }
-    del(text) {
+    del({ text }) {
       return text;
     }
-    html(text) {
+    html({ text }) {
       return text;
     }
-    text(text) {
+    text({ text }) {
       return text;
     }
-    link(href, title, text) {
+    link({ text }) {
       return "" + text;
     }
-    image(href, title, text) {
+    image({ text }) {
       return "" + text;
     }
     br() {
       this.options.renderer = this.options.renderer || new _Renderer();
       this.renderer = this.options.renderer;
       this.renderer.options = this.options;
+      this.renderer.parser = this;
       this.textRenderer = new _TextRenderer();
     }
     /**
     parse(tokens, top = true) {
       let out = "";
       for (let i3 = 0; i3 < tokens.length; i3++) {
-        const token = tokens[i3];
-        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
-          const genericToken = token;
+        const anyToken = tokens[i3];
+        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) {
+          const genericToken = anyToken;
           const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken);
           if (ret !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "paragraph", "text"].includes(genericToken.type)) {
             out += ret || "";
             continue;
           }
         }
+        const token = anyToken;
         switch (token.type) {
           case "space": {
+            out += this.renderer.space(token);
             continue;
           }
           case "hr": {
-            out += this.renderer.hr();
+            out += this.renderer.hr(token);
             continue;
           }
           case "heading": {
-            const headingToken = token;
-            out += this.renderer.heading(this.parseInline(headingToken.tokens), headingToken.depth, unescape2(this.parseInline(headingToken.tokens, this.textRenderer)));
+            out += this.renderer.heading(token);
             continue;
           }
           case "code": {
-            const codeToken = token;
-            out += this.renderer.code(codeToken.text, codeToken.lang, !!codeToken.escaped);
+            out += this.renderer.code(token);
             continue;
           }
           case "table": {
-            const tableToken = token;
-            let header = "";
-            let cell = "";
-            for (let j2 = 0; j2 < tableToken.header.length; j2++) {
-              cell += this.renderer.tablecell(this.parseInline(tableToken.header[j2].tokens), { header: true, align: tableToken.align[j2] });
-            }
-            header += this.renderer.tablerow(cell);
-            let body = "";
-            for (let j2 = 0; j2 < tableToken.rows.length; j2++) {
-              const row = tableToken.rows[j2];
-              cell = "";
-              for (let k2 = 0; k2 < row.length; k2++) {
-                cell += this.renderer.tablecell(this.parseInline(row[k2].tokens), { header: false, align: tableToken.align[k2] });
-              }
-              body += this.renderer.tablerow(cell);
-            }
-            out += this.renderer.table(header, body);
+            out += this.renderer.table(token);
             continue;
           }
           case "blockquote": {
-            const blockquoteToken = token;
-            const body = this.parse(blockquoteToken.tokens);
-            out += this.renderer.blockquote(body);
+            out += this.renderer.blockquote(token);
             continue;
           }
           case "list": {
-            const listToken = token;
-            const ordered = listToken.ordered;
-            const start2 = listToken.start;
-            const loose = listToken.loose;
-            let body = "";
-            for (let j2 = 0; j2 < listToken.items.length; j2++) {
-              const item = listToken.items[j2];
-              const checked = item.checked;
-              const task = item.task;
-              let itemBody = "";
-              if (item.task) {
-                const checkbox = this.renderer.checkbox(!!checked);
-                if (loose) {
-                  if (item.tokens.length > 0 && item.tokens[0].type === "paragraph") {
-                    item.tokens[0].text = checkbox + " " + item.tokens[0].text;
-                    if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === "text") {
-                      item.tokens[0].tokens[0].text = checkbox + " " + item.tokens[0].tokens[0].text;
-                    }
-                  } else {
-                    item.tokens.unshift({
-                      type: "text",
-                      text: checkbox + " "
-                    });
-                  }
-                } else {
-                  itemBody += checkbox + " ";
-                }
-              }
-              itemBody += this.parse(item.tokens, loose);
-              body += this.renderer.listitem(itemBody, task, !!checked);
-            }
-            out += this.renderer.list(body, ordered, start2);
+            out += this.renderer.list(token);
             continue;
           }
           case "html": {
-            const htmlToken = token;
-            out += this.renderer.html(htmlToken.text, htmlToken.block);
+            out += this.renderer.html(token);
             continue;
           }
           case "paragraph": {
-            const paragraphToken = token;
-            out += this.renderer.paragraph(this.parseInline(paragraphToken.tokens));
+            out += this.renderer.paragraph(token);
             continue;
           }
           case "text": {
             let textToken = token;
-            let body = textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text;
+            let body = this.renderer.text(textToken);
             while (i3 + 1 < tokens.length && tokens[i3 + 1].type === "text") {
               textToken = tokens[++i3];
-              body += "\n" + (textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text);
+              body += "\n" + this.renderer.text(textToken);
+            }
+            if (top) {
+              out += this.renderer.paragraph({
+                type: "paragraph",
+                raw: body,
+                text: body,
+                tokens: [{ type: "text", raw: body, text: body }]
+              });
+            } else {
+              out += body;
             }
-            out += top ? this.renderer.paragraph(body) : body;
             continue;
           }
           default: {
       renderer = renderer || this.renderer;
       let out = "";
       for (let i3 = 0; i3 < tokens.length; i3++) {
-        const token = tokens[i3];
-        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
-          const ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
-          if (ret !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(token.type)) {
+        const anyToken = tokens[i3];
+        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) {
+          const ret = this.options.extensions.renderers[anyToken.type].call({ parser: this }, anyToken);
+          if (ret !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(anyToken.type)) {
             out += ret || "";
             continue;
           }
         }
+        const token = anyToken;
         switch (token.type) {
           case "escape": {
-            const escapeToken = token;
-            out += renderer.text(escapeToken.text);
+            out += renderer.text(token);
             break;
           }
           case "html": {
-            const tagToken = token;
-            out += renderer.html(tagToken.text);
+            out += renderer.html(token);
             break;
           }
           case "link": {
-            const linkToken = token;
-            out += renderer.link(linkToken.href, linkToken.title, this.parseInline(linkToken.tokens, renderer));
+            out += renderer.link(token);
             break;
           }
           case "image": {
-            const imageToken = token;
-            out += renderer.image(imageToken.href, imageToken.title, imageToken.text);
+            out += renderer.image(token);
             break;
           }
           case "strong": {
-            const strongToken = token;
-            out += renderer.strong(this.parseInline(strongToken.tokens, renderer));
+            out += renderer.strong(token);
             break;
           }
           case "em": {
-            const emToken = token;
-            out += renderer.em(this.parseInline(emToken.tokens, renderer));
+            out += renderer.em(token);
             break;
           }
           case "codespan": {
-            const codespanToken = token;
-            out += renderer.codespan(codespanToken.text);
+            out += renderer.codespan(token);
             break;
           }
           case "br": {
-            out += renderer.br();
+            out += renderer.br(token);
             break;
           }
           case "del": {
-            const delToken = token;
-            out += renderer.del(this.parseInline(delToken.tokens, renderer));
+            out += renderer.del(token);
             break;
           }
           case "text": {
-            const textToken = token;
-            out += renderer.text(textToken.text);
+            out += renderer.text(token);
             break;
           }
           default: {
     "postprocess",
     "processAllTokens"
   ]));
-  var _parseMarkdown, parseMarkdown_fn, _onError, onError_fn;
   var Marked = class {
     constructor(...args) {
-      __privateAdd(this, _parseMarkdown);
-      __privateAdd(this, _onError);
       __publicField(this, "defaults", _getDefaults());
       __publicField(this, "options", this.setOptions);
-      __publicField(this, "parse", __privateMethod(this, _parseMarkdown, parseMarkdown_fn).call(this, _Lexer.lex, _Parser.parse));
-      __publicField(this, "parseInline", __privateMethod(this, _parseMarkdown, parseMarkdown_fn).call(this, _Lexer.lexInline, _Parser.parseInline));
+      __publicField(this, "parse", this.parseMarkdown(_Lexer.lex, _Parser.parse));
+      __publicField(this, "parseInline", this.parseMarkdown(_Lexer.lexInline, _Parser.parseInline));
       __publicField(this, "Parser", _Parser);
       __publicField(this, "Renderer", _Renderer);
       __publicField(this, "TextRenderer", _TextRenderer);
      * Run callback for every token
      */
     walkTokens(tokens, callback) {
-      var _a2, _b;
+      var _a3, _b3;
       let values = [];
       for (const token of tokens) {
         values = values.concat(callback.call(this, token));
           }
           default: {
             const genericToken = token;
-            if ((_b = (_a2 = this.defaults.extensions) == null ? void 0 : _a2.childTokens) == null ? void 0 : _b[genericToken.type]) {
+            if ((_b3 = (_a3 = this.defaults.extensions) == null ? void 0 : _a3.childTokens) == null ? void 0 : _b3[genericToken.type]) {
               this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {
                 const tokens2 = genericToken[childTokens].flat(Infinity);
                 values = values.concat(this.walkTokens(tokens2, callback));
             if (!(prop in renderer)) {
               throw new Error("renderer '".concat(prop, "' does not exist"));
             }
-            if (prop === "options") {
+            if (["options", "parser"].includes(prop)) {
               continue;
             }
             const rendererProp = prop;
     parser(tokens, options2) {
       return _Parser.parse(tokens, options2 != null ? options2 : this.defaults);
     }
-  };
-  _parseMarkdown = new WeakSet();
-  parseMarkdown_fn = function(lexer2, parser3) {
-    return (src, options2) => {
-      const origOpt = { ...options2 };
-      const opt = { ...this.defaults, ...origOpt };
-      if (this.defaults.async === true && origOpt.async === false) {
-        if (!opt.silent) {
-          console.warn("marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored.");
+    parseMarkdown(lexer2, parser3) {
+      const parse = (src, options2) => {
+        const origOpt = { ...options2 };
+        const opt = { ...this.defaults, ...origOpt };
+        const throwError = this.onError(!!opt.silent, !!opt.async);
+        if (this.defaults.async === true && origOpt.async === false) {
+          return throwError(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
         }
-        opt.async = true;
-      }
-      const throwError = __privateMethod(this, _onError, onError_fn).call(this, !!opt.silent, !!opt.async);
-      if (typeof src === "undefined" || src === null) {
-        return throwError(new Error("marked(): input parameter is undefined or null"));
-      }
-      if (typeof src !== "string") {
-        return throwError(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected"));
-      }
-      if (opt.hooks) {
-        opt.hooks.options = opt;
-      }
-      if (opt.async) {
-        return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src).then((src2) => lexer2(src2, opt)).then((tokens) => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens).then((tokens) => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens).then((tokens) => parser3(tokens, opt)).then((html3) => opt.hooks ? opt.hooks.postprocess(html3) : html3).catch(throwError);
-      }
-      try {
-        if (opt.hooks) {
-          src = opt.hooks.preprocess(src);
+        if (typeof src === "undefined" || src === null) {
+          return throwError(new Error("marked(): input parameter is undefined or null"));
+        }
+        if (typeof src !== "string") {
+          return throwError(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected"));
         }
-        let tokens = lexer2(src, opt);
         if (opt.hooks) {
-          tokens = opt.hooks.processAllTokens(tokens);
+          opt.hooks.options = opt;
         }
-        if (opt.walkTokens) {
-          this.walkTokens(tokens, opt.walkTokens);
+        if (opt.async) {
+          return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src).then((src2) => lexer2(src2, opt)).then((tokens) => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens).then((tokens) => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens).then((tokens) => parser3(tokens, opt)).then((html3) => opt.hooks ? opt.hooks.postprocess(html3) : html3).catch(throwError);
         }
-        let html3 = parser3(tokens, opt);
-        if (opt.hooks) {
-          html3 = opt.hooks.postprocess(html3);
+        try {
+          if (opt.hooks) {
+            src = opt.hooks.preprocess(src);
+          }
+          let tokens = lexer2(src, opt);
+          if (opt.hooks) {
+            tokens = opt.hooks.processAllTokens(tokens);
+          }
+          if (opt.walkTokens) {
+            this.walkTokens(tokens, opt.walkTokens);
+          }
+          let html3 = parser3(tokens, opt);
+          if (opt.hooks) {
+            html3 = opt.hooks.postprocess(html3);
+          }
+          return html3;
+        } catch (e3) {
+          return throwError(e3);
+        }
+      };
+      return parse;
+    }
+    onError(silent, async) {
+      return (e3) => {
+        e3.message += "\nPlease report this to https://github.com/markedjs/marked.";
+        if (silent) {
+          const msg = "<p>An error occurred:</p><pre>" + escape$1(e3.message + "", true) + "</pre>";
+          if (async) {
+            return Promise.resolve(msg);
+          }
+          return msg;
         }
-        return html3;
-      } catch (e3) {
-        return throwError(e3);
-      }
-    };
-  };
-  _onError = new WeakSet();
-  onError_fn = function(silent, async) {
-    return (e3) => {
-      e3.message += "\nPlease report this to https://github.com/markedjs/marked.";
-      if (silent) {
-        const msg = "<p>An error occurred:</p><pre>" + escape$1(e3.message + "", true) + "</pre>";
         if (async) {
-          return Promise.resolve(msg);
+          return Promise.reject(e3);
         }
-        return msg;
-      }
-      if (async) {
-        return Promise.reject(e3);
-      }
-      throw e3;
-    };
+        throw e3;
+      };
+    }
   };
   var markedInstance = new Marked();
   function marked(src, opt) {
   var lexer = _Lexer.lex;
 
   // modules/services/osmose.js
-  var tiler3 = utilTiler();
-  var dispatch4 = dispatch_default("loaded");
-  var _tileZoom3 = 14;
+  var tiler2 = utilTiler();
+  var dispatch3 = dispatch_default("loaded");
+  var _tileZoom2 = 14;
   var _osmoseUrlRoot = "https://osmose.openstreetmap.fr/api/0.3";
   var _osmoseData = { icons: {}, items: [] };
-  var _cache3;
-  function abortRequest3(controller) {
+  var _cache2;
+  function abortRequest2(controller) {
     if (controller) {
       controller.abort();
     }
   }
-  function abortUnwantedRequests3(cache, tiles) {
+  function abortUnwantedRequests2(cache, tiles) {
     Object.keys(cache.inflightTile).forEach((k2) => {
       let wanted = tiles.find((tile) => k2 === tile.id);
       if (!wanted) {
-        abortRequest3(cache.inflightTile[k2]);
+        abortRequest2(cache.inflightTile[k2]);
         delete cache.inflightTile[k2];
       }
     });
   }
-  function encodeIssueRtree3(d2) {
+  function encodeIssueRtree2(d2) {
     return { minX: d2.loc[0], minY: d2.loc[1], maxX: d2.loc[0], maxY: d2.loc[1], data: d2 };
   }
-  function updateRtree3(item, replace) {
-    _cache3.rtree.remove(item, (a2, b2) => a2.data.id === b2.data.id);
+  function updateRtree2(item, replace) {
+    _cache2.rtree.remove(item, (a2, b2) => a2.data.id === b2.data.id);
     if (replace) {
-      _cache3.rtree.insert(item);
+      _cache2.rtree.insert(item);
     }
   }
-  function preventCoincident2(loc) {
+  function preventCoincident(loc) {
     let coincident = false;
     do {
       let delta = coincident ? [1e-5, 0] : [0, 1e-5];
       loc = geoVecAdd(loc, delta);
       let bbox2 = geoExtent(loc).bbox();
-      coincident = _cache3.rtree.search(bbox2).length;
+      coincident = _cache2.rtree.search(bbox2).length;
     } while (coincident);
     return loc;
   }
         _osmoseData = d2.osmose;
         _osmoseData.items = Object.keys(d2.osmose.icons).map((s2) => s2.split("-")[0]).reduce((unique, item) => unique.indexOf(item) !== -1 ? unique : [...unique, item], []);
       });
-      if (!_cache3) {
+      if (!_cache2) {
         this.reset();
       }
-      this.event = utilRebind(this, dispatch4, "on");
+      this.event = utilRebind(this, dispatch3, "on");
     },
     reset() {
       let _strings = {};
       let _colors = {};
-      if (_cache3) {
-        Object.values(_cache3.inflightTile).forEach(abortRequest3);
-        _strings = _cache3.strings;
-        _colors = _cache3.colors;
+      if (_cache2) {
+        Object.values(_cache2.inflightTile).forEach(abortRequest2);
+        _strings = _cache2.strings;
+        _colors = _cache2.colors;
       }
-      _cache3 = {
+      _cache2 = {
         data: {},
         loadedTile: {},
         inflightTile: {},
         inflightPost: {},
         closed: {},
-        rtree: new import_rbush3.default(),
+        rtree: new RBush(),
         strings: _strings,
         colors: _colors
       };
         // So we want to filter our request for only types iD supports
         item: _osmoseData.items
       };
-      let tiles = tiler3.zoomExtent([_tileZoom3, _tileZoom3]).getTiles(projection2);
-      abortUnwantedRequests3(_cache3, tiles);
+      let tiles = tiler2.zoomExtent([_tileZoom2, _tileZoom2]).getTiles(projection2);
+      abortUnwantedRequests2(_cache2, tiles);
       tiles.forEach((tile) => {
-        if (_cache3.loadedTile[tile.id] || _cache3.inflightTile[tile.id])
-          return;
+        if (_cache2.loadedTile[tile.id] || _cache2.inflightTile[tile.id]) return;
         let [x2, y2, z2] = tile.xyz;
         let url = "".concat(_osmoseUrlRoot, "/issues/").concat(z2, "/").concat(x2, "/").concat(y2, ".geojson?") + utilQsString(params);
         let controller = new AbortController();
-        _cache3.inflightTile[tile.id] = controller;
+        _cache2.inflightTile[tile.id] = controller;
         json_default(url, { signal: controller.signal }).then((data) => {
-          delete _cache3.inflightTile[tile.id];
-          _cache3.loadedTile[tile.id] = true;
+          delete _cache2.inflightTile[tile.id];
+          _cache2.loadedTile[tile.id] = true;
           if (data.features) {
             data.features.forEach((issue) => {
               const { item, class: cl, uuid: id2 } = issue.properties;
               const itemType = "".concat(item, "-").concat(cl);
               if (itemType in _osmoseData.icons) {
                 let loc = issue.geometry.coordinates;
-                loc = preventCoincident2(loc);
+                loc = preventCoincident(loc);
                 let d2 = new QAItem(loc, this, itemType, id2, { item });
                 if (item === 8300 || item === 8360) {
                   d2.elems = [];
                 }
-                _cache3.data[d2.id] = d2;
-                _cache3.rtree.insert(encodeIssueRtree3(d2));
+                _cache2.data[d2.id] = d2;
+                _cache2.rtree.insert(encodeIssueRtree2(d2));
               }
             });
           }
-          dispatch4.call("loaded");
+          dispatch3.call("loaded");
         }).catch(() => {
-          delete _cache3.inflightTile[tile.id];
-          _cache3.loadedTile[tile.id] = true;
+          delete _cache2.inflightTile[tile.id];
+          _cache2.loadedTile[tile.id] = true;
         });
       });
     },
     },
     loadStrings(locale2 = _mainLocalizer.localeCode()) {
       const items = Object.keys(_osmoseData.icons);
-      if (locale2 in _cache3.strings && Object.keys(_cache3.strings[locale2]).length === items.length) {
-        return Promise.resolve(_cache3.strings[locale2]);
+      if (locale2 in _cache2.strings && Object.keys(_cache2.strings[locale2]).length === items.length) {
+        return Promise.resolve(_cache2.strings[locale2]);
       }
-      if (!(locale2 in _cache3.strings)) {
-        _cache3.strings[locale2] = {};
+      if (!(locale2 in _cache2.strings)) {
+        _cache2.strings[locale2] = {};
       }
       const allRequests = items.map((itemType) => {
-        if (itemType in _cache3.strings[locale2])
-          return null;
+        if (itemType in _cache2.strings[locale2]) return null;
         const cacheData = (data) => {
           const [cat = { items: [] }] = data.categories;
           const [item2 = { class: [] }] = cat.items;
           }
           const { item: itemInt, color: color2 } = item2;
           if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color2)) {
-            _cache3.colors[itemInt] = color2;
+            _cache2.colors[itemInt] = color2;
           }
           const { title, detail, fix, trap } = cl2;
           let issueStrings = {};
-          if (title)
-            issueStrings.title = title.auto;
-          if (detail)
-            issueStrings.detail = marked(detail.auto);
-          if (trap)
-            issueStrings.trap = marked(trap.auto);
-          if (fix)
-            issueStrings.fix = marked(fix.auto);
-          _cache3.strings[locale2][itemType] = issueStrings;
+          if (title) issueStrings.title = title.auto;
+          if (detail) issueStrings.detail = marked(detail.auto);
+          if (trap) issueStrings.trap = marked(trap.auto);
+          if (fix) issueStrings.fix = marked(fix.auto);
+          _cache2.strings[locale2][itemType] = issueStrings;
         };
         const [item, cl] = itemType.split("-");
         const url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale2);
         return json_default(url).then(cacheData);
       }).filter(Boolean);
-      return Promise.all(allRequests).then(() => _cache3.strings[locale2]);
+      return Promise.all(allRequests).then(() => _cache2.strings[locale2]);
     },
     getStrings(itemType, locale2 = _mainLocalizer.localeCode()) {
-      return locale2 in _cache3.strings ? _cache3.strings[locale2][itemType] : {};
+      return locale2 in _cache2.strings ? _cache2.strings[locale2][itemType] : {};
     },
     getColor(itemType) {
-      return itemType in _cache3.colors ? _cache3.colors[itemType] : "#FFFFFF";
+      return itemType in _cache2.colors ? _cache2.colors[itemType] : "#FFFFFF";
     },
     postUpdate(issue, callback) {
-      if (_cache3.inflightPost[issue.id]) {
+      if (_cache2.inflightPost[issue.id]) {
         return callback({ message: "Issue update already inflight", status: -2 }, issue);
       }
       const url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
       const controller = new AbortController();
       const after = () => {
-        delete _cache3.inflightPost[issue.id];
+        delete _cache2.inflightPost[issue.id];
         this.removeItem(issue);
         if (issue.newStatus === "done") {
-          if (!(issue.item in _cache3.closed)) {
-            _cache3.closed[issue.item] = 0;
+          if (!(issue.item in _cache2.closed)) {
+            _cache2.closed[issue.item] = 0;
           }
-          _cache3.closed[issue.item] += 1;
+          _cache2.closed[issue.item] += 1;
         }
-        if (callback)
-          callback(null, issue);
+        if (callback) callback(null, issue);
       };
-      _cache3.inflightPost[issue.id] = controller;
+      _cache2.inflightPost[issue.id] = controller;
       fetch(url, { signal: controller.signal }).then(after).catch((err) => {
-        delete _cache3.inflightPost[issue.id];
-        if (callback)
-          callback(err.message);
+        delete _cache2.inflightPost[issue.id];
+        if (callback) callback(err.message);
       });
     },
     // Get all cached QAItems covering the viewport
       const min3 = [viewport[0][0], viewport[1][1]];
       const max3 = [viewport[1][0], viewport[0][1]];
       const bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
-      return _cache3.rtree.search(bbox2).map((d2) => d2.data);
+      return _cache2.rtree.search(bbox2).map((d2) => d2.data);
     },
     // Get a QAItem from cache
     // NOTE: Don't change method name until UI v3 is merged
     getError(id2) {
-      return _cache3.data[id2];
+      return _cache2.data[id2];
     },
     // get the name of the icon to display for this item
     getIcon(itemType) {
     },
     // Replace a single QAItem in the cache
     replaceItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
-      _cache3.data[item.id] = item;
-      updateRtree3(encodeIssueRtree3(item), true);
+      if (!(item instanceof QAItem) || !item.id) return;
+      _cache2.data[item.id] = item;
+      updateRtree2(encodeIssueRtree2(item), true);
       return item;
     },
     // Remove a single QAItem from the cache
     removeItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
-      delete _cache3.data[item.id];
-      updateRtree3(encodeIssueRtree3(item), false);
+      if (!(item instanceof QAItem) || !item.id) return;
+      delete _cache2.data[item.id];
+      updateRtree2(encodeIssueRtree2(item), false);
     },
     // Used to populate `closed:osmose:*` changeset tags
     getClosedCounts() {
-      return _cache3.closed;
+      return _cache2.closed;
     },
     itemURL(item) {
       return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
     }
   };
 
+  // node_modules/pbf/index.js
+  var SHIFT_LEFT_32 = (1 << 16) * (1 << 16);
+  var SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
+  var TEXT_DECODER_MIN_LENGTH = 12;
+  var utf8TextDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder("utf-8");
+  var PBF_VARINT = 0;
+  var PBF_FIXED64 = 1;
+  var PBF_BYTES = 2;
+  var PBF_FIXED32 = 5;
+  var Pbf = class {
+    /**
+     * @param {Uint8Array | ArrayBuffer} [buf]
+     */
+    constructor(buf = new Uint8Array(16)) {
+      this.buf = ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf);
+      this.dataView = new DataView(this.buf.buffer);
+      this.pos = 0;
+      this.type = 0;
+      this.length = this.buf.length;
+    }
+    // === READING =================================================================
+    /**
+     * @template T
+     * @param {(tag: number, result: T, pbf: Pbf) => void} readField
+     * @param {T} result
+     * @param {number} [end]
+     */
+    readFields(readField, result, end = this.length) {
+      while (this.pos < end) {
+        const val = this.readVarint(), tag2 = val >> 3, startPos = this.pos;
+        this.type = val & 7;
+        readField(tag2, result, this);
+        if (this.pos === startPos) this.skip(val);
+      }
+      return result;
+    }
+    /**
+     * @template T
+     * @param {(tag: number, result: T, pbf: Pbf) => void} readField
+     * @param {T} result
+     */
+    readMessage(readField, result) {
+      return this.readFields(readField, result, this.readVarint() + this.pos);
+    }
+    readFixed32() {
+      const val = this.dataView.getUint32(this.pos, true);
+      this.pos += 4;
+      return val;
+    }
+    readSFixed32() {
+      const val = this.dataView.getInt32(this.pos, true);
+      this.pos += 4;
+      return val;
+    }
+    // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
+    readFixed64() {
+      const val = this.dataView.getUint32(this.pos, true) + this.dataView.getUint32(this.pos + 4, true) * SHIFT_LEFT_32;
+      this.pos += 8;
+      return val;
+    }
+    readSFixed64() {
+      const val = this.dataView.getUint32(this.pos, true) + this.dataView.getInt32(this.pos + 4, true) * SHIFT_LEFT_32;
+      this.pos += 8;
+      return val;
+    }
+    readFloat() {
+      const val = this.dataView.getFloat32(this.pos, true);
+      this.pos += 4;
+      return val;
+    }
+    readDouble() {
+      const val = this.dataView.getFloat64(this.pos, true);
+      this.pos += 8;
+      return val;
+    }
+    /**
+     * @param {boolean} [isSigned]
+     */
+    readVarint(isSigned) {
+      const buf = this.buf;
+      let val, b2;
+      b2 = buf[this.pos++];
+      val = b2 & 127;
+      if (b2 < 128) return val;
+      b2 = buf[this.pos++];
+      val |= (b2 & 127) << 7;
+      if (b2 < 128) return val;
+      b2 = buf[this.pos++];
+      val |= (b2 & 127) << 14;
+      if (b2 < 128) return val;
+      b2 = buf[this.pos++];
+      val |= (b2 & 127) << 21;
+      if (b2 < 128) return val;
+      b2 = buf[this.pos];
+      val |= (b2 & 15) << 28;
+      return readVarintRemainder(val, isSigned, this);
+    }
+    readVarint64() {
+      return this.readVarint(true);
+    }
+    readSVarint() {
+      const num = this.readVarint();
+      return num % 2 === 1 ? (num + 1) / -2 : num / 2;
+    }
+    readBoolean() {
+      return Boolean(this.readVarint());
+    }
+    readString() {
+      const end = this.readVarint() + this.pos;
+      const pos = this.pos;
+      this.pos = end;
+      if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
+        return utf8TextDecoder.decode(this.buf.subarray(pos, end));
+      }
+      return readUtf8(this.buf, pos, end);
+    }
+    readBytes() {
+      const end = this.readVarint() + this.pos, buffer = this.buf.subarray(this.pos, end);
+      this.pos = end;
+      return buffer;
+    }
+    // verbose for performance reasons; doesn't affect gzipped size
+    /**
+     * @param {number[]} [arr]
+     * @param {boolean} [isSigned]
+     */
+    readPackedVarint(arr = [], isSigned) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readVarint(isSigned));
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedSVarint(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readSVarint());
+      return arr;
+    }
+    /** @param {boolean[]} [arr] */
+    readPackedBoolean(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readBoolean());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedFloat(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readFloat());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedDouble(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readDouble());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedFixed32(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readFixed32());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedSFixed32(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readSFixed32());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedFixed64(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readFixed64());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedSFixed64(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readSFixed64());
+      return arr;
+    }
+    readPackedEnd() {
+      return this.type === PBF_BYTES ? this.readVarint() + this.pos : this.pos + 1;
+    }
+    /** @param {number} val */
+    skip(val) {
+      const type2 = val & 7;
+      if (type2 === PBF_VARINT) while (this.buf[this.pos++] > 127) {
+      }
+      else if (type2 === PBF_BYTES) this.pos = this.readVarint() + this.pos;
+      else if (type2 === PBF_FIXED32) this.pos += 4;
+      else if (type2 === PBF_FIXED64) this.pos += 8;
+      else throw new Error("Unimplemented type: ".concat(type2));
+    }
+    // === WRITING =================================================================
+    /**
+     * @param {number} tag
+     * @param {number} type
+     */
+    writeTag(tag2, type2) {
+      this.writeVarint(tag2 << 3 | type2);
+    }
+    /** @param {number} min */
+    realloc(min3) {
+      let length2 = this.length || 16;
+      while (length2 < this.pos + min3) length2 *= 2;
+      if (length2 !== this.length) {
+        const buf = new Uint8Array(length2);
+        buf.set(this.buf);
+        this.buf = buf;
+        this.dataView = new DataView(buf.buffer);
+        this.length = length2;
+      }
+    }
+    finish() {
+      this.length = this.pos;
+      this.pos = 0;
+      return this.buf.subarray(0, this.length);
+    }
+    /** @param {number} val */
+    writeFixed32(val) {
+      this.realloc(4);
+      this.dataView.setInt32(this.pos, val, true);
+      this.pos += 4;
+    }
+    /** @param {number} val */
+    writeSFixed32(val) {
+      this.realloc(4);
+      this.dataView.setInt32(this.pos, val, true);
+      this.pos += 4;
+    }
+    /** @param {number} val */
+    writeFixed64(val) {
+      this.realloc(8);
+      this.dataView.setInt32(this.pos, val & -1, true);
+      this.dataView.setInt32(this.pos + 4, Math.floor(val * SHIFT_RIGHT_32), true);
+      this.pos += 8;
+    }
+    /** @param {number} val */
+    writeSFixed64(val) {
+      this.realloc(8);
+      this.dataView.setInt32(this.pos, val & -1, true);
+      this.dataView.setInt32(this.pos + 4, Math.floor(val * SHIFT_RIGHT_32), true);
+      this.pos += 8;
+    }
+    /** @param {number} val */
+    writeVarint(val) {
+      val = +val || 0;
+      if (val > 268435455 || val < 0) {
+        writeBigVarint(val, this);
+        return;
+      }
+      this.realloc(4);
+      this.buf[this.pos++] = val & 127 | (val > 127 ? 128 : 0);
+      if (val <= 127) return;
+      this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
+      if (val <= 127) return;
+      this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
+      if (val <= 127) return;
+      this.buf[this.pos++] = val >>> 7 & 127;
+    }
+    /** @param {number} val */
+    writeSVarint(val) {
+      this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
+    }
+    /** @param {boolean} val */
+    writeBoolean(val) {
+      this.writeVarint(+val);
+    }
+    /** @param {string} str */
+    writeString(str) {
+      str = String(str);
+      this.realloc(str.length * 4);
+      this.pos++;
+      const startPos = this.pos;
+      this.pos = writeUtf8(this.buf, str, this.pos);
+      const len = this.pos - startPos;
+      if (len >= 128) makeRoomForExtraLength(startPos, len, this);
+      this.pos = startPos - 1;
+      this.writeVarint(len);
+      this.pos += len;
+    }
+    /** @param {number} val */
+    writeFloat(val) {
+      this.realloc(4);
+      this.dataView.setFloat32(this.pos, val, true);
+      this.pos += 4;
+    }
+    /** @param {number} val */
+    writeDouble(val) {
+      this.realloc(8);
+      this.dataView.setFloat64(this.pos, val, true);
+      this.pos += 8;
+    }
+    /** @param {Uint8Array} buffer */
+    writeBytes(buffer) {
+      const len = buffer.length;
+      this.writeVarint(len);
+      this.realloc(len);
+      for (let i3 = 0; i3 < len; i3++) this.buf[this.pos++] = buffer[i3];
+    }
+    /**
+     * @template T
+     * @param {(obj: T, pbf: Pbf) => void} fn
+     * @param {T} obj
+     */
+    writeRawMessage(fn, obj) {
+      this.pos++;
+      const startPos = this.pos;
+      fn(obj, this);
+      const len = this.pos - startPos;
+      if (len >= 128) makeRoomForExtraLength(startPos, len, this);
+      this.pos = startPos - 1;
+      this.writeVarint(len);
+      this.pos += len;
+    }
+    /**
+     * @template T
+     * @param {number} tag
+     * @param {(obj: T, pbf: Pbf) => void} fn
+     * @param {T} obj
+     */
+    writeMessage(tag2, fn, obj) {
+      this.writeTag(tag2, PBF_BYTES);
+      this.writeRawMessage(fn, obj);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedVarint(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedVarint, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedSVarint(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedSVarint, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {boolean[]} arr
+     */
+    writePackedBoolean(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedBoolean, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedFloat(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedFloat, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedDouble(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedDouble, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedFixed32(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedFixed32, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedSFixed32(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedSFixed32, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedFixed64(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedFixed64, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedSFixed64(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedSFixed64, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {Uint8Array} buffer
+     */
+    writeBytesField(tag2, buffer) {
+      this.writeTag(tag2, PBF_BYTES);
+      this.writeBytes(buffer);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeFixed32Field(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED32);
+      this.writeFixed32(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeSFixed32Field(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED32);
+      this.writeSFixed32(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeFixed64Field(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED64);
+      this.writeFixed64(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeSFixed64Field(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED64);
+      this.writeSFixed64(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeVarintField(tag2, val) {
+      this.writeTag(tag2, PBF_VARINT);
+      this.writeVarint(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeSVarintField(tag2, val) {
+      this.writeTag(tag2, PBF_VARINT);
+      this.writeSVarint(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {string} str
+     */
+    writeStringField(tag2, str) {
+      this.writeTag(tag2, PBF_BYTES);
+      this.writeString(str);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeFloatField(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED32);
+      this.writeFloat(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeDoubleField(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED64);
+      this.writeDouble(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {boolean} val
+     */
+    writeBooleanField(tag2, val) {
+      this.writeVarintField(tag2, +val);
+    }
+  };
+  function readVarintRemainder(l2, s2, p2) {
+    const buf = p2.buf;
+    let h2, b2;
+    b2 = buf[p2.pos++];
+    h2 = (b2 & 112) >> 4;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 127) << 3;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 127) << 10;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 127) << 17;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 127) << 24;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 1) << 31;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    throw new Error("Expected varint not more than 10 bytes");
+  }
+  function toNum(low, high, isSigned) {
+    return isSigned ? high * 4294967296 + (low >>> 0) : (high >>> 0) * 4294967296 + (low >>> 0);
+  }
+  function writeBigVarint(val, pbf) {
+    let low, high;
+    if (val >= 0) {
+      low = val % 4294967296 | 0;
+      high = val / 4294967296 | 0;
+    } else {
+      low = ~(-val % 4294967296);
+      high = ~(-val / 4294967296);
+      if (low ^ 4294967295) {
+        low = low + 1 | 0;
+      } else {
+        low = 0;
+        high = high + 1 | 0;
+      }
+    }
+    if (val >= 18446744073709552e3 || val < -18446744073709552e3) {
+      throw new Error("Given varint doesn't fit into 10 bytes");
+    }
+    pbf.realloc(10);
+    writeBigVarintLow(low, high, pbf);
+    writeBigVarintHigh(high, pbf);
+  }
+  function writeBigVarintLow(low, high, pbf) {
+    pbf.buf[pbf.pos++] = low & 127 | 128;
+    low >>>= 7;
+    pbf.buf[pbf.pos++] = low & 127 | 128;
+    low >>>= 7;
+    pbf.buf[pbf.pos++] = low & 127 | 128;
+    low >>>= 7;
+    pbf.buf[pbf.pos++] = low & 127 | 128;
+    low >>>= 7;
+    pbf.buf[pbf.pos] = low & 127;
+  }
+  function writeBigVarintHigh(high, pbf) {
+    const lsb = (high & 7) << 4;
+    pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127;
+  }
+  function makeRoomForExtraLength(startPos, len, pbf) {
+    const extraLen = len <= 16383 ? 1 : len <= 2097151 ? 2 : len <= 268435455 ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
+    pbf.realloc(extraLen);
+    for (let i3 = pbf.pos - 1; i3 >= startPos; i3--) pbf.buf[i3 + extraLen] = pbf.buf[i3];
+  }
+  function writePackedVarint(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeVarint(arr[i3]);
+  }
+  function writePackedSVarint(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeSVarint(arr[i3]);
+  }
+  function writePackedFloat(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeFloat(arr[i3]);
+  }
+  function writePackedDouble(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeDouble(arr[i3]);
+  }
+  function writePackedBoolean(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeBoolean(arr[i3]);
+  }
+  function writePackedFixed32(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeFixed32(arr[i3]);
+  }
+  function writePackedSFixed32(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeSFixed32(arr[i3]);
+  }
+  function writePackedFixed64(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeFixed64(arr[i3]);
+  }
+  function writePackedSFixed64(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeSFixed64(arr[i3]);
+  }
+  function readUtf8(buf, pos, end) {
+    let str = "";
+    let i3 = pos;
+    while (i3 < end) {
+      const b0 = buf[i3];
+      let c2 = null;
+      let bytesPerSequence = b0 > 239 ? 4 : b0 > 223 ? 3 : b0 > 191 ? 2 : 1;
+      if (i3 + bytesPerSequence > end) break;
+      let b1, b2, b3;
+      if (bytesPerSequence === 1) {
+        if (b0 < 128) {
+          c2 = b0;
+        }
+      } else if (bytesPerSequence === 2) {
+        b1 = buf[i3 + 1];
+        if ((b1 & 192) === 128) {
+          c2 = (b0 & 31) << 6 | b1 & 63;
+          if (c2 <= 127) {
+            c2 = null;
+          }
+        }
+      } else if (bytesPerSequence === 3) {
+        b1 = buf[i3 + 1];
+        b2 = buf[i3 + 2];
+        if ((b1 & 192) === 128 && (b2 & 192) === 128) {
+          c2 = (b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63;
+          if (c2 <= 2047 || c2 >= 55296 && c2 <= 57343) {
+            c2 = null;
+          }
+        }
+      } else if (bytesPerSequence === 4) {
+        b1 = buf[i3 + 1];
+        b2 = buf[i3 + 2];
+        b3 = buf[i3 + 3];
+        if ((b1 & 192) === 128 && (b2 & 192) === 128 && (b3 & 192) === 128) {
+          c2 = (b0 & 15) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63;
+          if (c2 <= 65535 || c2 >= 1114112) {
+            c2 = null;
+          }
+        }
+      }
+      if (c2 === null) {
+        c2 = 65533;
+        bytesPerSequence = 1;
+      } else if (c2 > 65535) {
+        c2 -= 65536;
+        str += String.fromCharCode(c2 >>> 10 & 1023 | 55296);
+        c2 = 56320 | c2 & 1023;
+      }
+      str += String.fromCharCode(c2);
+      i3 += bytesPerSequence;
+    }
+    return str;
+  }
+  function writeUtf8(buf, str, pos) {
+    for (let i3 = 0, c2, lead; i3 < str.length; i3++) {
+      c2 = str.charCodeAt(i3);
+      if (c2 > 55295 && c2 < 57344) {
+        if (lead) {
+          if (c2 < 56320) {
+            buf[pos++] = 239;
+            buf[pos++] = 191;
+            buf[pos++] = 189;
+            lead = c2;
+            continue;
+          } else {
+            c2 = lead - 55296 << 10 | c2 - 56320 | 65536;
+            lead = null;
+          }
+        } else {
+          if (c2 > 56319 || i3 + 1 === str.length) {
+            buf[pos++] = 239;
+            buf[pos++] = 191;
+            buf[pos++] = 189;
+          } else {
+            lead = c2;
+          }
+          continue;
+        }
+      } else if (lead) {
+        buf[pos++] = 239;
+        buf[pos++] = 191;
+        buf[pos++] = 189;
+        lead = null;
+      }
+      if (c2 < 128) {
+        buf[pos++] = c2;
+      } else {
+        if (c2 < 2048) {
+          buf[pos++] = c2 >> 6 | 192;
+        } else {
+          if (c2 < 65536) {
+            buf[pos++] = c2 >> 12 | 224;
+          } else {
+            buf[pos++] = c2 >> 18 | 240;
+            buf[pos++] = c2 >> 12 & 63 | 128;
+          }
+          buf[pos++] = c2 >> 6 & 63 | 128;
+        }
+        buf[pos++] = c2 & 63 | 128;
+      }
+    }
+    return pos;
+  }
+
+  // node_modules/@mapbox/point-geometry/index.js
+  function Point(x2, y2) {
+    this.x = x2;
+    this.y = y2;
+  }
+  Point.prototype = {
+    /**
+     * Clone this point, returning a new point that can be modified
+     * without affecting the old one.
+     * @return {Point} the clone
+     */
+    clone() {
+      return new Point(this.x, this.y);
+    },
+    /**
+     * Add this point's x & y coordinates to another point,
+     * yielding a new point.
+     * @param {Point} p the other point
+     * @return {Point} output point
+     */
+    add(p2) {
+      return this.clone()._add(p2);
+    },
+    /**
+     * Subtract this point's x & y coordinates to from point,
+     * yielding a new point.
+     * @param {Point} p the other point
+     * @return {Point} output point
+     */
+    sub(p2) {
+      return this.clone()._sub(p2);
+    },
+    /**
+     * Multiply this point's x & y coordinates by point,
+     * yielding a new point.
+     * @param {Point} p the other point
+     * @return {Point} output point
+     */
+    multByPoint(p2) {
+      return this.clone()._multByPoint(p2);
+    },
+    /**
+     * Divide this point's x & y coordinates by point,
+     * yielding a new point.
+     * @param {Point} p the other point
+     * @return {Point} output point
+     */
+    divByPoint(p2) {
+      return this.clone()._divByPoint(p2);
+    },
+    /**
+     * Multiply this point's x & y coordinates by a factor,
+     * yielding a new point.
+     * @param {number} k factor
+     * @return {Point} output point
+     */
+    mult(k2) {
+      return this.clone()._mult(k2);
+    },
+    /**
+     * Divide this point's x & y coordinates by a factor,
+     * yielding a new point.
+     * @param {number} k factor
+     * @return {Point} output point
+     */
+    div(k2) {
+      return this.clone()._div(k2);
+    },
+    /**
+     * Rotate this point around the 0, 0 origin by an angle a,
+     * given in radians
+     * @param {number} a angle to rotate around, in radians
+     * @return {Point} output point
+     */
+    rotate(a2) {
+      return this.clone()._rotate(a2);
+    },
+    /**
+     * Rotate this point around p point by an angle a,
+     * given in radians
+     * @param {number} a angle to rotate around, in radians
+     * @param {Point} p Point to rotate around
+     * @return {Point} output point
+     */
+    rotateAround(a2, p2) {
+      return this.clone()._rotateAround(a2, p2);
+    },
+    /**
+     * Multiply this point by a 4x1 transformation matrix
+     * @param {[number, number, number, number]} m transformation matrix
+     * @return {Point} output point
+     */
+    matMult(m2) {
+      return this.clone()._matMult(m2);
+    },
+    /**
+     * Calculate this point but as a unit vector from 0, 0, meaning
+     * that the distance from the resulting point to the 0, 0
+     * coordinate will be equal to 1 and the angle from the resulting
+     * point to the 0, 0 coordinate will be the same as before.
+     * @return {Point} unit vector point
+     */
+    unit() {
+      return this.clone()._unit();
+    },
+    /**
+     * Compute a perpendicular point, where the new y coordinate
+     * is the old x coordinate and the new x coordinate is the old y
+     * coordinate multiplied by -1
+     * @return {Point} perpendicular point
+     */
+    perp() {
+      return this.clone()._perp();
+    },
+    /**
+     * Return a version of this point with the x & y coordinates
+     * rounded to integers.
+     * @return {Point} rounded point
+     */
+    round() {
+      return this.clone()._round();
+    },
+    /**
+     * Return the magnitude of this point: this is the Euclidean
+     * distance from the 0, 0 coordinate to this point's x and y
+     * coordinates.
+     * @return {number} magnitude
+     */
+    mag() {
+      return Math.sqrt(this.x * this.x + this.y * this.y);
+    },
+    /**
+     * Judge whether this point is equal to another point, returning
+     * true or false.
+     * @param {Point} other the other point
+     * @return {boolean} whether the points are equal
+     */
+    equals(other) {
+      return this.x === other.x && this.y === other.y;
+    },
+    /**
+     * Calculate the distance from this point to another point
+     * @param {Point} p the other point
+     * @return {number} distance
+     */
+    dist(p2) {
+      return Math.sqrt(this.distSqr(p2));
+    },
+    /**
+     * Calculate the distance from this point to another point,
+     * without the square root step. Useful if you're comparing
+     * relative distances.
+     * @param {Point} p the other point
+     * @return {number} distance
+     */
+    distSqr(p2) {
+      const dx = p2.x - this.x, dy = p2.y - this.y;
+      return dx * dx + dy * dy;
+    },
+    /**
+     * Get the angle from the 0, 0 coordinate to this point, in radians
+     * coordinates.
+     * @return {number} angle
+     */
+    angle() {
+      return Math.atan2(this.y, this.x);
+    },
+    /**
+     * Get the angle from this point to another point, in radians
+     * @param {Point} b the other point
+     * @return {number} angle
+     */
+    angleTo(b2) {
+      return Math.atan2(this.y - b2.y, this.x - b2.x);
+    },
+    /**
+     * Get the angle between this point and another point, in radians
+     * @param {Point} b the other point
+     * @return {number} angle
+     */
+    angleWith(b2) {
+      return this.angleWithSep(b2.x, b2.y);
+    },
+    /**
+     * Find the angle of the two vectors, solving the formula for
+     * the cross product a x b = |a||b|sin(θ) for θ.
+     * @param {number} x the x-coordinate
+     * @param {number} y the y-coordinate
+     * @return {number} the angle in radians
+     */
+    angleWithSep(x2, y2) {
+      return Math.atan2(
+        this.x * y2 - this.y * x2,
+        this.x * x2 + this.y * y2
+      );
+    },
+    /** @param {[number, number, number, number]} m */
+    _matMult(m2) {
+      const x2 = m2[0] * this.x + m2[1] * this.y, y2 = m2[2] * this.x + m2[3] * this.y;
+      this.x = x2;
+      this.y = y2;
+      return this;
+    },
+    /** @param {Point} p */
+    _add(p2) {
+      this.x += p2.x;
+      this.y += p2.y;
+      return this;
+    },
+    /** @param {Point} p */
+    _sub(p2) {
+      this.x -= p2.x;
+      this.y -= p2.y;
+      return this;
+    },
+    /** @param {number} k */
+    _mult(k2) {
+      this.x *= k2;
+      this.y *= k2;
+      return this;
+    },
+    /** @param {number} k */
+    _div(k2) {
+      this.x /= k2;
+      this.y /= k2;
+      return this;
+    },
+    /** @param {Point} p */
+    _multByPoint(p2) {
+      this.x *= p2.x;
+      this.y *= p2.y;
+      return this;
+    },
+    /** @param {Point} p */
+    _divByPoint(p2) {
+      this.x /= p2.x;
+      this.y /= p2.y;
+      return this;
+    },
+    _unit() {
+      this._div(this.mag());
+      return this;
+    },
+    _perp() {
+      const y2 = this.y;
+      this.y = this.x;
+      this.x = -y2;
+      return this;
+    },
+    /** @param {number} angle */
+    _rotate(angle2) {
+      const cos2 = Math.cos(angle2), sin2 = Math.sin(angle2), x2 = cos2 * this.x - sin2 * this.y, y2 = sin2 * this.x + cos2 * this.y;
+      this.x = x2;
+      this.y = y2;
+      return this;
+    },
+    /**
+     * @param {number} angle
+     * @param {Point} p
+     */
+    _rotateAround(angle2, p2) {
+      const cos2 = Math.cos(angle2), sin2 = Math.sin(angle2), x2 = p2.x + cos2 * (this.x - p2.x) - sin2 * (this.y - p2.y), y2 = p2.y + sin2 * (this.x - p2.x) + cos2 * (this.y - p2.y);
+      this.x = x2;
+      this.y = y2;
+      return this;
+    },
+    _round() {
+      this.x = Math.round(this.x);
+      this.y = Math.round(this.y);
+      return this;
+    },
+    constructor: Point
+  };
+  Point.convert = function(p2) {
+    if (p2 instanceof Point) {
+      return (
+        /** @type {Point} */
+        p2
+      );
+    }
+    if (Array.isArray(p2)) {
+      return new Point(+p2[0], +p2[1]);
+    }
+    if (p2.x !== void 0 && p2.y !== void 0) {
+      return new Point(+p2.x, +p2.y);
+    }
+    throw new Error("Expected [x, y] or {x, y} point format");
+  };
+
+  // node_modules/@mapbox/vector-tile/index.js
+  var VectorTileFeature = class {
+    /**
+     * @param {Pbf} pbf
+     * @param {number} end
+     * @param {number} extent
+     * @param {string[]} keys
+     * @param {unknown[]} values
+     */
+    constructor(pbf, end, extent, keys2, values) {
+      this.properties = {};
+      this.extent = extent;
+      this.type = 0;
+      this.id = void 0;
+      this._pbf = pbf;
+      this._geometry = -1;
+      this._keys = keys2;
+      this._values = values;
+      pbf.readFields(readFeature, this, end);
+    }
+    loadGeometry() {
+      const pbf = this._pbf;
+      pbf.pos = this._geometry;
+      const end = pbf.readVarint() + pbf.pos;
+      const lines = [];
+      let line;
+      let cmd = 1;
+      let length2 = 0;
+      let x2 = 0;
+      let y2 = 0;
+      while (pbf.pos < end) {
+        if (length2 <= 0) {
+          const cmdLen = pbf.readVarint();
+          cmd = cmdLen & 7;
+          length2 = cmdLen >> 3;
+        }
+        length2--;
+        if (cmd === 1 || cmd === 2) {
+          x2 += pbf.readSVarint();
+          y2 += pbf.readSVarint();
+          if (cmd === 1) {
+            if (line) lines.push(line);
+            line = [];
+          }
+          if (line) line.push(new Point(x2, y2));
+        } else if (cmd === 7) {
+          if (line) {
+            line.push(line[0].clone());
+          }
+        } else {
+          throw new Error("unknown command ".concat(cmd));
+        }
+      }
+      if (line) lines.push(line);
+      return lines;
+    }
+    bbox() {
+      const pbf = this._pbf;
+      pbf.pos = this._geometry;
+      const end = pbf.readVarint() + pbf.pos;
+      let cmd = 1, length2 = 0, x2 = 0, y2 = 0, x12 = Infinity, x22 = -Infinity, y12 = Infinity, y22 = -Infinity;
+      while (pbf.pos < end) {
+        if (length2 <= 0) {
+          const cmdLen = pbf.readVarint();
+          cmd = cmdLen & 7;
+          length2 = cmdLen >> 3;
+        }
+        length2--;
+        if (cmd === 1 || cmd === 2) {
+          x2 += pbf.readSVarint();
+          y2 += pbf.readSVarint();
+          if (x2 < x12) x12 = x2;
+          if (x2 > x22) x22 = x2;
+          if (y2 < y12) y12 = y2;
+          if (y2 > y22) y22 = y2;
+        } else if (cmd !== 7) {
+          throw new Error("unknown command ".concat(cmd));
+        }
+      }
+      return [x12, y12, x22, y22];
+    }
+    /**
+     * @param {number} x
+     * @param {number} y
+     * @param {number} z
+     * @return {Feature}
+     */
+    toGeoJSON(x2, y2, z2) {
+      const size = this.extent * Math.pow(2, z2), x05 = this.extent * x2, y05 = this.extent * y2, vtCoords = this.loadGeometry();
+      function projectPoint(p2) {
+        return [
+          (p2.x + x05) * 360 / size - 180,
+          360 / Math.PI * Math.atan(Math.exp((1 - (p2.y + y05) * 2 / size) * Math.PI)) - 90
+        ];
+      }
+      function projectLine(line) {
+        return line.map(projectPoint);
+      }
+      let geometry;
+      if (this.type === 1) {
+        const points = [];
+        for (const line of vtCoords) {
+          points.push(line[0]);
+        }
+        const coordinates = projectLine(points);
+        geometry = points.length === 1 ? { type: "Point", coordinates: coordinates[0] } : { type: "MultiPoint", coordinates };
+      } else if (this.type === 2) {
+        const coordinates = vtCoords.map(projectLine);
+        geometry = coordinates.length === 1 ? { type: "LineString", coordinates: coordinates[0] } : { type: "MultiLineString", coordinates };
+      } else if (this.type === 3) {
+        const polygons = classifyRings(vtCoords);
+        const coordinates = [];
+        for (const polygon2 of polygons) {
+          coordinates.push(polygon2.map(projectLine));
+        }
+        geometry = coordinates.length === 1 ? { type: "Polygon", coordinates: coordinates[0] } : { type: "MultiPolygon", coordinates };
+      } else {
+        throw new Error("unknown feature type");
+      }
+      const result = {
+        type: "Feature",
+        geometry,
+        properties: this.properties
+      };
+      if (this.id != null) {
+        result.id = this.id;
+      }
+      return result;
+    }
+  };
+  VectorTileFeature.types = ["Unknown", "Point", "LineString", "Polygon"];
+  function readFeature(tag2, feature3, pbf) {
+    if (tag2 === 1) feature3.id = pbf.readVarint();
+    else if (tag2 === 2) readTag(pbf, feature3);
+    else if (tag2 === 3) feature3.type = /** @type {0 | 1 | 2 | 3} */
+    pbf.readVarint();
+    else if (tag2 === 4) feature3._geometry = pbf.pos;
+  }
+  function readTag(pbf, feature3) {
+    const end = pbf.readVarint() + pbf.pos;
+    while (pbf.pos < end) {
+      const key = feature3._keys[pbf.readVarint()], value = feature3._values[pbf.readVarint()];
+      feature3.properties[key] = value;
+    }
+  }
+  function classifyRings(rings) {
+    const len = rings.length;
+    if (len <= 1) return [rings];
+    const polygons = [];
+    let polygon2, ccw;
+    for (let i3 = 0; i3 < len; i3++) {
+      const area = signedArea(rings[i3]);
+      if (area === 0) continue;
+      if (ccw === void 0) ccw = area < 0;
+      if (ccw === area < 0) {
+        if (polygon2) polygons.push(polygon2);
+        polygon2 = [rings[i3]];
+      } else if (polygon2) {
+        polygon2.push(rings[i3]);
+      }
+    }
+    if (polygon2) polygons.push(polygon2);
+    return polygons;
+  }
+  function signedArea(ring) {
+    let sum = 0;
+    for (let i3 = 0, len = ring.length, j2 = len - 1, p1, p2; i3 < len; j2 = i3++) {
+      p1 = ring[i3];
+      p2 = ring[j2];
+      sum += (p2.x - p1.x) * (p1.y + p2.y);
+    }
+    return sum;
+  }
+  var VectorTileLayer = class {
+    /**
+     * @param {Pbf} pbf
+     * @param {number} [end]
+     */
+    constructor(pbf, end) {
+      this.version = 1;
+      this.name = "";
+      this.extent = 4096;
+      this.length = 0;
+      this._pbf = pbf;
+      this._keys = [];
+      this._values = [];
+      this._features = [];
+      pbf.readFields(readLayer, this, end);
+      this.length = this._features.length;
+    }
+    /** return feature `i` from this layer as a `VectorTileFeature`
+     * @param {number} i
+     */
+    feature(i3) {
+      if (i3 < 0 || i3 >= this._features.length) throw new Error("feature index out of bounds");
+      this._pbf.pos = this._features[i3];
+      const end = this._pbf.readVarint() + this._pbf.pos;
+      return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
+    }
+  };
+  function readLayer(tag2, layer, pbf) {
+    if (tag2 === 15) layer.version = pbf.readVarint();
+    else if (tag2 === 1) layer.name = pbf.readString();
+    else if (tag2 === 5) layer.extent = pbf.readVarint();
+    else if (tag2 === 2) layer._features.push(pbf.pos);
+    else if (tag2 === 3) layer._keys.push(pbf.readString());
+    else if (tag2 === 4) layer._values.push(readValueMessage(pbf));
+  }
+  function readValueMessage(pbf) {
+    let value = null;
+    const end = pbf.readVarint() + pbf.pos;
+    while (pbf.pos < end) {
+      const tag2 = pbf.readVarint() >> 3;
+      value = tag2 === 1 ? pbf.readString() : tag2 === 2 ? pbf.readFloat() : tag2 === 3 ? pbf.readDouble() : tag2 === 4 ? pbf.readVarint64() : tag2 === 5 ? pbf.readVarint() : tag2 === 6 ? pbf.readSVarint() : tag2 === 7 ? pbf.readBoolean() : null;
+    }
+    return value;
+  }
+  var VectorTile = class {
+    /**
+     * @param {Pbf} pbf
+     * @param {number} [end]
+     */
+    constructor(pbf, end) {
+      this.layers = pbf.readFields(readTile, {}, end);
+    }
+  };
+  function readTile(tag2, layers, pbf) {
+    if (tag2 === 3) {
+      const layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
+      if (layer.length) layers[layer.name] = layer;
+    }
+  }
+
   // modules/services/mapillary.js
-  var import_pbf = __toESM(require_pbf());
-  var import_rbush4 = __toESM(require_rbush_min());
-  var import_vector_tile = __toESM(require_vector_tile());
   var accessToken = "MLY|4100327730013843|5bb78b81720791946a9a7b956c57b7cf";
   var apiUrl = "https://graph.mapillary.com/";
   var baseTileUrl = "https://tiles.mapillary.com/maps/vtp";
   var viewercss = "mapillary-js/mapillary.css";
   var viewerjs = "mapillary-js/mapillary.js";
   var minZoom = 14;
-  var dispatch5 = dispatch_default("change", "loadedImages", "loadedSigns", "loadedMapFeatures", "bearingChanged", "imageChanged");
+  var dispatch4 = dispatch_default("change", "loadedImages", "loadedSigns", "loadedMapFeatures", "bearingChanged", "imageChanged");
   var _loadViewerPromise;
   var _mlyActiveImage;
   var _mlyCache;
   var _mlyShowSignDetections = false;
   var _mlyViewer;
   var _mlyViewerFilter = ["all"];
+  var _isViewerOpen = false;
   function loadTiles(which, url, maxZoom2, projection2) {
-    const tiler9 = utilTiler().zoomExtent([minZoom, maxZoom2]).skipNullIsland(true);
-    const tiles = tiler9.getTiles(projection2);
+    const tiler8 = utilTiler().zoomExtent([minZoom, maxZoom2]).skipNullIsland(true);
+    const tiles = tiler8.getTiles(projection2);
     tiles.forEach(function(tile) {
       loadTile(which, url, tile);
     });
   function loadTile(which, url, tile) {
     const cache = _mlyCache.requests;
     const tileId = "".concat(tile.id, "-").concat(which);
-    if (cache.loaded[tileId] || cache.inflight[tileId])
-      return;
+    if (cache.loaded[tileId] || cache.inflight[tileId]) return;
     const controller = new AbortController();
     cache.inflight[tileId] = controller;
     const requestUrl = url.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace("{z}", tile.xyz[2]);
       }
       loadTileDataToCache(data, tile, which);
       if (which === "images") {
-        dispatch5.call("loadedImages");
+        dispatch4.call("loadedImages");
       } else if (which === "signs") {
-        dispatch5.call("loadedSigns");
+        dispatch4.call("loadedSigns");
       } else if (which === "points") {
-        dispatch5.call("loadedMapFeatures");
+        dispatch4.call("loadedMapFeatures");
       }
     }).catch(function() {
       cache.loaded[tileId] = true;
     });
   }
   function loadTileDataToCache(data, tile, which) {
-    const vectorTile = new import_vector_tile.VectorTile(new import_pbf.default(data));
+    const vectorTile = new VectorTile(new Pbf(data));
     let features, cache, layer, i3, feature3, loc, d2;
     if (vectorTile.layers.hasOwnProperty("image")) {
       features = [];
   function partitionViewport(projection2) {
     const z2 = geoScaleToZoom(projection2.scale());
     const z22 = Math.ceil(z2 * 2) / 2 + 2.5;
-    const tiler9 = utilTiler().zoomExtent([z22, z22]);
-    return tiler9.getTiles(projection2).map(function(tile) {
+    const tiler8 = utilTiler().zoomExtent([z22, z22]);
+    return tiler8.getTiles(projection2).map(function(tile) {
       return tile.extent;
     });
   }
       if (!_mlyCache) {
         this.reset();
       }
-      this.event = utilRebind(this, dispatch5, "on");
+      this.event = utilRebind(this, dispatch4, "on");
     },
     // Reset cache and state
     reset: function() {
         });
       }
       _mlyCache = {
-        images: { rtree: new import_rbush4.default(), forImageId: {} },
+        images: { rtree: new RBush(), forImageId: {} },
         image_detections: { forImageId: {} },
-        signs: { rtree: new import_rbush4.default() },
-        points: { rtree: new import_rbush4.default() },
-        sequences: { rtree: new import_rbush4.default(), lineString: {} },
+        signs: { rtree: new RBush() },
+        points: { rtree: new RBush() },
+        sequences: { rtree: new RBush(), lineString: {} },
         requests: { loaded: {}, inflight: {} }
       };
       _mlyActiveImage = null;
     },
     // Return a promise that resolves when the image viewer (Mapillary JS) library has finished loading
     ensureViewerLoaded: function(context) {
-      if (_loadViewerPromise)
-        return _loadViewerPromise;
+      if (_loadViewerPromise) return _loadViewerPromise;
       const wrap2 = context.container().select(".photoviewer").selectAll(".mly-wrapper").data([0]);
       wrap2.enter().append("div").attr("id", "ideditor-mly").attr("class", "photo-wrapper mly-wrapper").classed("hide", true);
       const that = this;
         let loadedCount = 0;
         function loaded() {
           loadedCount += 1;
-          if (loadedCount === 2)
-            resolve();
+          if (loadedCount === 2) resolve();
         }
         const head = select_default2("head");
         head.selectAll("#ideditor-mapillary-viewercss").data([0]).enter().append("link").attr("id", "ideditor-mapillary-viewercss").attr("rel", "stylesheet").attr("crossorigin", "anonymous").attr("href", context.asset(viewercss)).on("load.serviceMapillary", loaded).on("error.serviceMapillary", function() {
       const fromDate = context.photos().fromDate();
       const toDate = context.photos().toDate();
       const filter2 = ["all"];
-      if (!showsPano)
-        filter2.push(["!=", "cameraType", "spherical"]);
-      if (!showsFlat && showsPano)
-        filter2.push(["==", "pano", true]);
+      if (!showsPano) filter2.push(["!=", "cameraType", "spherical"]);
+      if (!showsFlat && showsPano) filter2.push(["==", "pano", true]);
       if (fromDate) {
         filter2.push([">=", "capturedAt", new Date(fromDate).getTime()]);
       }
         wrap2.selectAll(".photo-wrapper.mly-wrapper").classed("hide", false);
         _mlyViewer.resize();
       }
+      _isViewerOpen = true;
       return this;
     },
     // Hide the image viewer and resets map markers
         _mlyViewer.getComponent("sequence").stop();
       }
       const viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(null);
+      if (!viewer.empty()) viewer.datum(null);
       viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
       this.updateUrlImage(null);
-      dispatch5.call("imageChanged");
-      dispatch5.call("loadedMapFeatures");
-      dispatch5.call("loadedSigns");
+      dispatch4.call("imageChanged");
+      dispatch4.call("loadedMapFeatures");
+      dispatch4.call("loadedSigns");
+      _isViewerOpen = false;
       return this.setStyles(context, null);
     },
+    // Get viewer status
+    isViewerOpen: function() {
+      return _isViewerOpen;
+    },
     // Update the URL with current image id
     updateUrlImage: function(imageId) {
       if (!window.mocha) {
     // Initialize image viewer (Mapillar JS)
     initViewer: function(context) {
       const that = this;
-      if (!window.mapillary)
-        return;
+      if (!window.mapillary) return;
       const opts = {
         accessToken,
         component: {
         _mlyViewer.setFilter(_mlyViewerFilter);
       }
       context.ui().photoviewer.on("resize.mapillary", function() {
-        if (_mlyViewer)
-          _mlyViewer.resize();
+        if (_mlyViewer) _mlyViewer.resize();
       });
       function imageChanged(node) {
         that.resetTags();
         if (_mlyShowFeatureDetections || _mlyShowSignDetections) {
           that.updateDetections(image.id, "".concat(apiUrl, "/").concat(image.id, "/detections?access_token=").concat(accessToken, "&fields=id,image,geometry,value"));
         }
-        dispatch5.call("imageChanged");
+        dispatch4.call("imageChanged");
       }
       function bearingChanged(e3) {
-        dispatch5.call("bearingChanged", void 0, e3);
+        dispatch4.call("bearingChanged", void 0, e3);
       }
     },
     // Move to an image
     },
     // Get detections for the current image and shows them in the image viewer
     updateDetections: function(imageId, url) {
-      if (!_mlyViewer || _mlyFallback)
-        return;
-      if (!imageId)
-        return;
+      if (!_mlyViewer || _mlyFallback) return;
+      if (!imageId) return;
       const cache = _mlyCache.image_detections;
       if (cache.forImageId[imageId]) {
         showDetections(_mlyCache.image_detections.forImageId[imageId]);
       }
       function makeTag(data) {
         const valueParts = data.value.split("--");
-        if (!valueParts.length)
-          return;
+        if (!valueParts.length) return;
         let tag2;
         let text;
         let color2 = 16777215;
         for (var i3 = 0; i3 < decodedGeometry.length; i3++) {
           uintArray[i3] = decodedGeometry.charCodeAt(i3);
         }
-        const tile = new import_vector_tile.VectorTile(new import_pbf.default(uintArray.buffer));
+        const tile = new VectorTile(new Pbf(uintArray.buffer));
         const layer = tile.layers["mpy-or"];
         const geometries = layer.feature(0).loadGeometry();
-        const polygon2 = geometries.map((ring) => ring.map((point2) => [point2.x / layer.extent, point2.y / layer.extent]));
+        const polygon2 = geometries.map((ring) => ring.map((point) => [point.x / layer.extent, point.y / layer.extent]));
         tag2 = new mapillary.OutlineTag(
           data.id,
           new mapillary.PolygonGeometry(polygon2[0]),
     }
   };
 
-  // modules/services/nominatim.js
-  var import_rbush7 = __toESM(require_rbush_min());
-
   // modules/core/difference.js
   var import_fast_deep_equal3 = __toESM(require_fast_deep_equal());
   function coreDifference(base, head) {
     function checkEntityID(id2) {
       var h2 = head.entities[id2];
       var b2 = base.entities[id2];
-      if (h2 === b2)
-        return;
-      if (_changes[id2])
-        return;
+      if (h2 === b2) return;
+      if (_changes[id2]) return;
       if (!h2 && b2) {
         _changes[id2] = { base: b2, head: h2 };
         _didChange.deletion = true;
           var ids = utilArrayUnion(mh, mb);
           for (i3 = 0; i3 < ids.length; i3++) {
             var member = head.hasEntity(ids[i3]);
-            if (!member)
-              continue;
-            if (extent && !member.intersects(extent, head))
-              continue;
+            if (!member) continue;
+            if (extent && !member.intersects(extent, head)) continue;
             result[ids[i3]] = member;
           }
         }
       function addParents(parents, result2) {
         for (var i4 = 0; i4 < parents.length; i4++) {
           var parent = parents[i4];
-          if (parent.id in result2)
-            continue;
+          if (parent.id in result2) continue;
           result2[parent.id] = parent;
           addParents(head.parentRelations(parent), result2);
         }
   }
 
   // modules/core/tree.js
-  var import_rbush5 = __toESM(require_rbush_min());
   function coreTree(head) {
-    var _rtree = new import_rbush5.default();
+    var _rtree = new RBush();
     var _bboxes = {};
-    var _segmentsRTree = new import_rbush5.default();
+    var _segmentsRTree = new RBush();
     var _segmentsBBoxes = {};
     var _segmentsByWayId = {};
     var tree = {};
     }
     function segmentBBox(segment) {
       var extent = segment.extent(head);
-      if (!extent)
-        return null;
+      if (!extent) return null;
       var bbox2 = extent.bbox();
       bbox2.segment = segment;
       _segmentsBBoxes[segment.id] = bbox2;
           segments = segments.concat(entitySegments);
         }
       });
-      if (segments.length)
-        _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
+      if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
     }
     function updateParents(entity, insertions, memo) {
       head.parentWays(entity).forEach(function(way) {
         updateParents(way, insertions, memo);
       });
       head.parentRelations(entity).forEach(function(relation) {
-        if (memo[entity.id])
-          return;
-        memo[entity.id] = true;
+        if (memo[relation.id]) return;
+        memo[relation.id] = true;
         if (_bboxes[relation.id]) {
           removeEntity(relation);
           insertions[relation.id] = relation;
       var insertions = {};
       for (var i3 = 0; i3 < entities.length; i3++) {
         var entity = entities[i3];
-        if (!entity.visible)
-          continue;
+        if (!entity.visible) continue;
         if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
           if (!force) {
             continue;
       return tree;
     };
     function updateToGraph(graph) {
-      if (graph === head)
-        return;
+      if (graph === head) return;
       var diff = coreDifference(head, graph);
       head = graph;
       var changed = diff.didChange;
-      if (!changed.addition && !changed.deletion && !changed.geometry)
-        return;
+      if (!changed.addition && !changed.deletion && !changed.geometry) return;
       var insertions = {};
       if (changed.deletion) {
         diff.deleted().forEach(function(entity) {
       return loading;
     };
     loading.message = function(val) {
-      if (!arguments.length)
-        return _message;
+      if (!arguments.length) return _message;
       _message = val;
       return loading;
     };
     loading.blocking = function(val) {
-      if (!arguments.length)
-        return _blocking;
+      if (!arguments.length) return _blocking;
       _blocking = val;
       return loading;
     };
           var origArguments = arguments;
           select_default2(document).transition("history.perform").duration(duration).ease(linear2).tween("history.tween", function() {
             return function(t2) {
-              if (t2 < 1)
-                _overwrite([action0], t2);
+              if (t2 < 1) _overwrite([action0], t2);
             };
           }).on("start", function() {
             _perform([action0], 0);
         var previous = previousStack.graph;
         while (_index > 0) {
           _index--;
-          if (_stack[_index].annotation)
-            break;
+          if (_stack[_index].annotation) break;
         }
         dispatch14.call("undone", this, _stack[_index], previousStack);
         return change(previous);
       undoAnnotation: function() {
         var i3 = _index;
         while (i3 >= 0) {
-          if (_stack[i3].annotation)
-            return _stack[i3].annotation;
+          if (_stack[i3].annotation) return _stack[i3].annotation;
           i3--;
         }
       },
       redoAnnotation: function() {
         var i3 = _index + 1;
         while (i3 <= _stack.length - 1) {
-          if (_stack[i3].annotation)
-            return _stack[i3].annotation;
+          if (_stack[i3].annotation) return _stack[i3].annotation;
           i3++;
         }
       },
         }
       },
       toJSON: function() {
-        if (!this.hasChanges())
-          return;
+        if (!this.hasChanges()) return;
         var allEntities = {};
         var baseEntities = {};
         var base = _stack[0];
             }
           });
           var x2 = {};
-          if (modified.length)
-            x2.modified = modified;
-          if (deleted.length)
-            x2.deleted = deleted;
-          if (i3.imageryUsed)
-            x2.imageryUsed = i3.imageryUsed;
-          if (i3.photoOverlaysUsed)
-            x2.photoOverlaysUsed = i3.photoOverlaysUsed;
-          if (i3.annotation)
-            x2.annotation = i3.annotation;
-          if (i3.transform)
-            x2.transform = i3.transform;
-          if (i3.selectedIDs)
-            x2.selectedIDs = i3.selectedIDs;
+          if (modified.length) x2.modified = modified;
+          if (deleted.length) x2.deleted = deleted;
+          if (i3.imageryUsed) x2.imageryUsed = i3.imageryUsed;
+          if (i3.photoOverlaysUsed) x2.photoOverlaysUsed = i3.photoOverlaysUsed;
+          if (i3.annotation) x2.annotation = i3.annotation;
+          if (i3.transform) x2.transform = i3.transform;
+          if (i3.selectedIDs) x2.selectedIDs = i3.selectedIDs;
           return x2;
         });
         return JSON.stringify({
         if (lock.locked() && // don't overwrite existing, unresolved changes
         !_hasUnresolvedRestorableChanges) {
           const success = corePreferences(getKey("saved_history"), history.toJSON() || null);
-          if (!success)
-            dispatch14.call("storage_error");
+          if (!success) dispatch14.call("storage_error");
         }
         return history;
       },
         if (lock.locked()) {
           _hasUnresolvedRestorableChanges = false;
           var json = this.savedHistoryJSON();
-          if (json)
-            history.fromJSON(json, true);
+          if (json) history.fromJSON(json, true);
         }
       },
       _getKey: getKey
       return node.tags.noexit === "yes" || node.tags.amenity === "parking_entrance" || node.tags.entrance && node.tags.entrance !== "no";
     }
     const validation = function checkAlmostJunction(entity, graph) {
-      if (!isHighway(entity))
-        return [];
-      if (entity.isDegenerate())
-        return [];
+      if (!isHighway(entity)) return [];
+      if (entity.isDegenerate()) return [];
       const tree = context.history().tree();
       const extendableNodeInfos = findConnectableEndNodesByExtension(entity);
       let issues = [];
       }
       function findConnectableEndNodesByExtension(way) {
         let results = [];
-        if (way.isClosed())
-          return results;
+        if (way.isClosed()) return results;
         let testNodes;
         const indices = [0, way.nodes.length - 1];
         indices.forEach((nodeIndex) => {
           const nodeID = way.nodes[nodeIndex];
           const node = graph.entity(nodeID);
-          if (!isExtendableCandidate(node, way))
-            return;
+          if (!isExtendableCandidate(node, way)) return;
           const connectionInfo = canConnectByExtend(way, nodeIndex);
-          if (!connectionInfo)
-            return;
+          if (!connectionInfo) return;
           testNodes = graph.childNodes(way).slice();
           testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc);
-          if (geoHasSelfIntersections(testNodes, nodeID))
-            return;
+          if (geoHasSelfIntersections(testNodes, nodeID)) return;
           results.push(connectionInfo);
         });
         return results;
             minAngle = diff;
           }
         });
-        if (minAngle <= SIG_ANGLE_TH)
-          return joinTo;
+        if (minAngle <= SIG_ANGLE_TH) return joinTo;
         return null;
       }
       function hasTag(tags, key) {
         return tags[key] !== void 0 && tags[key] !== "no";
       }
       function canConnectWays(way, way2) {
-        if (way.id === way2.id)
-          return true;
-        if ((hasTag(way.tags, "bridge") || hasTag(way2.tags, "bridge")) && !(hasTag(way.tags, "bridge") && hasTag(way2.tags, "bridge")))
-          return false;
-        if ((hasTag(way.tags, "tunnel") || hasTag(way2.tags, "tunnel")) && !(hasTag(way.tags, "tunnel") && hasTag(way2.tags, "tunnel")))
-          return false;
+        if (way.id === way2.id) return true;
+        if ((hasTag(way.tags, "bridge") || hasTag(way2.tags, "bridge")) && !(hasTag(way.tags, "bridge") && hasTag(way2.tags, "bridge"))) return false;
+        if ((hasTag(way.tags, "tunnel") || hasTag(way2.tags, "tunnel")) && !(hasTag(way.tags, "tunnel") && hasTag(way2.tags, "tunnel"))) return false;
         const layer1 = way.tags.layer || "0", layer2 = way2.tags.layer || "0";
-        if (layer1 !== layer2)
-          return false;
+        if (layer1 !== layer2) return false;
         const level1 = way.tags.level || "0", level2 = way2.tags.level || "0";
-        if (level1 !== level2)
-          return false;
+        if (level1 !== level2) return false;
         return true;
       }
       function canConnectByExtend(way, endNodeIdx) {
         for (let i3 = 0; i3 < segmentInfos.length; i3++) {
           let segmentInfo = segmentInfos[i3];
           let way2 = graph.entity(segmentInfo.wayId);
-          if (!isHighway(way2))
-            continue;
-          if (!canConnectWays(way, way2))
-            continue;
+          if (!isHighway(way2)) continue;
+          if (!canConnectWays(way, way2)) continue;
           let nAid = segmentInfo.nodes[0], nBid = segmentInfo.nodes[1];
-          if (nAid === tipNid || nBid === tipNid)
-            continue;
+          if (nAid === tipNid || nBid === tipNid) continue;
           let nA = graph.entity(nAid), nB = graph.entity(nBid);
           let crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
           if (crossLoc) {
         }
       }
       function wayTypeFor(way) {
-        if (way.tags.boundary && way.tags.boundary !== "no")
-          return "boundary";
-        if (way.tags.indoor && way.tags.indoor !== "no")
-          return "indoor";
-        if (way.tags.building && way.tags.building !== "no" || way.tags["building:part"] && way.tags["building:part"] !== "no")
-          return "building";
-        if (osmPathHighwayTagValues[way.tags.highway])
-          return "path";
+        if (way.tags.boundary && way.tags.boundary !== "no") return "boundary";
+        if (way.tags.indoor && way.tags.indoor !== "no") return "indoor";
+        if (way.tags.building && way.tags.building !== "no" || way.tags["building:part"] && way.tags["building:part"] !== "no") return "building";
+        if (osmPathHighwayTagValues[way.tags.highway]) return "path";
         var parentRelations = graph.parentRelations(way);
         for (var i3 in parentRelations) {
           var relation = parentRelations[i3];
-          if (relation.tags.type === "boundary")
-            return "boundary";
+          if (relation.tags.type === "boundary") return "boundary";
           if (relation.isMultipolygon()) {
-            if (relation.tags.indoor && relation.tags.indoor !== "no")
-              return "indoor";
-            if (relation.tags.building && relation.tags.building !== "no" || relation.tags["building:part"] && relation.tags["building:part"] !== "no")
-              return "building";
+            if (relation.tags.indoor && relation.tags.indoor !== "no") return "indoor";
+            if (relation.tags.building && relation.tags.building !== "no" || relation.tags["building:part"] && relation.tags["building:part"] !== "no") return "building";
           }
         }
         return "other";
       }
       function shouldCheckWay(way) {
-        if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4)
-          return false;
+        if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
         var bbox2 = way.extent(graph).bbox();
         var hypotenuseMeters = geoSphericalDistance([bbox2.minX, bbox2.minY], [bbox2.maxX, bbox2.maxY]);
-        if (hypotenuseMeters < 1.5)
-          return false;
+        if (hypotenuseMeters < 1.5) return false;
         return true;
       }
       function getIssuesForWay(way) {
-        if (!shouldCheckWay(way))
-          return [];
+        if (!shouldCheckWay(way)) return [];
         var issues = [], nodes = graph.childNodes(way);
         for (var i3 = 0; i3 < nodes.length - 1; i3++) {
           var node1 = nodes[i3];
           var node2 = nodes[i3 + 1];
           var issue = getWayIssueIfAny(node1, node2, way);
-          if (issue)
-            issues.push(issue);
+          if (issue) issues.push(issue);
         }
         return issues;
       }
         var issues = [];
         function checkForCloseness(node1, node2, way) {
           var issue = getWayIssueIfAny(node1, node2, way);
-          if (issue)
-            issues.push(issue);
+          if (issue) issues.push(issue);
         }
         for (var i3 = 0; i3 < parentWays.length; i3++) {
           var parentWay = parentWays[i3];
-          if (!shouldCheckWay(parentWay))
-            continue;
+          if (!shouldCheckWay(parentWay)) continue;
           var lastIndex = parentWay.nodes.length - 1;
           for (var j2 = 0; j2 < parentWay.nodes.length; j2++) {
             if (j2 !== 0) {
         return issues;
       }
       function thresholdMetersForWay(way) {
-        if (!shouldCheckWay(way))
-          return 0;
+        if (!shouldCheckWay(way)) return 0;
         var wayType = wayTypeFor(way);
-        if (wayType === "boundary")
-          return 0;
-        if (wayType === "indoor")
-          return 0.01;
-        if (wayType === "building")
-          return 0.05;
-        if (wayType === "path")
-          return 0.1;
+        if (wayType === "boundary") return 0;
+        if (wayType === "indoor") return 0.01;
+        if (wayType === "building") return 0.05;
+        if (wayType === "path") return 0.1;
         return 0.2;
       }
       function getIssuesForDetachedPoint(node) {
         var intersected = context.history().tree().intersects(queryExtent, graph);
         for (var j2 = 0; j2 < intersected.length; j2++) {
           var nearby = intersected[j2];
-          if (nearby.id === node.id)
-            continue;
-          if (nearby.type !== "node" || nearby.geometry(graph) !== "point")
-            continue;
+          if (nearby.id === node.id) continue;
+          if (nearby.type !== "node" || nearby.geometry(graph) !== "point") continue;
           if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
-            if ("memorial:type" in node.tags && "memorial:type" in nearby.tags && node.tags["memorial:type"] === "stolperstein" && nearby.tags["memorial:type"] === "stolperstein")
-              continue;
-            if ("memorial" in node.tags && "memorial" in nearby.tags && node.tags.memorial === "stolperstein" && nearby.tags.memorial === "stolperstein")
-              continue;
+            if ("memorial:type" in node.tags && "memorial:type" in nearby.tags && node.tags["memorial:type"] === "stolperstein" && nearby.tags["memorial:type"] === "stolperstein") continue;
+            if ("memorial" in node.tags && "memorial" in nearby.tags && node.tags.memorial === "stolperstein" && nearby.tags.memorial === "stolperstein") continue;
             var zAxisKeys = { layer: true, level: true, "addr:housenumber": true, "addr:unit": true };
             var zAxisDifferentiates = false;
             for (var key in zAxisKeys) {
                 break;
               }
             }
-            if (zAxisDifferentiates)
-              continue;
+            if (zAxisDifferentiates) continue;
             issues.push(new validationIssue({
               type: type2,
               subtype: "detached",
           });
           var threshold = Math.min(...thresholds);
           var distance = geoSphericalDistance(node1.loc, node2.loc);
-          if (distance > threshold)
-            return null;
+          if (distance > threshold) return null;
         }
         return new validationIssue({
           type: type2,
     };
     function getFeatureType(entity, graph) {
       var geometry = entity.geometry(graph);
-      if (geometry !== "line" && geometry !== "area")
-        return null;
+      if (geometry !== "line" && geometry !== "area") return null;
       var tags = entity.tags;
-      if (hasTag(tags, "building") && !ignoredBuildings[tags.building])
-        return "building";
-      if (hasTag(tags, "highway") && osmRoutableHighwayTagValues[tags.highway])
-        return "highway";
-      if (geometry !== "line")
-        return null;
-      if (hasTag(tags, "railway") && osmRailwayTrackTagValues[tags.railway])
-        return "railway";
-      if (hasTag(tags, "waterway") && osmFlowingWaterwayTagValues[tags.waterway])
-        return "waterway";
+      if (hasTag(tags, "building") && !ignoredBuildings[tags.building]) return "building";
+      if (hasTag(tags, "highway") && osmRoutableHighwayTagValues[tags.highway]) return "highway";
+      if (geometry !== "line") return null;
+      if (hasTag(tags, "railway") && osmRailwayTrackTagValues[tags.railway]) return "railway";
+      if (hasTag(tags, "waterway") && osmFlowingWaterwayTagValues[tags.waterway]) return "waterway";
       return null;
     }
     function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
       var layer1 = tags1.layer || "0";
       var layer2 = tags2.layer || "0";
       if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
-        if (hasTag(tags1, "bridge") && !hasTag(tags2, "bridge"))
-          return true;
-        if (!hasTag(tags1, "bridge") && hasTag(tags2, "bridge"))
-          return true;
-        if (hasTag(tags1, "bridge") && hasTag(tags2, "bridge") && layer1 !== layer2)
-          return true;
-      } else if (allowsBridge(featureType1) && hasTag(tags1, "bridge"))
-        return true;
-      else if (allowsBridge(featureType2) && hasTag(tags2, "bridge"))
-        return true;
+        if (hasTag(tags1, "bridge") && !hasTag(tags2, "bridge")) return true;
+        if (!hasTag(tags1, "bridge") && hasTag(tags2, "bridge")) return true;
+        if (hasTag(tags1, "bridge") && hasTag(tags2, "bridge") && layer1 !== layer2) return true;
+      } else if (allowsBridge(featureType1) && hasTag(tags1, "bridge")) return true;
+      else if (allowsBridge(featureType2) && hasTag(tags2, "bridge")) return true;
       if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
-        if (hasTag(tags1, "tunnel") && !hasTag(tags2, "tunnel"))
-          return true;
-        if (!hasTag(tags1, "tunnel") && hasTag(tags2, "tunnel"))
-          return true;
-        if (hasTag(tags1, "tunnel") && hasTag(tags2, "tunnel") && layer1 !== layer2)
-          return true;
-      } else if (allowsTunnel(featureType1) && hasTag(tags1, "tunnel"))
-        return true;
-      else if (allowsTunnel(featureType2) && hasTag(tags2, "tunnel"))
-        return true;
-      if (featureType1 === "waterway" && featureType2 === "highway" && tags2.man_made === "pier")
-        return true;
-      if (featureType2 === "waterway" && featureType1 === "highway" && tags1.man_made === "pier")
-        return true;
+        if (hasTag(tags1, "tunnel") && !hasTag(tags2, "tunnel")) return true;
+        if (!hasTag(tags1, "tunnel") && hasTag(tags2, "tunnel")) return true;
+        if (hasTag(tags1, "tunnel") && hasTag(tags2, "tunnel") && layer1 !== layer2) return true;
+      } else if (allowsTunnel(featureType1) && hasTag(tags1, "tunnel")) return true;
+      else if (allowsTunnel(featureType2) && hasTag(tags2, "tunnel")) return true;
+      if (featureType1 === "waterway" && featureType2 === "highway" && tags2.man_made === "pier") return true;
+      if (featureType2 === "waterway" && featureType1 === "highway" && tags1.man_made === "pier") return true;
       if (featureType1 === "building" || featureType2 === "building" || taggedAsIndoor(tags1) || taggedAsIndoor(tags2)) {
-        if (layer1 !== layer2)
-          return true;
+        if (layer1 !== layer2) return true;
       }
       return false;
     }
           }
           return {};
         }
-        if (featureType1 === "waterway")
-          return {};
-        if (featureType1 === "railway")
-          return {};
+        if (featureType1 === "waterway") return {};
+        if (featureType1 === "railway") return {};
       } else {
         var featureTypes = [featureType1, featureType2];
         if (featureTypes.indexOf("highway") !== -1) {
           if (featureTypes.indexOf("railway") !== -1) {
-            if (!bothLines)
-              return {};
+            if (!bothLines) return {};
             var isTram = entity1.tags.railway === "tram" || entity2.tags.railway === "tram";
             if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
-              if (isTram)
-                return { railway: "tram_crossing" };
+              if (isTram) return { railway: "tram_crossing" };
               return { railway: "crossing" };
             } else {
-              if (isTram)
-                return { railway: "tram_level_crossing" };
+              if (isTram) return { railway: "tram_level_crossing" };
               return { railway: "level_crossing" };
             }
           }
           if (featureTypes.indexOf("waterway") !== -1) {
-            if (hasTag(entity1.tags, "tunnel") && hasTag(entity2.tags, "tunnel"))
-              return null;
-            if (hasTag(entity1.tags, "bridge") && hasTag(entity2.tags, "bridge"))
-              return null;
+            if (hasTag(entity1.tags, "tunnel") && hasTag(entity2.tags, "tunnel")) return null;
+            if (hasTag(entity1.tags, "bridge") && hasTag(entity2.tags, "bridge")) return null;
             if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
               return null;
             }
     }
     function findCrossingsByWay(way1, graph, tree) {
       var edgeCrossInfos = [];
-      if (way1.type !== "way")
-        return edgeCrossInfos;
+      if (way1.type !== "way") return edgeCrossInfos;
       var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
       var way1FeatureType = getFeatureType(taggedFeature1, graph);
-      if (way1FeatureType === null)
-        return edgeCrossInfos;
+      if (way1FeatureType === null) return edgeCrossInfos;
       var checkedSingleCrossingWays = {};
       var i3, j2;
       var extent;
         segmentInfos = tree.waySegments(extent, graph);
         for (j2 = 0; j2 < segmentInfos.length; j2++) {
           segment2Info = segmentInfos[j2];
-          if (segment2Info.wayId === way1.id)
-            continue;
-          if (checkedSingleCrossingWays[segment2Info.wayId])
-            continue;
+          if (segment2Info.wayId === way1.id) continue;
+          if (checkedSingleCrossingWays[segment2Info.wayId]) continue;
           comparedWays[segment2Info.wayId] = true;
           way2 = graph.hasEntity(segment2Info.wayId);
-          if (!way2)
-            continue;
+          if (!way2) continue;
           taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph);
           way2FeatureType = getFeatureType(taggedFeature2, graph);
           if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
             continue;
           }
           nA = graph.hasEntity(nAId);
-          if (!nA)
-            continue;
+          if (!nA) continue;
           nB = graph.hasEntity(nBId);
-          if (!nB)
-            continue;
+          if (!nB) continue;
           segment1 = [n1.loc, n22.loc];
           segment2 = [nA.loc, nB.loc];
-          var point2 = geoLineIntersection(segment1, segment2);
-          if (point2) {
+          var point = geoLineIntersection(segment1, segment2);
+          if (point) {
             edgeCrossInfos.push({
               wayInfos: [
                 {
                   edge: [nA.id, nB.id]
                 }
               ],
-              crossPoint: point2
+              crossPoint: point
             });
             if (oneOnly) {
               checkedSingleCrossingWays[way2.id] = true;
     }
     function waysToCheck(entity, graph) {
       var featureType = getFeatureType(entity, graph);
-      if (!featureType)
-        return [];
+      if (!featureType) return [];
       if (entity.type === "way") {
         return [entity];
       } else if (entity.type === "relation") {
         loc: crossing.crossPoint,
         dynamicFixes: function(context2) {
           var mode = context2.mode();
-          if (!mode || mode.id !== "select" || mode.selectedIDs().length !== 1)
-            return [];
+          if (!mode || mode.id !== "select" || mode.selectedIDs().length !== 1) return [];
           var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
           var selectedFeatureType = this.data.featureTypes[selectedIndex];
           var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
         title: _t.append("issues.fix." + fixTitleID + ".title"),
         onClick: function(context2) {
           var mode = context2.mode();
-          if (!mode || mode.id !== "select")
-            return;
+          if (!mode || mode.id !== "select") return;
           var selectedIDs = mode.selectedIDs();
-          if (selectedIDs.length !== 1)
-            return;
+          if (selectedIDs.length !== 1) return;
           var selectedWayID = selectedIDs[0];
-          if (!context2.hasEntity(selectedWayID))
-            return;
+          if (!context2.hasEntity(selectedWayID)) return;
           var resultWayIDs = [selectedWayID];
           var edge, crossedEdge, crossedWayID;
           if (this.issue.entityIds[0] === selectedWayID) {
             var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection2) + Math.PI;
             var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection2) + Math.PI;
             var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
-            if (crossingAngle > Math.PI)
-              crossingAngle -= Math.PI;
+            if (crossingAngle > Math.PI) crossingAngle -= Math.PI;
             structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2;
             structLengthMeters += 4;
             structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
                   }
                 }
               }
-              if (!newNode)
-                newNode = endNode;
+              if (!newNode) newNode = endNode;
               var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs);
               graph = splitAction(graph);
               if (splitAction.getCreatedWayIDs().length) {
         title: _t.append("issues.fix.tag_this_as_" + higherOrLower + ".title"),
         onClick: function(context2) {
           var mode = context2.mode();
-          if (!mode || mode.id !== "select")
-            return;
+          if (!mode || mode.id !== "select") return;
           var selectedIDs = mode.selectedIDs();
-          if (selectedIDs.length !== 1)
-            return;
+          if (selectedIDs.length !== 1) return;
           var selectedID = selectedIDs[0];
           if (!this.issue.entityIds.some(function(entityId) {
             return entityId === selectedID;
-          }))
-            return;
+          })) return;
           var entity = context2.hasEntity(selectedID);
-          if (!entity)
-            return;
+          if (!entity) return;
           var tags = Object.assign({}, entity.tags);
           var layer = tags.layer && Number(tags.layer);
           if (layer && !isNaN(layer)) {
     }
     function move(d3_event, datum2) {
       var loc = context.map().mouseCoordinates();
-      if (!_drawNode)
-        createDrawNode(loc);
+      if (!_drawNode) createDrawNode(loc);
       context.surface().classed("nope-disabled", d3_event.altKey);
       var targetLoc = datum2 && datum2.properties && datum2.properties.entity && allowsVertex(datum2.properties.entity) && datum2.properties.entity.loc;
       var targetNodes = datum2 && datum2.properties && datum2.properties.nodes;
         }
       } else {
         if (parentWay.isClosed()) {
-          if (nodes.length < 3)
-            return false;
-          if (_drawNode)
-            nodes.splice(-2, 1);
+          if (nodes.length < 3) return false;
+          if (_drawNode) nodes.splice(-2, 1);
           testNode = nodes[nodes.length - 2];
         } else {
           return false;
       context.enter(nextMode);
     }
     function setActiveElements() {
-      if (!_drawNode)
-        return;
+      if (!_drawNode) return;
       context.surface().selectAll("." + _drawNode.id).classed("active", true);
     }
     function resetToStartGraph() {
       }).on("down", function() {
         move.apply(this, arguments);
       }).on("downcancel", function() {
-        if (_drawNode)
-          removeDrawNode();
+        if (_drawNode) removeDrawNode();
       }).on("click", drawWay.add).on("clickWay", drawWay.addWay).on("clickNode", drawWay.addNode).on("undo", context.undo).on("cancel", drawWay.cancel).on("finish", drawWay.finish);
       select_default2(window).on("keydown.drawWay", keydown).on("keyup.drawWay", keyup);
       context.map().dblclickZoomEnable(false).on("drawn.draw", setActiveElements);
       });
     };
     function getFeatureType(ways) {
-      if (ways.every((way) => way.isClosed()))
-        return "area";
-      if (ways.every((way) => !way.isClosed()))
-        return "line";
+      if (ways.every((way) => way.isClosed())) return "area";
+      if (ways.every((way) => !way.isClosed())) return "line";
       return "generic";
     }
     function followMode() {
-      if (_didResolveTempEdit)
-        return;
+      if (_didResolveTempEdit) return;
       try {
         const isDrawingArea = _origWay.nodes[0] === _origWay.nodes.slice(-1)[0];
         const [secondLastNodeId, lastNodeId] = _origWay.nodes.slice(isDrawingArea ? -3 : -2);
         const indexOfSecondLast = way.nodes.indexOf(secondLastNodeId);
         const isDescendingPastZero = indexOfLast === way.nodes.length - 2 && indexOfSecondLast === 0;
         let nextNodeIndex = indexOfLast + (indexOfLast > indexOfSecondLast && !isDescendingPastZero ? 1 : -1);
-        if (nextNodeIndex === -1)
-          nextNodeIndex = indexOfSecondLast === 1 ? way.nodes.length - 2 : 1;
+        if (nextNodeIndex === -1) nextNodeIndex = indexOfSecondLast === 1 ? way.nodes.length - 2 : 1;
         const nextNode = historyGraph.entity(way.nodes[nextNodeIndex]);
         drawWay.addNode(nextNode, {
           geometry: { type: "Point", coordinates: nextNode.loc },
       context.enter(modeBrowse(context));
     };
     drawWay.nodeIndex = function(val) {
-      if (!arguments.length)
-        return _nodeIndex;
+      if (!arguments.length) return _nodeIndex;
       _nodeIndex = val;
       return drawWay;
     };
     drawWay.activeID = function() {
-      if (!arguments.length)
-        return _drawNode && _drawNode.id;
+      if (!arguments.length) return _drawNode && _drawNode.id;
       return drawWay;
     };
     return utilRebind(drawWay, dispatch14, "on");
     }
     var validation = function checkDisconnectedWay(entity, graph) {
       var routingIslandWays = routingIslandForEntity(entity);
-      if (!routingIslandWays)
-        return [];
+      if (!routingIslandWays) return [];
       return [new validationIssue({
         type: type2,
         subtype: "highway",
           if (singleEntity.type === "way" && !singleEntity.isClosed()) {
             var textDirection = _mainLocalizer.textDirection();
             var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), "start");
-            if (startFix)
-              fixes.push(startFix);
+            if (startFix) fixes.push(startFix);
             var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), "end");
-            if (endFix)
-              fixes.push(endFix);
+            if (endFix) fixes.push(endFix);
           }
           if (!fixes.length) {
             fixes.push(new validationIssueFix({
       }
       function isConnectedVertex(vertex) {
         var osm = services.osm;
-        if (osm && !osm.isDataLoaded(vertex.loc))
-          return true;
-        if (vertex.tags.entrance && vertex.tags.entrance !== "no")
-          return true;
-        if (vertex.tags.amenity === "parking_entrance")
-          return true;
+        if (osm && !osm.isDataLoaded(vertex.loc)) return true;
+        if (vertex.tags.entrance && vertex.tags.entrance !== "no") return true;
+        if (vertex.tags.amenity === "parking_entrance") return true;
         return false;
       }
       function isRoutableNode(node) {
-        if (node.tags.highway === "elevator")
-          return true;
+        if (node.tags.highway === "elevator") return true;
         return false;
       }
       function isRoutableWay(way, ignoreInnerWays) {
-        if (isTaggedAsHighway(way) || way.tags.route === "ferry")
-          return true;
+        if (isTaggedAsHighway(way) || way.tags.route === "ferry") return true;
         return graph.parentRelations(way).some(function(parentRelation) {
-          if (parentRelation.tags.type === "route" && parentRelation.tags.route === "ferry")
-            return true;
-          if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== "inner"))
-            return true;
+          if (parentRelation.tags.type === "route" && parentRelation.tags.route === "ferry") return true;
+          if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== "inner")) return true;
           return false;
         });
       }
       function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
         var vertex = graph.hasEntity(vertexID);
-        if (!vertex || vertex.tags.noexit === "yes")
-          return null;
+        if (!vertex || vertex.tags.noexit === "yes") return null;
         var useLeftContinue = whichEnd === "start" && textDirection === "ltr" || whichEnd === "end" && textDirection === "rtl";
         return new validationIssueFix({
           icon: "iD-operation-continue" + (useLeftContinue ? "-left" : ""),
             var way = context.hasEntity(wayId);
             var vertexId = this.entityIds[0];
             var vertex2 = context.hasEntity(vertexId);
-            if (!way || !vertex2)
-              return;
+            if (!way || !vertex2) return;
             var map2 = context.map();
             if (!context.editable() || !map2.trimmedExtent().contains(vertex2.loc)) {
               map2.zoomToEase(vertex2);
   function validationHelpRequest(context) {
     var type2 = "help_request";
     var validation = function checkFixmeTag(entity) {
-      if (!entity.tags.fixme)
-        return [];
-      if (entity.version === void 0)
-        return [];
+      if (!entity.tags.fixme) return [];
+      if (entity.version === void 0) return [];
       if (entity.v !== void 0) {
         var baseEntity = context.history().base().hasEntity(entity.id);
-        if (!baseEntity || !baseEntity.tags.fixme)
-          return [];
+        if (!baseEntity || !baseEntity.tags.fixme) return [];
       }
       return [new validationIssue({
         type: type2,
   function validationImpossibleOneway() {
     var type2 = "impossible_oneway";
     var validation = function checkImpossibleOneway(entity, graph) {
-      if (entity.type !== "way" || entity.geometry(graph) !== "line")
-        return [];
-      if (entity.isClosed())
-        return [];
-      if (!typeForWay(entity))
-        return [];
-      if (!isOneway(entity))
-        return [];
+      if (entity.type !== "way" || entity.geometry(graph) !== "line") return [];
+      if (entity.isClosed()) return [];
+      if (!typeForWay(entity)) return [];
+      if (!isOneway(entity)) return [];
       var firstIssues = issuesForNode(entity, entity.first());
       var lastIssues = issuesForNode(entity, entity.last());
       return firstIssues.concat(lastIssues);
       function typeForWay(way) {
-        if (way.geometry(graph) !== "line")
-          return null;
-        if (osmRoutableHighwayTagValues[way.tags.highway])
-          return "highway";
-        if (osmFlowingWaterwayTagValues[way.tags.waterway])
-          return "waterway";
+        if (way.geometry(graph) !== "line") return null;
+        if (osmRoutableHighwayTagValues[way.tags.highway]) return "highway";
+        if (osmFlowingWaterwayTagValues[way.tags.waterway]) return "waterway";
         return null;
       }
       function isOneway(way) {
-        if (way.tags.oneway === "yes")
-          return true;
-        if (way.tags.oneway)
-          return false;
+        if (way.tags.oneway === "yes") return true;
+        if (way.tags.oneway) return false;
         for (var key in way.tags) {
           if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
             return true;
         for (var index in way.nodes) {
           if (way.nodes[index] === nodeID) {
             occurrences += 1;
-            if (occurrences > 1)
-              return true;
+            if (occurrences > 1) return true;
           }
         }
         return false;
       function isConnectedViaOtherTypes(way, node) {
         var wayType = typeForWay(way);
         if (wayType === "highway") {
-          if (node.tags.entrance && node.tags.entrance !== "no")
-            return true;
-          if (node.tags.amenity === "parking_entrance")
-            return true;
+          if (node.tags.entrance && node.tags.entrance !== "no") return true;
+          if (node.tags.amenity === "parking_entrance") return true;
         } else if (wayType === "waterway") {
           if (node.id === way.first()) {
-            if (node.tags.natural === "spring")
-              return true;
+            if (node.tags.natural === "spring") return true;
           } else {
-            if (node.tags.manhole === "drain")
-              return true;
+            if (node.tags.manhole === "drain") return true;
           }
         }
         return graph.parentWays(node).some(function(parentWay) {
-          if (parentWay.id === way.id)
-            return false;
+          if (parentWay.id === way.id) return false;
           if (wayType === "highway") {
-            if (parentWay.geometry(graph) === "area" && osmRoutableHighwayTagValues[parentWay.tags.highway])
-              return true;
-            if (parentWay.tags.route === "ferry")
-              return true;
+            if (parentWay.geometry(graph) === "area" && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true;
+            if (parentWay.tags.route === "ferry") return true;
             return graph.parentRelations(parentWay).some(function(parentRelation) {
-              if (parentRelation.tags.type === "route" && parentRelation.tags.route === "ferry")
-                return true;
+              if (parentRelation.tags.type === "route" && parentRelation.tags.route === "ferry") return true;
               return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
             });
           } else if (wayType === "waterway") {
-            if (parentWay.tags.natural === "water" || parentWay.tags.natural === "coastline")
-              return true;
+            if (parentWay.tags.natural === "water" || parentWay.tags.natural === "coastline") return true;
           }
           return false;
         });
       function issuesForNode(way, nodeID) {
         var isFirst = nodeID === way.first();
         var wayType = typeForWay(way);
-        if (nodeOccursMoreThanOnce(way, nodeID))
-          return [];
+        if (nodeOccursMoreThanOnce(way, nodeID)) return [];
         var osm = services.osm;
-        if (!osm)
-          return [];
+        if (!osm) return [];
         var node = graph.hasEntity(nodeID);
-        if (!node || !osm.isDataLoaded(node.loc))
-          return [];
-        if (isConnectedViaOtherTypes(way, node))
-          return [];
+        if (!node || !osm.isDataLoaded(node.loc)) return [];
+        if (isConnectedViaOtherTypes(way, node)) return [];
         var attachedWaysOfSameType = graph.parentWays(node).filter(function(parentWay) {
-          if (parentWay.id === way.id)
-            return false;
+          if (parentWay.id === way.id) return false;
           return typeForWay(parentWay) === wayType;
         });
-        if (wayType === "waterway" && attachedWaysOfSameType.length === 0)
-          return [];
+        if (wayType === "waterway" && attachedWaysOfSameType.length === 0) return [];
         var attachedOneways = attachedWaysOfSameType.filter(function(attachedWay) {
           return isOneway(attachedWay);
         });
-        if (attachedOneways.length < attachedWaysOfSameType.length)
-          return [];
+        if (attachedOneways.length < attachedWaysOfSameType.length) return [];
         if (attachedOneways.length) {
           var connectedEndpointsOkay = attachedOneways.some(function(attachedOneway) {
-            if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID)
-              return true;
-            if (nodeOccursMoreThanOnce(attachedOneway, nodeID))
-              return true;
+            if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
+            if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
             return false;
           });
-          if (connectedEndpointsOkay)
-            return [];
+          if (connectedEndpointsOkay) return [];
         }
         var placement = isFirst ? "start" : "end", messageID = wayType + ".", referenceID = wayType + ".";
         if (wayType === "waterway") {
     ];
     const validation = function checkIncompatibleSource(entity) {
       const entitySources = entity.tags && entity.tags.source && entity.tags.source.split(";");
-      if (!entitySources)
-        return [];
+      if (!entitySources) return [];
       const entityID = entity.id;
       return entitySources.map((source) => {
         const matchRule = incompatibleRules.find((rule) => {
-          if (!rule.regex.test(source))
-            return false;
-          if (rule.exceptRegex && rule.exceptRegex.test(source))
-            return false;
+          if (!rule.regex.test(source)) return false;
+          if (rule.exceptRegex && rule.exceptRegex.test(source)) return false;
           return true;
         });
-        if (!matchRule)
-          return null;
+        if (!matchRule) return null;
         return new validationIssue({
           type: type2,
           severity: "warning",
   function validationMaprules() {
     var type2 = "maprules";
     var validation = function checkMaprules(entity, graph) {
-      if (!services.maprules)
-        return [];
+      if (!services.maprules) return [];
       var rules = services.maprules.validationRules();
       var issues = [];
       for (var i3 = 0; i3 < rules.length; i3++) {
   function validationMismatchedGeometry() {
     var type2 = "mismatched_geometry";
     function tagSuggestingLineIsArea(entity) {
-      if (entity.type !== "way" || entity.isClosed())
-        return null;
+      if (entity.type !== "way" || entity.isClosed()) return null;
       var tagSuggestingArea = entity.tagSuggestingArea();
       if (!tagSuggestingArea) {
         return null;
       return tagSuggestingArea;
     }
     function makeConnectEndpointsFixOnClick(way, graph) {
-      if (way.nodes.length < 3)
-        return null;
+      if (way.nodes.length < 3) return null;
       var nodes = graph.childNodes(way), testNodes;
       var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc);
       if (firstToLastDistanceMeters < 0.75) {
     }
     function lineTaggedAsAreaIssue(entity) {
       var tagSuggestingArea = tagSuggestingLineIsArea(entity);
-      if (!tagSuggestingArea)
-        return null;
+      if (!tagSuggestingArea) return null;
       var validAsLine = false;
       var presetAsLine = _mainPresetIndex.matchTags(entity.tags, "line");
       if (presetAsLine) {
       }
     }
     function vertexPointIssue(entity, graph) {
-      if (entity.type !== "node")
-        return null;
-      if (Object.keys(entity.tags).length === 0)
-        return null;
-      if (entity.isOnAddressLine(graph))
-        return null;
+      if (entity.type !== "node") return null;
+      if (Object.keys(entity.tags).length === 0) return null;
+      if (entity.isOnAddressLine(graph)) return null;
       var geometry = entity.geometry(graph);
       var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
       if (geometry === "point" && !allowedGeometries.point && allowedGeometries.vertex) {
       return null;
     }
     function otherMismatchIssue(entity, graph) {
-      if (!entity.hasInterestingTags())
-        return null;
-      if (entity.type !== "node" && entity.type !== "way")
-        return null;
-      if (entity.type === "node" && entity.isOnAddressLine(graph))
-        return null;
+      if (!entity.hasInterestingTags()) return null;
+      if (entity.type !== "node" && entity.type !== "way") return null;
+      if (entity.type === "node" && entity.isOnAddressLine(graph)) return null;
       var sourceGeom = entity.geometry(graph);
       var targetGeoms = entity.type === "way" ? ["point", "vertex"] : ["line", "area"];
-      if (sourceGeom === "area")
-        targetGeoms.unshift("line");
+      if (sourceGeom === "area") targetGeoms.unshift("line");
       var asSource = _mainPresetIndex.match(entity, graph);
       var targetGeom = targetGeoms.find((nodeGeom) => {
         var asTarget = _mainPresetIndex.matchTags(entity.tags, nodeGeom);
         if (!asSource || !asTarget || asSource === asTarget || // sometimes there are two presets with the same tags for different geometries
-        (0, import_fast_deep_equal4.default)(asSource.tags, asTarget.tags))
-          return false;
-        if (asTarget.isFallback())
-          return false;
+        (0, import_fast_deep_equal4.default)(asSource.tags, asTarget.tags)) return false;
+        if (asTarget.isFallback()) return false;
         var primaryKey = Object.keys(asTarget.tags)[0];
-        if (primaryKey === "building")
-          return false;
-        if (asTarget.tags[primaryKey] === "*")
-          return false;
+        if (primaryKey === "building") return false;
+        if (asTarget.tags[primaryKey] === "*") return false;
         return asSource.isFallback() || asSource.tags[primaryKey] === "*";
       });
-      if (!targetGeom)
-        return null;
+      if (!targetGeom) return null;
       var subtype = targetGeom + "_as_" + sourceGeom;
-      if (targetGeom === "vertex")
-        targetGeom = "point";
-      if (sourceGeom === "vertex")
-        sourceGeom = "point";
+      if (targetGeom === "vertex") targetGeom = "point";
+      if (sourceGeom === "vertex") sourceGeom = "point";
       var referenceId = targetGeom + "_as_" + sourceGeom;
       var dynamicFixes;
       if (targetGeom === "point") {
     }
     function unclosedMultipolygonPartIssues(entity, graph) {
       if (entity.type !== "relation" || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
-      !entity.isComplete(graph))
-        return [];
+      !entity.isComplete(graph)) return [];
       var sequences = osmJoinWays(entity.members, graph);
       var issues = [];
       for (var i3 in sequences) {
         var sequence = sequences[i3];
-        if (!sequence.nodes)
-          continue;
+        if (!sequence.nodes) continue;
         var firstNode = sequence.nodes[0];
         var lastNode = sequence.nodes[sequence.nodes.length - 1];
-        if (firstNode === lastNode)
-          continue;
+        if (firstNode === lastNode) continue;
         var issue = new validationIssue({
           type: type2,
           subtype: "unclosed_multipolygon_part",
     }
     var validation = function checkMismatchedGeometry(entity, graph) {
       var vertexPoint = vertexPointIssue(entity, graph);
-      if (vertexPoint)
-        return [vertexPoint];
+      if (vertexPoint) return [vertexPoint];
       var lineAsArea = lineTaggedAsAreaIssue(entity);
-      if (lineAsArea)
-        return [lineAsArea];
+      if (lineAsArea) return [lineAsArea];
       var mismatch = otherMismatchIssue(entity, graph);
-      if (mismatch)
-        return [mismatch];
+      if (mismatch) return [mismatch];
       return unclosedMultipolygonPartIssues(entity, graph);
     };
     validation.type = type2;
       var issues = [];
       if (entity.type === "way") {
         graph.parentRelations(entity).forEach(function(relation) {
-          if (!relation.isMultipolygon())
-            return;
+          if (!relation.isMultipolygon()) return;
           var member = relation.memberById(entity.id);
           if (member && isMissingRole(member)) {
             issues.push(makeIssue(entity, relation, member));
     function hasDescriptiveTags(entity) {
       var onlyAttributeKeys = ["description", "name", "note", "start_date"];
       var entityDescriptiveKeys = Object.keys(entity.tags).filter(function(k2) {
-        if (k2 === "area" || !osmIsInterestingTag(k2))
-          return false;
+        if (k2 === "area" || !osmIsInterestingTag(k2)) return false;
         return !onlyAttributeKeys.some(function(attributeKey) {
           return k2 === attributeKey || k2.indexOf(attributeKey + ":") === 0;
         });
       if (!subtype && isUnknownRoad(entity)) {
         subtype = "highway_classification";
       }
-      if (!subtype)
-        return [];
+      if (!subtype) return [];
       var messageID = subtype === "highway_classification" ? "unknown_road" : "missing_tag." + subtype;
       var referenceID = subtype === "highway_classification" ? "unknown_road" : "missing_tag";
       var canDelete = entity.version === void 0 || entity.v !== void 0;
     _mainFileFetcher.get("deprecated").then((d2) => _dataDeprecated = d2).catch(() => {
     }).finally(() => _waitingForDeprecated = false);
     function oldTagIssues(entity, graph) {
-      if (!entity.hasInterestingTags())
-        return [];
+      if (!entity.hasInterestingTags()) return [];
       let preset = _mainPresetIndex.match(entity, graph);
-      if (!preset)
-        return [];
+      if (!preset) return [];
       const oldTags = Object.assign({}, entity.tags);
       let subtype = "deprecated_tags";
       if (preset.replacement) {
       let issues = [];
       issues.provisional = _waitingForDeprecated || waitingForNsi;
       const tagDiff = utilTagDiff(oldTags, newTags);
-      if (!tagDiff.length)
-        return issues;
+      if (!tagDiff.length) return issues;
       const isOnlyAddingTags = tagDiff.every((d2) => d2.type === "+");
       let prefix = "";
       if (nsiResult) {
       return issues;
       function doUpgrade(graph2) {
         const currEntity = graph2.hasEntity(entity.id);
-        if (!currEntity)
-          return graph2;
+        if (!currEntity) return graph2;
         let newTags2 = Object.assign({}, currEntity.tags);
         tagDiff.forEach((diff) => {
           if (diff.type === "-") {
       }
       function addNotTag(graph2) {
         const currEntity = graph2.hasEntity(entity.id);
-        if (!currEntity)
-          return graph2;
+        if (!currEntity) return graph2;
         const item = nsiResult && nsiResult.matched;
-        if (!item)
-          return graph2;
+        if (!item) return graph2;
         let newTags2 = Object.assign({}, currEntity.tags);
         const wd = item.mainTag;
         const notwd = "not:".concat(wd);
       }
       function showMessage(context) {
         const currEntity = context.hasEntity(entity.id);
-        if (!currEntity)
-          return "";
+        if (!currEntity) return "";
         let messageID = "issues.outdated_tags.".concat(prefix, "message");
         if (subtype === "noncanonical_brand" && isOnlyAddingTags) {
           messageID += "_incomplete";
     };
     var validation = function checkPrivateData(entity) {
       var tags = entity.tags;
-      if (!tags.building || !privateBuildingValues[tags.building])
-        return [];
+      if (!tags.building || !privateBuildingValues[tags.building]) return [];
       var keepTags = {};
       for (var k2 in tags) {
-        if (publicKeys[k2])
-          return [];
+        if (publicKeys[k2]) return [];
         if (!personalTags[k2]) {
           keepTags[k2] = tags[k2];
         }
       }
       var tagDiff = utilTagDiff(tags, keepTags);
-      if (!tagDiff.length)
-        return [];
+      if (!tagDiff.length) return [];
       var fixID = tagDiff.length === 1 ? "remove_tag" : "remove_tags";
       return [new validationIssue({
         type: type2,
       })];
       function doUpgrade(graph) {
         var currEntity = graph.hasEntity(entity.id);
-        if (!currEntity)
-          return graph;
+        if (!currEntity) return graph;
         var newTags = Object.assign({}, currEntity.tags);
         tagDiff.forEach(function(diff) {
           if (diff.type === "-") {
       }
       function showMessage(context) {
         var currEntity = context.hasEntity(this.entityIds[0]);
-        if (!currEntity)
-          return "";
+        if (!currEntity) return "";
         return _t.append(
           "issues.private_data.contact.message",
           { feature: utilDisplayLabel(currEntity, context.graph()) }
         severity: "warning",
         message: function(context) {
           let entity = context.hasEntity(this.entityIds[0]);
-          if (!entity)
-            return "";
+          if (!entity) return "";
           let preset = _mainPresetIndex.match(entity, context.graph());
           let langName = langCode && _mainLocalizer.languageName(langCode);
           return _t.append(
     let validation = function checkGenericName(entity) {
       const tags = entity.tags;
       const hasWikidata = !!tags.wikidata || !!tags["brand:wikidata"] || !!tags["operator:wikidata"];
-      if (hasWikidata)
-        return [];
+      if (hasWikidata) return [];
       let issues = [];
       for (let key in tags) {
         const m2 = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
-        if (!m2)
-          continue;
+        if (!m2) continue;
         const langCode = m2.length >= 2 ? m2[1] : null;
         const value = tags[key];
         if (isGenericName(value, tags)) {
     var epsilon3 = 0.05;
     var nodeThreshold = 10;
     function isBuilding(entity, graph) {
-      if (entity.type !== "way" || entity.geometry(graph) !== "area")
-        return false;
+      if (entity.type !== "way" || entity.geometry(graph) !== "area") return false;
       return entity.tags.building && entity.tags.building !== "no";
     }
     var validation = function checkUnsquareWay(entity, graph) {
-      if (!isBuilding(entity, graph))
-        return [];
-      if (entity.tags.nonsquare === "yes")
-        return [];
+      if (!isBuilding(entity, graph)) return [];
+      if (entity.tags.nonsquare === "yes") return [];
       var isClosed = entity.isClosed();
-      if (!isClosed)
-        return [];
+      if (!isClosed) return [];
       var nodes = graph.childNodes(entity).slice();
-      if (nodes.length > nodeThreshold + 1)
-        return [];
+      if (nodes.length > nodeThreshold + 1) return [];
       var osm = services.osm;
       if (!osm || nodes.some(function(node) {
         return !osm.isDataLoaded(node.loc);
-      }))
-        return [];
+      })) return [];
       var hasConnectedSquarableWays = nodes.some(function(node) {
         return graph.parentWays(node).some(function(way) {
-          if (way.id === entity.id)
-            return false;
-          if (isBuilding(way, graph))
-            return true;
+          if (way.id === entity.id) return false;
+          if (isBuilding(way, graph)) return true;
           return graph.parentRelations(way).some(function(parentRelation) {
             return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== "no";
           });
         });
       });
-      if (hasConnectedSquarableWays)
-        return [];
+      if (hasConnectedSquarableWays) return [];
       var storedDegreeThreshold = corePreferences("validate-square-degrees");
       var degreeThreshold = isFinite(storedDegreeThreshold) ? Number(storedDegreeThreshold) : DEFAULT_DEG_THRESHOLD;
       var points = nodes.map(function(node) {
         return context.projection(node.loc);
       });
-      if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon3, degreeThreshold, true))
-        return [];
+      if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon3, degreeThreshold, true)) return [];
       var autoArgs;
       if (!entity.tags.wikidata) {
         var autoAction = actionOrthogonalize(entity.id, context.projection, void 0, degreeThreshold);
         const parts = rule.split("/", 2);
         const type2 = parts[0];
         const subtype = parts[1] || "*";
-        if (!type2 || !subtype)
-          return;
+        if (!type2 || !subtype) return;
         result.push({ type: makeRegExp(type2), subtype: makeRegExp(subtype) });
       });
       return result;
     }
     validator.init = () => {
       Object.values(validations_exports).forEach((validation) => {
-        if (typeof validation !== "function")
-          return;
+        if (typeof validation !== "function") return;
         const fn = validation(context);
         const key = fn.type;
         _rules[key] = fn;
       _deferredRIC = {};
       _deferredST.forEach(window.clearTimeout);
       _deferredST.clear();
-      if (resetIgnored)
-        _ignoredIssueIDs.clear();
+      if (resetIgnored) _ignoredIssueIDs.clear();
       _resolvedIssueIDs.clear();
       _baseCache = validationCache("base");
       _headCache = validationCache("head");
     };
     function revalidateUnsquare(cache) {
       const checkUnsquareWay = _rules.unsquare_way;
-      if (!cache.graph || typeof checkUnsquareWay !== "function")
-        return;
+      if (!cache.graph || typeof checkUnsquareWay !== "function") return;
       cache.uncacheIssuesOfType("unsquare_way");
       const buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), cache.graph).filter((entity) => entity.type === "way" && entity.tags.building && entity.tags.building !== "no");
       buildings.forEach((entity) => {
         const detected = checkUnsquareWay(entity, cache.graph);
-        if (!detected.length)
-          return;
+        if (!detected.length) return;
         cache.cacheIssues(detected);
       });
     }
       if (_headCache.graph && _headCache.graph !== _baseCache.graph) {
         Object.values(_headCache.issuesByIssueID).forEach((issue) => {
           const userModified = (issue.entityIds || []).some((id2) => _completeDiff.hasOwnProperty(id2));
-          if (opts.what === "edited" && !userModified)
-            return;
-          if (!filter2(issue))
-            return;
+          if (opts.what === "edited" && !userModified) return;
+          if (!filter2(issue)) return;
           seen.add(issue.id);
           results.push(issue);
         });
       }
       if (opts.what === "all") {
         Object.values(_baseCache.issuesByIssueID).forEach((issue) => {
-          if (!filter2(issue))
-            return;
+          if (!filter2(issue)) return;
           seen.add(issue.id);
           results.push(issue);
         });
       }
       return results;
       function filter2(issue) {
-        if (!issue)
-          return false;
-        if (seen.has(issue.id))
-          return false;
-        if (_resolvedIssueIDs.has(issue.id))
-          return false;
-        if (opts.includeDisabledRules === "only" && !_disabledRules[issue.type])
-          return false;
-        if (!opts.includeDisabledRules && _disabledRules[issue.type])
-          return false;
-        if (opts.includeIgnored === "only" && !_ignoredIssueIDs.has(issue.id))
-          return false;
-        if (!opts.includeIgnored && _ignoredIssueIDs.has(issue.id))
-          return false;
-        if ((issue.entityIds || []).some((id2) => !context.hasEntity(id2)))
-          return false;
+        if (!issue) return false;
+        if (seen.has(issue.id)) return false;
+        if (_resolvedIssueIDs.has(issue.id)) return false;
+        if (opts.includeDisabledRules === "only" && !_disabledRules[issue.type]) return false;
+        if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
+        if (opts.includeIgnored === "only" && !_ignoredIssueIDs.has(issue.id)) return false;
+        if (!opts.includeIgnored && _ignoredIssueIDs.has(issue.id)) return false;
+        if ((issue.entityIds || []).some((id2) => !context.hasEntity(id2))) return false;
         if (opts.where === "visible") {
           const extent = issue.extent(context.graph());
-          if (!view.intersects(extent))
-            return false;
+          if (!view.intersects(extent)) return false;
         }
         return true;
       }
     };
     validator.validate = () => {
       const baseGraph = context.history().base();
-      if (!_headCache.graph)
-        _headCache.graph = baseGraph;
-      if (!_baseCache.graph)
-        _baseCache.graph = baseGraph;
+      if (!_headCache.graph) _headCache.graph = baseGraph;
+      if (!_baseCache.graph) _baseCache.graph = baseGraph;
       const prevGraph = _headCache.graph;
       const currGraph = context.graph();
       if (currGraph === prevGraph) {
     });
     context.on("exit.validator", validator.validate);
     context.history().on("merge.validator", (entities) => {
-      if (!entities)
-        return;
+      if (!entities) return;
       const baseGraph = context.history().base();
-      if (!_headCache.graph)
-        _headCache.graph = baseGraph;
-      if (!_baseCache.graph)
-        _baseCache.graph = baseGraph;
+      if (!_headCache.graph) _headCache.graph = baseGraph;
+      if (!_baseCache.graph) _baseCache.graph = baseGraph;
       let entityIDs = entities.map((entity) => entity.id);
       entityIDs = _baseCache.withAllRelatedEntities(entityIDs);
       validateEntitiesAsync(entityIDs, _baseCache);
     function updateResolvedIssues(entityIDs) {
       entityIDs.forEach((entityID) => {
         const baseIssues = _baseCache.issuesByEntityID[entityID];
-        if (!baseIssues)
-          return;
+        if (!baseIssues) return;
         baseIssues.forEach((issueID) => {
           const issue = _baseCache.issuesByIssueID[issueID];
           const userModified = (issue.entityIds || []).some((id2) => _completeDiff.hasOwnProperty(id2));
     }
     function validateEntitiesAsync(entityIDs, cache) {
       const jobs = Array.from(entityIDs).map((entityID) => {
-        if (cache.queuedEntityIDs.has(entityID))
-          return null;
+        if (cache.queuedEntityIDs.has(entityID)) return null;
         cache.queuedEntityIDs.add(entityID);
         cache.uncacheEntityID(entityID);
         return () => {
           cache.queuedEntityIDs.delete(entityID);
           const graph = cache.graph;
-          if (!graph)
-            return;
+          if (!graph) return;
           const entity = graph.hasEntity(entityID);
-          if (!entity)
-            return;
+          if (!entity) return;
           const result = validateEntity(entity, graph);
           if (result.provisional) {
             cache.provisionalEntityIDs.add(entityID);
         };
       }).filter(Boolean);
       cache.queue = cache.queue.concat(utilArrayChunk(jobs, 100));
-      if (cache.queuePromise)
-        return cache.queuePromise;
+      if (cache.queuePromise) return cache.queuePromise;
       cache.queuePromise = processQueue(cache).then(() => revalidateProvisionalEntities(cache)).catch(() => {
       }).finally(() => cache.queuePromise = null);
       return cache.queuePromise;
     }
     function revalidateProvisionalEntities(cache) {
-      if (!cache.provisionalEntityIDs.size)
-        return;
+      if (!cache.provisionalEntityIDs.size) return;
       const handle = window.setTimeout(() => {
         _deferredST.delete(handle);
-        if (!cache.provisionalEntityIDs.size)
-          return;
+        if (!cache.provisionalEntityIDs.size) return;
         validateEntitiesAsync(Array.from(cache.provisionalEntityIDs), cache);
       }, RETRY);
       _deferredST.add(handle);
     }
     function processQueue(cache) {
-      if (!cache.queue.length)
-        return Promise.resolve();
+      if (!cache.queue.length) return Promise.resolve();
       const chunk = cache.queue.pop();
       return new Promise((resolvePromise, rejectPromise) => {
         const handle = window.requestIdleCallback(() => {
         });
         _deferredRIC[handle] = rejectPromise;
       }).then(() => {
-        if (cache.queue.length % 25 === 0)
-          dispatch14.call("validated");
+        if (cache.queue.length % 25 === 0) dispatch14.call("validated");
       }).then(() => processQueue(cache));
     }
     return validator;
         return;
       }
       var osm = context.connection();
-      if (!osm)
-        return;
+      if (!osm) return;
       if (!osm.authenticated()) {
         osm.authenticate(function(err) {
           if (!err) {
     };
     function performFullConflictCheck(changeset) {
       var osm = context.connection();
-      if (!osm)
-        return;
+      if (!osm) return;
       var history = context.history();
       var localGraph = context.graph();
       var remoteGraph = coreGraph(history.base(), true);
         var s2 = new Set(ids);
         ids.forEach(function(id2) {
           var entity = graph.entity(id2);
-          if (entity.type !== "way")
-            return;
+          if (entity.type !== "way") return;
           graph.childNodes(entity).forEach(function(child) {
             if (child.version !== void 0) {
               s2.add(child.id);
         return Array.from(s2);
       }
       function loaded(err, result) {
-        if (_errors.length)
-          return;
+        if (_errors.length) return;
         if (err) {
           _errors.push({
             msg: err.message || err.responseText,
             _toLoad = _toLoad.filter(function(val) {
               return val !== entity.id;
             });
-            if (!entity.visible)
-              return;
+            if (!entity.visible) return;
             var i4, id2;
             if (entity.type === "way") {
               for (i4 = 0; i4 < entity.nodes.length; i4++) {
           return utilDisplayName(entity) || utilDisplayType(entity.id) + " " + entity.id;
         }
         function sameVersions(local, remote) {
-          if (local.version !== remote.version)
-            return false;
+          if (local.version !== remote.version) return false;
           if (local.type === "way") {
             var children2 = utilArrayUnion(local.nodes, remote.nodes);
             for (var i4 = 0; i4 < children2.length; i4++) {
               var a2 = localGraph.hasEntity(children2[i4]);
               var b2 = remoteGraph.hasEntity(children2[i4]);
-              if (a2 && b2 && a2.version !== b2.version)
-                return false;
+              if (a2 && b2 && a2.version !== b2.version) return false;
             }
           }
           return true;
         _toCheck.forEach(function(id2) {
           var local = localGraph.entity(id2);
           var remote = remoteGraph.entity(id2);
-          if (sameVersions(local, remote))
-            return;
+          if (sameVersions(local, remote)) return;
           var merge2 = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags, formatUser);
           history.replace(merge2);
           var mergeConflicts = merge2.conflicts();
-          if (!mergeConflicts.length)
-            return;
+          if (!mergeConflicts.length) return;
           var forceLocal = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags).withOption("force_local");
           var forceRemote = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags).withOption("force_remote");
           var keepMine = _t("save.conflict." + (remote.visible ? "keep_local" : "restore"));
     return uploader;
   }
 
-  // modules/renderer/background_source.js
-  var import_lodash4 = __toESM(require_lodash());
-
-  // modules/util/IntervalTasksQueue.js
-  var IntervalTasksQueue = class {
-    /**
-     * Interval in milliseconds inside which only 1 task can execute.
-     * e.g. if interval is 200ms, and 5 async tasks are unqueued,
-     * they will complete in ~1s if not cleared
-     * @param {number} intervalInMs
-     */
-    constructor(intervalInMs) {
-      this.intervalInMs = intervalInMs;
-      this.pendingHandles = [];
-      this.time = 0;
-    }
-    enqueue(task) {
-      let taskTimeout = this.time;
-      this.time += this.intervalInMs;
-      this.pendingHandles.push(setTimeout(() => {
-        this.time -= this.intervalInMs;
-        task();
-      }, taskTimeout));
-    }
-    clear() {
-      this.pendingHandles.forEach((timeoutHandle) => {
-        clearTimeout(timeoutHandle);
-      });
-      this.pendingHandles = [];
-      this.time = 0;
-    }
-  };
-
-  // modules/renderer/background_source.js
-  var isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
-  window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function() {
-    isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
-  });
-  function localeDateString(s2) {
-    if (!s2)
-      return null;
-    var options2 = { day: "numeric", month: "short", year: "numeric" };
-    var d2 = new Date(s2);
-    if (isNaN(d2.getTime()))
-      return null;
-    return d2.toLocaleDateString(_mainLocalizer.localeCode(), options2);
-  }
-  function vintageRange(vintage) {
-    var s2;
-    if (vintage.start || vintage.end) {
-      s2 = vintage.start || "?";
-      if (vintage.start !== vintage.end) {
-        s2 += " - " + (vintage.end || "?");
-      }
-    }
-    return s2;
-  }
-  function rendererBackgroundSource(data) {
-    var source = Object.assign({}, data);
-    var _offset = [0, 0];
-    var _name = source.name;
-    var _description = source.description;
-    var _best = !!source.best;
-    var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
-    source.tileSize = data.tileSize || 256;
-    source.zoomExtent = data.zoomExtent || [0, 22];
-    source.overzoom = data.overzoom !== false;
-    source.offset = function(val) {
-      if (!arguments.length)
-        return _offset;
-      _offset = val;
-      return source;
+  // modules/modes/draw_area.js
+  function modeDrawArea(context, wayID, startGraph, button) {
+    var mode = {
+      button,
+      id: "draw-area"
     };
-    source.nudge = function(val, zoomlevel) {
-      _offset[0] += val[0] / Math.pow(2, zoomlevel);
-      _offset[1] += val[1] / Math.pow(2, zoomlevel);
-      return source;
+    var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on("rejectedSelfIntersection.modeDrawArea", function() {
+      context.ui().flash.iconName("#iD-icon-no").label(_t.append("self_intersection.error.areas"))();
+    });
+    mode.wayID = wayID;
+    mode.enter = function() {
+      context.install(behavior);
     };
-    source.name = function() {
-      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
-      return _t("imagery." + id_safe + ".name", { default: (0, import_lodash4.escape)(_name) });
+    mode.exit = function() {
+      context.uninstall(behavior);
     };
-    source.label = function() {
-      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
-      return _t.append("imagery." + id_safe + ".name", { default: (0, import_lodash4.escape)(_name) });
+    mode.selectedIDs = function() {
+      return [wayID];
     };
-    source.hasDescription = function() {
-      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
-      var descriptionText = _mainLocalizer.tInfo("imagery." + id_safe + ".description", { default: (0, import_lodash4.escape)(_description) }).text;
-      return descriptionText !== "";
+    mode.activeID = function() {
+      return behavior && behavior.activeID() || [];
     };
-    source.description = function() {
-      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
-      return _t.append("imagery." + id_safe + ".description", { default: (0, import_lodash4.escape)(_description) });
+    return mode;
+  }
+
+  // modules/modes/add_area.js
+  function modeAddArea(context, mode) {
+    mode.id = "add-area";
+    var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
+    function defaultTags(loc) {
+      var defaultTags2 = { area: "yes" };
+      if (mode.preset) defaultTags2 = mode.preset.setTags(defaultTags2, "area", false, loc);
+      return defaultTags2;
+    }
+    function actionClose(wayId) {
+      return function(graph) {
+        return graph.replace(graph.entity(wayId).close());
+      };
+    }
+    function start2(loc) {
+      var startGraph = context.graph();
+      var node = osmNode({ loc });
+      var way = osmWay({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id),
+        actionClose(way.id)
+      );
+      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    }
+    function startFromWay(loc, edge) {
+      var startGraph = context.graph();
+      var node = osmNode({ loc });
+      var way = osmWay({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id),
+        actionClose(way.id),
+        actionAddMidpoint({ loc, edge }, node)
+      );
+      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    }
+    function startFromNode(node) {
+      var startGraph = context.graph();
+      var way = osmWay({ tags: defaultTags(node.loc) });
+      context.perform(
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id),
+        actionClose(way.id)
+      );
+      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    }
+    mode.enter = function() {
+      context.install(behavior);
     };
-    source.best = function() {
-      return _best;
+    mode.exit = function() {
+      context.uninstall(behavior);
     };
-    source.area = function() {
-      if (!data.polygon)
-        return Number.MAX_VALUE;
-      var area = area_default({ type: "MultiPolygon", coordinates: [data.polygon] });
-      return isNaN(area) ? 0 : area;
+    return mode;
+  }
+
+  // modules/modes/add_line.js
+  function modeAddLine(context, mode) {
+    mode.id = "add-line";
+    var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
+    function defaultTags(loc) {
+      var defaultTags2 = {};
+      if (mode.preset) defaultTags2 = mode.preset.setTags(defaultTags2, "line", false, loc);
+      return defaultTags2;
+    }
+    function start2(loc) {
+      var startGraph = context.graph();
+      var node = osmNode({ loc });
+      var way = osmWay({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id)
+      );
+      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+    }
+    function startFromWay(loc, edge) {
+      var startGraph = context.graph();
+      var node = osmNode({ loc });
+      var way = osmWay({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id),
+        actionAddMidpoint({ loc, edge }, node)
+      );
+      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+    }
+    function startFromNode(node) {
+      var startGraph = context.graph();
+      var way = osmWay({ tags: defaultTags(node.loc) });
+      context.perform(
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id)
+      );
+      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+    }
+    mode.enter = function() {
+      context.install(behavior);
     };
-    source.imageryUsed = function() {
-      return _name || source.id;
+    mode.exit = function() {
+      context.uninstall(behavior);
     };
-    source.template = function(val) {
-      if (!arguments.length)
-        return _template;
-      if (source.id === "custom" || source.id === "Bing") {
-        _template = val;
+    return mode;
+  }
+
+  // modules/modes/add_point.js
+  function modeAddPoint(context, mode) {
+    mode.id = "add-point";
+    var behavior = behaviorDraw(context).on("click", add).on("clickWay", addWay).on("clickNode", addNode).on("cancel", cancel).on("finish", cancel);
+    function defaultTags(loc) {
+      var defaultTags2 = {};
+      if (mode.preset) defaultTags2 = mode.preset.setTags(defaultTags2, "point", false, loc);
+      return defaultTags2;
+    }
+    function add(loc) {
+      var node = osmNode({ loc, tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        _t("operations.add.annotation.point")
+      );
+      enterSelectMode(node);
+    }
+    function addWay(loc, edge) {
+      var node = osmNode({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddMidpoint({ loc, edge }, node),
+        _t("operations.add.annotation.vertex")
+      );
+      enterSelectMode(node);
+    }
+    function enterSelectMode(node) {
+      context.enter(
+        modeSelect(context, [node.id]).newFeature(true)
+      );
+    }
+    function addNode(node) {
+      const _defaultTags = defaultTags(node.loc);
+      if (Object.keys(_defaultTags).length === 0) {
+        enterSelectMode(node);
+        return;
       }
-      return source;
+      var tags = Object.assign({}, node.tags);
+      for (var key in _defaultTags) {
+        tags[key] = _defaultTags[key];
+      }
+      context.perform(
+        actionChangeTags(node.id, tags),
+        _t("operations.add.annotation.point")
+      );
+      enterSelectMode(node);
+    }
+    function cancel() {
+      context.enter(modeBrowse(context));
+    }
+    mode.enter = function() {
+      context.install(behavior);
     };
-    source.url = function(coord2) {
-      var result = _template.replace(/#[\s\S]*/u, "");
-      if (result === "")
-        return result;
-      if (!source.type || source.id === "custom") {
-        if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(result)) {
-          source.type = "wms";
-          source.projection = "EPSG:3857";
-        } else if (/\{(x|y)\}/.test(result)) {
-          source.type = "tms";
-        } else if (/\{u\}/.test(result)) {
-          source.type = "bing";
+    mode.exit = function() {
+      context.uninstall(behavior);
+    };
+    return mode;
+  }
+
+  // modules/ui/note_comments.js
+  function uiNoteComments() {
+    var _note;
+    function noteComments(selection2) {
+      if (_note.isNew()) return;
+      var comments = selection2.selectAll(".comments-container").data([0]);
+      comments = comments.enter().append("div").attr("class", "comments-container").merge(comments);
+      var commentEnter = comments.selectAll(".comment").data(_note.comments).enter().append("div").attr("class", "comment");
+      commentEnter.append("div").attr("class", function(d2) {
+        return "comment-avatar user-" + d2.uid;
+      }).call(svgIcon("#iD-icon-avatar", "comment-avatar-icon"));
+      var mainEnter = commentEnter.append("div").attr("class", "comment-main");
+      var metadataEnter = mainEnter.append("div").attr("class", "comment-metadata");
+      metadataEnter.append("div").attr("class", "comment-author").each(function(d2) {
+        var selection3 = select_default2(this);
+        var osm = services.osm;
+        if (osm && d2.user) {
+          selection3 = selection3.append("a").attr("class", "comment-author-link").attr("href", osm.userURL(d2.user)).attr("target", "_blank");
+        }
+        if (d2.user) {
+          selection3.text(d2.user);
+        } else {
+          selection3.call(_t.append("note.anonymous"));
         }
-      }
-      if (source.type === "wms") {
-        var tileToProjectedCoords = function(x2, y2, z2) {
-          var zoomSize = Math.pow(2, z2);
-          var lon = x2 / zoomSize * Math.PI * 2 - Math.PI;
-          var lat = Math.atan(Math.sinh(Math.PI * (1 - 2 * y2 / zoomSize)));
-          switch (source.projection) {
-            case "EPSG:4326":
-              return {
-                x: lon * 180 / Math.PI,
-                y: lat * 180 / Math.PI
-              };
-            default:
-              var mercCoords = mercatorRaw(lon, lat);
-              return {
-                x: 2003750834e-2 / Math.PI * mercCoords[0],
-                y: 2003750834e-2 / Math.PI * mercCoords[1]
-              };
-          }
-        };
-        var tileSize = source.tileSize;
-        var projection2 = source.projection;
-        var minXmaxY = tileToProjectedCoords(coord2[0], coord2[1], coord2[2]);
-        var maxXminY = tileToProjectedCoords(coord2[0] + 1, coord2[1] + 1, coord2[2]);
-        result = result.replace(/\{(\w+)\}/g, function(token, key) {
-          switch (key) {
-            case "width":
-            case "height":
-              return tileSize;
-            case "proj":
-              return projection2;
-            case "wkid":
-              return projection2.replace(/^EPSG:/, "");
-            case "bbox":
-              if (projection2 === "EPSG:4326" && // The CRS parameter implies version 1.3 (prior versions use SRS)
-              /VERSION=1.3|CRS={proj}/.test(source.template().toUpperCase())) {
-                return maxXminY.y + "," + minXmaxY.x + "," + minXmaxY.y + "," + maxXminY.x;
-              } else {
-                return minXmaxY.x + "," + maxXminY.y + "," + maxXminY.x + "," + minXmaxY.y;
-              }
-            case "w":
-              return minXmaxY.x;
-            case "s":
-              return maxXminY.y;
-            case "n":
-              return maxXminY.x;
-            case "e":
-              return minXmaxY.y;
-            default:
-              return token;
-          }
-        });
-      } else if (source.type === "tms") {
-        result = result.replace("{x}", coord2[0]).replace("{y}", coord2[1]).replace(/\{[t-]y\}/, Math.pow(2, coord2[2]) - coord2[1] - 1).replace(/\{z(oom)?\}/, coord2[2]).replace(/\{@2x\}|\{r\}/, isRetina ? "@2x" : "");
-      } else if (source.type === "bing") {
-        result = result.replace("{u}", function() {
-          var u2 = "";
-          for (var zoom = coord2[2]; zoom > 0; zoom--) {
-            var b2 = 0;
-            var mask = 1 << zoom - 1;
-            if ((coord2[0] & mask) !== 0)
-              b2++;
-            if ((coord2[1] & mask) !== 0)
-              b2 += 2;
-            u2 += b2.toString();
-          }
-          return u2;
-        });
-      }
-      result = result.replace(/\{switch:([^}]+)\}/, function(s2, r2) {
-        var subdomains = r2.split(",");
-        return subdomains[(coord2[0] + coord2[1]) % subdomains.length];
       });
-      return result;
-    };
-    source.validZoom = function(z2) {
-      return source.zoomExtent[0] <= z2 && (source.overzoom || source.zoomExtent[1] > z2);
-    };
-    source.isLocatorOverlay = function() {
-      return source.id === "mapbox_locator_overlay";
-    };
-    source.isHidden = function() {
-      return source.id === "DigitalGlobe-Premium-vintage" || source.id === "DigitalGlobe-Standard-vintage";
-    };
-    source.copyrightNotices = function() {
-    };
-    source.getMetadata = function(center, tileCoord, callback) {
-      var vintage = {
-        start: localeDateString(source.startDate),
-        end: localeDateString(source.endDate)
-      };
-      vintage.range = vintageRange(vintage);
-      var metadata = { vintage };
-      callback(null, metadata);
-    };
-    return source;
-  }
-  rendererBackgroundSource.Bing = function(data, dispatch14) {
-    data.template = "https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=1&pr=odbl&n=z";
-    var bing = rendererBackgroundSource(data);
-    var key = utilAesDecrypt("5c875730b09c6b422433e807e1ff060b6536c791dbfffcffc4c6b18a1bdba1f14593d151adb50e19e1be1ab19aef813bf135d0f103475e5c724dec94389e45d0");
-    const strictParam = "n";
-    var url = "https://dev.virtualearth.net/REST/v1/Imagery/Metadata/AerialOSM?include=ImageryProviders&uriScheme=https&key=" + key;
-    var cache = {};
-    var inflight = {};
-    var providers = [];
-    var taskQueue = new IntervalTasksQueue(250);
-    var metadataLastZoom = -1;
-    json_default(url).then(function(json) {
-      let imageryResource = json.resourceSets[0].resources[0];
-      let template = imageryResource.imageUrl;
-      let subDomains = imageryResource.imageUrlSubdomains;
-      let subDomainNumbers = subDomains.map((subDomain) => {
-        return subDomain.substring(1);
-      }).join(",");
-      template = template.replace("{subdomain}", "t{switch:".concat(subDomainNumbers, "}")).replace("{quadkey}", "{u}");
-      if (!new URLSearchParams(template).has(strictParam)) {
-        template += "&".concat(strictParam, "=z");
-      }
-      bing.template(template);
-      providers = imageryResource.imageryProviders.map(function(provider) {
-        return {
-          attribution: provider.attribution,
-          areas: provider.coverageAreas.map(function(area) {
-            return {
-              zoom: [area.zoomMin, area.zoomMax],
-              extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
-            };
-          })
-        };
+      metadataEnter.append("div").attr("class", "comment-date").html(function(d2) {
+        return _t.html("note.status." + d2.action, { when: localeDateString2(d2.date) });
       });
-      dispatch14.call("change");
-    }).catch(function() {
-    });
-    bing.copyrightNotices = function(zoom, extent) {
-      zoom = Math.min(zoom, 21);
-      return providers.filter(function(provider) {
-        return provider.areas.some(function(area) {
-          return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
-        });
-      }).map(function(provider) {
-        return provider.attribution;
-      }).join(", ");
-    };
-    bing.getMetadata = function(center, tileCoord, callback) {
-      var tileID = tileCoord.slice(0, 3).join("/");
-      var zoom = Math.min(tileCoord[2], 21);
-      var centerPoint = center[1] + "," + center[0];
-      var url2 = "https://dev.virtualearth.net/REST/v1/Imagery/BasicMetadata/AerialOSM/" + centerPoint + "?zl=" + zoom + "&key=" + key;
-      if (inflight[tileID])
-        return;
-      if (!cache[tileID]) {
-        cache[tileID] = {};
-      }
-      if (cache[tileID] && cache[tileID].metadata) {
-        return callback(null, cache[tileID].metadata);
-      }
-      inflight[tileID] = true;
-      if (metadataLastZoom !== tileCoord[2]) {
-        metadataLastZoom = tileCoord[2];
-        taskQueue.clear();
-      }
-      taskQueue.enqueue(() => {
-        json_default(url2).then(function(result) {
-          delete inflight[tileID];
-          if (!result) {
-            throw new Error("Unknown Error");
-          }
-          var vintage = {
-            start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
-            end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
-          };
-          vintage.range = vintageRange(vintage);
-          var metadata = { vintage };
-          cache[tileID].metadata = metadata;
-          if (callback)
-            callback(null, metadata);
-        }).catch(function(err) {
-          delete inflight[tileID];
-          if (callback)
-            callback(err.message);
+      mainEnter.append("div").attr("class", "comment-text").html(function(d2) {
+        return d2.html;
+      }).selectAll("a").attr("rel", "noopener nofollow").attr("target", "_blank");
+      comments.call(replaceAvatars);
+    }
+    function replaceAvatars(selection2) {
+      var showThirdPartyIcons = corePreferences("preferences.privacy.thirdpartyicons") || "true";
+      var osm = services.osm;
+      if (showThirdPartyIcons !== "true" || !osm) return;
+      var uids = {};
+      _note.comments.forEach(function(d2) {
+        if (d2.uid) uids[d2.uid] = true;
+      });
+      Object.keys(uids).forEach(function(uid) {
+        osm.loadUser(uid, function(err, user) {
+          if (!user || !user.image_url) return;
+          selection2.selectAll(".comment-avatar.user-" + uid).html("").append("img").attr("class", "icon comment-avatar-icon").attr("src", user.image_url).attr("alt", user.display_name);
         });
       });
-    };
-    bing.terms_url = "https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details";
-    return bing;
-  };
-  rendererBackgroundSource.Esri = function(data) {
-    if (data.template.match(/blankTile/) === null) {
-      data.template = data.template + "?blankTile=false";
     }
-    var esri = rendererBackgroundSource(data);
-    var cache = {};
-    var inflight = {};
-    var _prevCenter;
-    esri.fetchTilemap = function(center) {
-      if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5e3)
-        return;
-      _prevCenter = center;
-      var z2 = 20;
-      var dummyUrl = esri.url([1, 2, 3]);
-      var x2 = Math.floor((center[0] + 180) / 360 * Math.pow(2, z2));
-      var y2 = Math.floor((1 - Math.log(Math.tan(center[1] * Math.PI / 180) + 1 / Math.cos(center[1] * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, z2));
-      var tilemapUrl = dummyUrl.replace(/tile\/[0-9]+\/[0-9]+\/[0-9]+\?blankTile=false/, "tilemap") + "/" + z2 + "/" + y2 + "/" + x2 + "/8/8";
-      json_default(tilemapUrl).then(function(tilemap) {
-        if (!tilemap) {
-          throw new Error("Unknown Error");
-        }
-        var hasTiles = true;
-        for (var i3 = 0; i3 < tilemap.data.length; i3++) {
-          if (!tilemap.data[i3]) {
-            hasTiles = false;
-            break;
-          }
-        }
-        esri.zoomExtent[1] = hasTiles ? 22 : 19;
-      }).catch(function() {
-      });
+    function localeDateString2(s2) {
+      if (!s2) return null;
+      var options2 = { day: "numeric", month: "short", year: "numeric" };
+      s2 = s2.replace(/-/g, "/");
+      var d2 = new Date(s2);
+      if (isNaN(d2.getTime())) return null;
+      return d2.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+    }
+    noteComments.note = function(val) {
+      if (!arguments.length) return _note;
+      _note = val;
+      return noteComments;
     };
-    esri.getMetadata = function(center, tileCoord, callback) {
-      if (esri.id !== "EsriWorldImagery") {
-        return callback(null, {});
-      }
-      var tileID = tileCoord.slice(0, 3).join("/");
-      var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
-      var centerPoint = center[0] + "," + center[1];
-      var unknown = _t("info_panels.background.unknown");
-      var vintage = {};
-      var metadata = {};
-      if (inflight[tileID])
-        return;
-      var url = "https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/4/query";
-      url += "?returnGeometry=false&geometry=" + centerPoint + "&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json";
-      if (!cache[tileID]) {
-        cache[tileID] = {};
-      }
-      if (cache[tileID] && cache[tileID].metadata) {
-        return callback(null, cache[tileID].metadata);
-      }
-      inflight[tileID] = true;
-      json_default(url).then(function(result) {
-        delete inflight[tileID];
-        result = result.features.map((f2) => f2.attributes).filter((a2) => a2.MinMapLevel <= zoom && a2.MaxMapLevel >= zoom)[0];
-        if (!result) {
-          throw new Error("Unknown Error");
-        } else if (result.features && result.features.length < 1) {
-          throw new Error("No Results");
-        } else if (result.error && result.error.message) {
-          throw new Error(result.error.message);
-        }
-        var captureDate = localeDateString(result.SRC_DATE2);
-        vintage = {
-          start: captureDate,
-          end: captureDate,
-          range: captureDate
-        };
-        metadata = {
-          vintage,
-          source: clean2(result.NICE_NAME),
-          description: clean2(result.NICE_DESC),
-          resolution: clean2(+Number(result.SRC_RES).toFixed(4)),
-          accuracy: clean2(+Number(result.SRC_ACC).toFixed(4))
-        };
-        if (isFinite(metadata.resolution)) {
-          metadata.resolution += " m";
+    return noteComments;
+  }
+
+  // modules/ui/note_header.js
+  function uiNoteHeader() {
+    var _note;
+    function noteHeader(selection2) {
+      var header = selection2.selectAll(".note-header").data(
+        _note ? [_note] : [],
+        function(d2) {
+          return d2.status + d2.id;
         }
-        if (isFinite(metadata.accuracy)) {
-          metadata.accuracy += " m";
+      );
+      header.exit().remove();
+      var headerEnter = header.enter().append("div").attr("class", "note-header");
+      var iconEnter = headerEnter.append("div").attr("class", function(d2) {
+        return "note-header-icon " + d2.status;
+      }).classed("new", function(d2) {
+        return d2.id < 0;
+      });
+      iconEnter.append("div").attr("class", "preset-icon-28").call(svgIcon("#iD-icon-note", "note-fill"));
+      iconEnter.each(function(d2) {
+        var statusIcon;
+        if (d2.id < 0) {
+          statusIcon = "#iD-icon-plus";
+        } else if (d2.status === "open") {
+          statusIcon = "#iD-icon-close";
+        } else {
+          statusIcon = "#iD-icon-apply";
         }
-        cache[tileID].metadata = metadata;
-        if (callback)
-          callback(null, metadata);
-      }).catch(function(err) {
-        delete inflight[tileID];
-        if (callback)
-          callback(err.message);
+        iconEnter.append("div").attr("class", "note-icon-annotation").attr("title", _t("icons.close")).call(svgIcon(statusIcon, "icon-annotation"));
       });
-      function clean2(val) {
-        return String(val).trim() || unknown;
-      }
-    };
-    return esri;
-  };
-  rendererBackgroundSource.None = function() {
-    var source = rendererBackgroundSource({ id: "none", template: "" });
-    source.name = function() {
-      return _t("background.none");
-    };
-    source.label = function() {
-      return _t.append("background.none");
-    };
-    source.imageryUsed = function() {
-      return null;
-    };
-    source.area = function() {
-      return -1;
-    };
-    return source;
-  };
-  rendererBackgroundSource.Custom = function(template) {
-    var source = rendererBackgroundSource({ id: "custom", template });
-    source.name = function() {
-      return _t("background.custom");
-    };
-    source.label = function() {
-      return _t.append("background.custom");
-    };
-    source.imageryUsed = function() {
-      var cleaned = source.template();
-      if (cleaned.indexOf("?") !== -1) {
-        var parts = cleaned.split("?", 2);
-        var qs = utilStringQs(parts[1]);
-        ["access_token", "connectId", "token", "Signature"].forEach(function(param) {
-          if (qs[param]) {
-            qs[param] = "{apikey}";
-          }
-        });
-        cleaned = parts[0] + "?" + utilQsString(qs, true);
-      }
-      cleaned = cleaned.replace(/token\/(\w+)/, "token/{apikey}").replace(/key=(\w+)/, "key={apikey}");
-      return "Custom (" + cleaned + " )";
-    };
-    source.area = function() {
-      return -2;
-    };
-    return source;
-  };
-
-  // node_modules/@turf/helpers/dist/es/index.js
-  var earthRadius = 63710088e-1;
-  var factors = {
-    centimeters: earthRadius * 100,
-    centimetres: earthRadius * 100,
-    degrees: earthRadius / 111325,
-    feet: earthRadius * 3.28084,
-    inches: earthRadius * 39.37,
-    kilometers: earthRadius / 1e3,
-    kilometres: earthRadius / 1e3,
-    meters: earthRadius,
-    metres: earthRadius,
-    miles: earthRadius / 1609.344,
-    millimeters: earthRadius * 1e3,
-    millimetres: earthRadius * 1e3,
-    nauticalmiles: earthRadius / 1852,
-    radians: 1,
-    yards: earthRadius * 1.0936
-  };
-  var unitsFactors = {
-    centimeters: 100,
-    centimetres: 100,
-    degrees: 1 / 111325,
-    feet: 3.28084,
-    inches: 39.37,
-    kilometers: 1 / 1e3,
-    kilometres: 1 / 1e3,
-    meters: 1,
-    metres: 1,
-    miles: 1 / 1609.344,
-    millimeters: 1e3,
-    millimetres: 1e3,
-    nauticalmiles: 1 / 1852,
-    radians: 1 / earthRadius,
-    yards: 1.0936133
-  };
-  function feature2(geom, properties, options2) {
-    if (options2 === void 0) {
-      options2 = {};
-    }
-    var feat = { type: "Feature" };
-    if (options2.id === 0 || options2.id) {
-      feat.id = options2.id;
-    }
-    if (options2.bbox) {
-      feat.bbox = options2.bbox;
-    }
-    feat.properties = properties || {};
-    feat.geometry = geom;
-    return feat;
-  }
-  function polygon(coordinates, properties, options2) {
-    if (options2 === void 0) {
-      options2 = {};
-    }
-    for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
-      var ring = coordinates_1[_i];
-      if (ring.length < 4) {
-        throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
-      }
-      for (var j2 = 0; j2 < ring[ring.length - 1].length; j2++) {
-        if (ring[ring.length - 1][j2] !== ring[0][j2]) {
-          throw new Error("First and last Position are not equivalent.");
+      headerEnter.append("div").attr("class", "note-header-label").html(function(d2) {
+        if (_note.isNew()) {
+          return _t.html("note.new");
         }
-      }
-    }
-    var geom = {
-      type: "Polygon",
-      coordinates
-    };
-    return feature2(geom, properties, options2);
-  }
-  function lineString(coordinates, properties, options2) {
-    if (options2 === void 0) {
-      options2 = {};
-    }
-    if (coordinates.length < 2) {
-      throw new Error("coordinates must be an array of two or more positions");
+        return _t.html("note.note") + " " + d2.id + " " + (d2.status === "closed" ? _t.html("note.closed") : "");
+      });
     }
-    var geom = {
-      type: "LineString",
-      coordinates
+    noteHeader.note = function(val) {
+      if (!arguments.length) return _note;
+      _note = val;
+      return noteHeader;
     };
-    return feature2(geom, properties, options2);
+    return noteHeader;
   }
-  function multiLineString(coordinates, properties, options2) {
-    if (options2 === void 0) {
-      options2 = {};
+
+  // modules/ui/note_report.js
+  function uiNoteReport() {
+    var _note;
+    function noteReport(selection2) {
+      var url;
+      if (services.osm && _note instanceof osmNote && !_note.isNew()) {
+        url = services.osm.noteReportURL(_note);
+      }
+      var link3 = selection2.selectAll(".note-report").data(url ? [url] : []);
+      link3.exit().remove();
+      var linkEnter = link3.enter().append("a").attr("class", "note-report").attr("target", "_blank").attr("href", function(d2) {
+        return d2;
+      }).call(svgIcon("#iD-icon-out-link", "inline"));
+      linkEnter.append("span").call(_t.append("note.report"));
     }
-    var geom = {
-      type: "MultiLineString",
-      coordinates
+    noteReport.note = function(val) {
+      if (!arguments.length) return _note;
+      _note = val;
+      return noteReport;
     };
-    return feature2(geom, properties, options2);
+    return noteReport;
   }
-  function multiPolygon(coordinates, properties, options2) {
-    if (options2 === void 0) {
-      options2 = {};
+
+  // modules/ui/view_on_osm.js
+  function uiViewOnOSM(context) {
+    var _what;
+    function viewOnOSM(selection2) {
+      var url;
+      if (_what instanceof osmEntity) {
+        url = context.connection().entityURL(_what);
+      } else if (_what instanceof osmNote) {
+        url = context.connection().noteURL(_what);
+      }
+      var data = !_what || _what.isNew() ? [] : [_what];
+      var link3 = selection2.selectAll(".view-on-osm").data(data, function(d2) {
+        return d2.id;
+      });
+      link3.exit().remove();
+      var linkEnter = link3.enter().append("a").attr("class", "view-on-osm").attr("target", "_blank").attr("href", url).call(svgIcon("#iD-icon-out-link", "inline"));
+      linkEnter.append("span").call(_t.append("inspector.view_on_osm"));
     }
-    var geom = {
-      type: "MultiPolygon",
-      coordinates
+    viewOnOSM.what = function(_2) {
+      if (!arguments.length) return _what;
+      _what = _2;
+      return viewOnOSM;
     };
-    return feature2(geom, properties, options2);
+    return viewOnOSM;
   }
 
-  // node_modules/@turf/invariant/dist/es/index.js
-  function getGeom(geojson) {
-    if (geojson.type === "Feature") {
-      return geojson.geometry;
+  // modules/ui/note_editor.js
+  function uiNoteEditor(context) {
+    var dispatch14 = dispatch_default("change");
+    var noteComments = uiNoteComments(context);
+    var noteHeader = uiNoteHeader();
+    var _note;
+    var _newNote;
+    function noteEditor(selection2) {
+      var header = selection2.selectAll(".header").data([0]);
+      var headerEnter = header.enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
+        context.enter(modeBrowse(context));
+      }).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("note.title"));
+      var body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      var editor = body.selectAll(".note-editor").data([0]);
+      editor.enter().append("div").attr("class", "modal-section note-editor").merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
+      var footer = selection2.selectAll(".footer").data([0]);
+      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnOSM(context).what(_note)).call(uiNoteReport(context).note(_note));
+      var osm = services.osm;
+      if (osm) {
+        osm.on("change.note-save", function() {
+          selection2.call(noteEditor);
+        });
+      }
     }
-    return geojson;
-  }
-
-  // node_modules/@turf/bbox-clip/dist/es/lib/lineclip.js
-  function lineclip(points, bbox2, result) {
-    var len = points.length, codeA = bitCode(points[0], bbox2), part = [], i3, codeB, lastCode;
-    var a2;
-    var b2;
-    if (!result)
-      result = [];
-    for (i3 = 1; i3 < len; i3++) {
-      a2 = points[i3 - 1];
-      b2 = points[i3];
-      codeB = lastCode = bitCode(b2, bbox2);
-      while (true) {
-        if (!(codeA | codeB)) {
-          part.push(a2);
-          if (codeB !== lastCode) {
-            part.push(b2);
-            if (i3 < len - 1) {
-              result.push(part);
-              part = [];
-            }
-          } else if (i3 === len - 1) {
-            part.push(b2);
-          }
-          break;
-        } else if (codeA & codeB) {
-          break;
-        } else if (codeA) {
-          a2 = intersect(a2, b2, codeA, bbox2);
-          codeA = bitCode(a2, bbox2);
+    function noteSaveSection(selection2) {
+      var isSelected = _note && _note.id === context.selectedNoteID();
+      var noteSave = selection2.selectAll(".note-save").data(isSelected ? [_note] : [], function(d2) {
+        return d2.status + d2.id;
+      });
+      noteSave.exit().remove();
+      var noteSaveEnter = noteSave.enter().append("div").attr("class", "note-save save-section cf");
+      noteSaveEnter.append("h4").attr("class", ".note-save-header").text("").each(function() {
+        if (_note.isNew()) {
+          _t.append("note.newDescription")(select_default2(this));
         } else {
-          b2 = intersect(a2, b2, codeB, bbox2);
-          codeB = bitCode(b2, bbox2);
+          _t.append("note.newComment")(select_default2(this));
         }
+      });
+      var commentTextarea = noteSaveEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("note.inputPlaceholder")).attr("maxlength", 1e3).property("value", function(d2) {
+        return d2.newComment;
+      }).call(utilNoAuto).on("keydown.note-input", keydown).on("input.note-input", changeInput).on("blur.note-input", changeInput);
+      if (!commentTextarea.empty() && _newNote) {
+        commentTextarea.node().focus();
       }
-      codeA = lastCode;
-    }
-    if (part.length)
-      result.push(part);
-    return result;
-  }
-  function polygonclip(points, bbox2) {
-    var result, edge, prev, prevInside, i3, p2, inside;
-    for (edge = 1; edge <= 8; edge *= 2) {
-      result = [];
-      prev = points[points.length - 1];
-      prevInside = !(bitCode(prev, bbox2) & edge);
-      for (i3 = 0; i3 < points.length; i3++) {
-        p2 = points[i3];
-        inside = !(bitCode(p2, bbox2) & edge);
-        if (inside !== prevInside)
-          result.push(intersect(prev, p2, edge, bbox2));
-        if (inside)
-          result.push(p2);
-        prev = p2;
-        prevInside = inside;
+      noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons);
+      function keydown(d3_event) {
+        if (!(d3_event.keyCode === 13 && // ↩ Return
+        d3_event.metaKey)) return;
+        var osm = services.osm;
+        if (!osm) return;
+        var hasAuth = osm.authenticated();
+        if (!hasAuth) return;
+        if (!_note.newComment) return;
+        d3_event.preventDefault();
+        select_default2(this).on("keydown.note-input", null);
+        window.setTimeout(function() {
+          if (_note.isNew()) {
+            noteSave.selectAll(".save-button").node().focus();
+            clickSave(_note);
+          } else {
+            noteSave.selectAll(".comment-button").node().focus();
+            clickComment(_note);
+          }
+        }, 10);
       }
-      points = result;
-      if (!points.length)
-        break;
-    }
-    return result;
-  }
-  function intersect(a2, b2, edge, bbox2) {
-    return edge & 8 ? [a2[0] + (b2[0] - a2[0]) * (bbox2[3] - a2[1]) / (b2[1] - a2[1]), bbox2[3]] : edge & 4 ? [a2[0] + (b2[0] - a2[0]) * (bbox2[1] - a2[1]) / (b2[1] - a2[1]), bbox2[1]] : edge & 2 ? [bbox2[2], a2[1] + (b2[1] - a2[1]) * (bbox2[2] - a2[0]) / (b2[0] - a2[0])] : edge & 1 ? [bbox2[0], a2[1] + (b2[1] - a2[1]) * (bbox2[0] - a2[0]) / (b2[0] - a2[0])] : null;
-  }
-  function bitCode(p2, bbox2) {
-    var code = 0;
-    if (p2[0] < bbox2[0])
-      code |= 1;
-    else if (p2[0] > bbox2[2])
-      code |= 2;
-    if (p2[1] < bbox2[1])
-      code |= 4;
-    else if (p2[1] > bbox2[3])
-      code |= 8;
-    return code;
-  }
-
-  // node_modules/@turf/bbox-clip/dist/es/index.js
-  function bboxClip(feature3, bbox2) {
-    var geom = getGeom(feature3);
-    var type2 = geom.type;
-    var properties = feature3.type === "Feature" ? feature3.properties : {};
-    var coords = geom.coordinates;
-    switch (type2) {
-      case "LineString":
-      case "MultiLineString": {
-        var lines_1 = [];
-        if (type2 === "LineString") {
-          coords = [coords];
-        }
-        coords.forEach(function(line) {
-          lineclip(line, bbox2, lines_1);
-        });
-        if (lines_1.length === 1) {
-          return lineString(lines_1[0], properties);
+      function changeInput() {
+        var input = select_default2(this);
+        var val = input.property("value").trim() || void 0;
+        _note = _note.update({ newComment: val });
+        var osm = services.osm;
+        if (osm) {
+          osm.replaceNote(_note);
         }
-        return multiLineString(lines_1, properties);
+        noteSave.call(noteSaveButtons);
       }
-      case "Polygon":
-        return polygon(clipPolygon(coords, bbox2), properties);
-      case "MultiPolygon":
-        return multiPolygon(coords.map(function(poly) {
-          return clipPolygon(poly, bbox2);
-        }), properties);
-      default:
-        throw new Error("geometry " + type2 + " not supported");
     }
-  }
-  function clipPolygon(rings, bbox2) {
-    var outRings = [];
-    for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
-      var ring = rings_1[_i];
-      var clipped = polygonclip(ring, bbox2);
-      if (clipped.length > 0) {
-        if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
-          clipped.push(clipped[0]);
-        }
-        if (clipped.length >= 4) {
-          outRings.push(clipped);
+    function userDetails(selection2) {
+      var detailSection = selection2.selectAll(".detail-section").data([0]);
+      detailSection = detailSection.enter().append("div").attr("class", "detail-section").merge(detailSection);
+      var osm = services.osm;
+      if (!osm) return;
+      var hasAuth = osm.authenticated();
+      var authWarning = detailSection.selectAll(".auth-warning").data(hasAuth ? [] : [0]);
+      authWarning.exit().transition().duration(200).style("opacity", 0).remove();
+      var authEnter = authWarning.enter().insert("div", ".tag-reference-body").attr("class", "field-warning auth-warning").style("opacity", 0);
+      authEnter.call(svgIcon("#iD-icon-alert", "inline"));
+      authEnter.append("span").call(_t.append("note.login"));
+      authEnter.append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("login")).on("click.note-login", function(d3_event) {
+        d3_event.preventDefault();
+        osm.authenticate();
+      });
+      authEnter.transition().duration(200).style("opacity", 1);
+      var prose = detailSection.selectAll(".note-save-prose").data(hasAuth ? [0] : []);
+      prose.exit().remove();
+      prose = prose.enter().append("p").attr("class", "note-save-prose").call(_t.append("note.upload_explanation")).merge(prose);
+      osm.userDetails(function(err, user) {
+        if (err) return;
+        var userLink = select_default2(document.createElement("div"));
+        if (user.image_url) {
+          userLink.append("img").attr("src", user.image_url).attr("class", "icon pre-text user-icon");
         }
-      }
+        userLink.append("a").attr("class", "user-info").text(user.display_name).attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
+        prose.html(_t.html("note.upload_explanation_with_user", { user: { html: userLink.html() } }));
+      });
     }
-    return outRings;
-  }
-
-  // node_modules/@turf/meta/dist/es/index.js
-  function coordEach(geojson, callback, excludeWrapCoord) {
-    if (geojson === null)
-      return;
-    var j2, k2, l2, geometry, stopG, coords, geometryMaybeCollection, wrapShrink = 0, coordIndex = 0, isGeometryCollection, type2 = geojson.type, isFeatureCollection = type2 === "FeatureCollection", isFeature = type2 === "Feature", stop = isFeatureCollection ? geojson.features.length : 1;
-    for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
-      geometryMaybeCollection = isFeatureCollection ? geojson.features[featureIndex].geometry : isFeature ? geojson.geometry : geojson;
-      isGeometryCollection = geometryMaybeCollection ? geometryMaybeCollection.type === "GeometryCollection" : false;
-      stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
-      for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
-        var multiFeatureIndex = 0;
-        var geometryIndex = 0;
-        geometry = isGeometryCollection ? geometryMaybeCollection.geometries[geomIndex] : geometryMaybeCollection;
-        if (geometry === null)
-          continue;
-        coords = geometry.coordinates;
-        var geomType = geometry.type;
-        wrapShrink = excludeWrapCoord && (geomType === "Polygon" || geomType === "MultiPolygon") ? 1 : 0;
-        switch (geomType) {
-          case null:
-            break;
-          case "Point":
-            if (callback(
-              coords,
-              coordIndex,
-              featureIndex,
-              multiFeatureIndex,
-              geometryIndex
-            ) === false)
-              return false;
-            coordIndex++;
-            multiFeatureIndex++;
-            break;
-          case "LineString":
-          case "MultiPoint":
-            for (j2 = 0; j2 < coords.length; j2++) {
-              if (callback(
-                coords[j2],
-                coordIndex,
-                featureIndex,
-                multiFeatureIndex,
-                geometryIndex
-              ) === false)
-                return false;
-              coordIndex++;
-              if (geomType === "MultiPoint")
-                multiFeatureIndex++;
-            }
-            if (geomType === "LineString")
-              multiFeatureIndex++;
-            break;
-          case "Polygon":
-          case "MultiLineString":
-            for (j2 = 0; j2 < coords.length; j2++) {
-              for (k2 = 0; k2 < coords[j2].length - wrapShrink; k2++) {
-                if (callback(
-                  coords[j2][k2],
-                  coordIndex,
-                  featureIndex,
-                  multiFeatureIndex,
-                  geometryIndex
-                ) === false)
-                  return false;
-                coordIndex++;
-              }
-              if (geomType === "MultiLineString")
-                multiFeatureIndex++;
-              if (geomType === "Polygon")
-                geometryIndex++;
-            }
-            if (geomType === "Polygon")
-              multiFeatureIndex++;
-            break;
-          case "MultiPolygon":
-            for (j2 = 0; j2 < coords.length; j2++) {
-              geometryIndex = 0;
-              for (k2 = 0; k2 < coords[j2].length; k2++) {
-                for (l2 = 0; l2 < coords[j2][k2].length - wrapShrink; l2++) {
-                  if (callback(
-                    coords[j2][k2][l2],
-                    coordIndex,
-                    featureIndex,
-                    multiFeatureIndex,
-                    geometryIndex
-                  ) === false)
-                    return false;
-                  coordIndex++;
-                }
-                geometryIndex++;
-              }
-              multiFeatureIndex++;
-            }
-            break;
-          case "GeometryCollection":
-            for (j2 = 0; j2 < geometry.geometries.length; j2++)
-              if (coordEach(geometry.geometries[j2], callback, excludeWrapCoord) === false)
-                return false;
-            break;
-          default:
-            throw new Error("Unknown Geometry Type");
-        }
+    function noteSaveButtons(selection2) {
+      var osm = services.osm;
+      var hasAuth = osm && osm.authenticated();
+      var isSelected = _note && _note.id === context.selectedNoteID();
+      var buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_note] : [], function(d2) {
+        return d2.status + d2.id;
+      });
+      buttonSection.exit().remove();
+      var buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
+      if (_note.isNew()) {
+        buttonEnter.append("button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
+        buttonEnter.append("button").attr("class", "button save-button action").call(_t.append("note.save"));
+      } else {
+        buttonEnter.append("button").attr("class", "button status-button action");
+        buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("note.comment"));
+      }
+      buttonSection = buttonSection.merge(buttonEnter);
+      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
+      buttonSection.select(".save-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
+      buttonSection.select(".status-button").attr("disabled", hasAuth ? null : true).each(function(d2) {
+        var action = d2.status === "open" ? "close" : "open";
+        var andComment = d2.newComment ? "_comment" : "";
+        _t.addOrUpdate("note." + action + andComment)(select_default2(this));
+      }).on("click.status", clickStatus);
+      buttonSection.select(".comment-button").attr("disabled", isSaveDisabled).on("click.comment", clickComment);
+      function isSaveDisabled(d2) {
+        return hasAuth && d2.status === "open" && d2.newComment ? null : true;
       }
     }
-  }
-
-  // node_modules/@turf/bbox/dist/es/index.js
-  function bbox(geojson) {
-    var result = [Infinity, Infinity, -Infinity, -Infinity];
-    coordEach(geojson, function(coord2) {
-      if (result[0] > coord2[0]) {
-        result[0] = coord2[0];
+    function clickCancel(d3_event, d2) {
+      this.blur();
+      var osm = services.osm;
+      if (osm) {
+        osm.removeNote(d2);
       }
-      if (result[1] > coord2[1]) {
-        result[1] = coord2[1];
+      context.enter(modeBrowse(context));
+      dispatch14.call("change");
+    }
+    function clickSave(d3_event, d2) {
+      this.blur();
+      var osm = services.osm;
+      if (osm) {
+        osm.postNoteCreate(d2, function(err, note) {
+          dispatch14.call("change", note);
+        });
       }
-      if (result[2] < coord2[0]) {
-        result[2] = coord2[0];
+    }
+    function clickStatus(d3_event, d2) {
+      this.blur();
+      var osm = services.osm;
+      if (osm) {
+        var setStatus = d2.status === "open" ? "closed" : "open";
+        osm.postNoteUpdate(d2, setStatus, function(err, note) {
+          dispatch14.call("change", note);
+        });
       }
-      if (result[3] < coord2[1]) {
-        result[3] = coord2[1];
+    }
+    function clickComment(d3_event, d2) {
+      this.blur();
+      var osm = services.osm;
+      if (osm) {
+        osm.postNoteUpdate(d2, d2.status, function(err, note) {
+          dispatch14.call("change", note);
+        });
       }
-    });
-    return result;
+    }
+    noteEditor.note = function(val) {
+      if (!arguments.length) return _note;
+      _note = val;
+      return noteEditor;
+    };
+    noteEditor.newNote = function(val) {
+      if (!arguments.length) return _newNote;
+      _newNote = val;
+      return noteEditor;
+    };
+    return utilRebind(noteEditor, dispatch14, "on");
   }
-  bbox["default"] = bbox;
-  var es_default = bbox;
 
-  // modules/renderer/background.js
-  var import_which_polygon3 = __toESM(require_which_polygon());
-
-  // modules/renderer/tile_layer.js
-  function rendererTileLayer(context) {
-    var transformProp = utilPrefixCSSProperty("Transform");
-    var tiler9 = utilTiler();
-    var _tileSize = 256;
-    var _projection;
-    var _cache5 = {};
-    var _tileOrigin;
-    var _zoom;
-    var _source;
-    function tileSizeAtZoom(d2, z2) {
-      var EPSILON = 2e-3;
-      return _tileSize * Math.pow(2, z2 - d2[2]) / _tileSize + EPSILON;
-    }
-    function atZoom(t2, distance) {
-      var power = Math.pow(2, distance);
-      return [
-        Math.floor(t2[0] * power),
-        Math.floor(t2[1] * power),
-        t2[2] + distance
-      ];
-    }
-    function lookUp(d2) {
-      for (var up = -1; up > -d2[2]; up--) {
-        var tile = atZoom(d2, up);
-        if (_cache5[_source.url(tile)] !== false) {
-          return tile;
-        }
+  // modules/modes/select_note.js
+  function modeSelectNote(context, selectedNoteID) {
+    var mode = {
+      id: "select-note",
+      button: "browse"
+    };
+    var _keybinding = utilKeybinding("select-note");
+    var _noteEditor = uiNoteEditor(context).on("change", function() {
+      context.map().pan([0, 0]);
+      var note = checkSelectedID();
+      if (!note) return;
+      context.ui().sidebar.show(_noteEditor.note(note));
+    });
+    var _behaviors = [
+      behaviorBreathe(context),
+      behaviorHover(context),
+      behaviorSelect(context),
+      behaviorLasso(context),
+      modeDragNode(context).behavior,
+      modeDragNote(context).behavior
+    ];
+    var _newFeature = false;
+    function checkSelectedID() {
+      if (!services.osm) return;
+      var note = services.osm.getNote(selectedNoteID);
+      if (!note) {
+        context.enter(modeBrowse(context));
       }
+      return note;
     }
-    function uniqueBy(a2, n3) {
-      var o2 = [];
-      var seen = {};
-      for (var i3 = 0; i3 < a2.length; i3++) {
-        if (seen[a2[i3][n3]] === void 0) {
-          o2.push(a2[i3]);
-          seen[a2[i3][n3]] = true;
+    function selectNote(d3_event, drawn) {
+      if (!checkSelectedID()) return;
+      var selection2 = context.surface().selectAll(".layer-notes .note-" + selectedNoteID);
+      if (selection2.empty()) {
+        var source = d3_event && d3_event.type === "zoom" && d3_event.sourceEvent;
+        if (drawn && source && (source.type === "pointermove" || source.type === "mousemove" || source.type === "touchmove")) {
+          context.enter(modeBrowse(context));
         }
+      } else {
+        selection2.classed("selected", true);
+        context.selectedNoteID(selectedNoteID);
       }
-      return o2;
     }
-    function addSource(d2) {
-      d2.push(_source.url(d2));
-      return d2;
+    function esc() {
+      if (context.container().select(".combobox").size()) return;
+      context.enter(modeBrowse(context));
     }
-    function background(selection2) {
-      _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
-      var pixelOffset;
-      if (_source) {
-        pixelOffset = [
-          _source.offset()[0] * Math.pow(2, _zoom),
-          _source.offset()[1] * Math.pow(2, _zoom)
-        ];
-      } else {
-        pixelOffset = [0, 0];
+    mode.zoomToSelected = function() {
+      if (!services.osm) return;
+      var note = services.osm.getNote(selectedNoteID);
+      if (note) {
+        context.map().centerZoomEase(note.loc, 20);
       }
-      var translate = [
-        _projection.translate()[0] + pixelOffset[0],
-        _projection.translate()[1] + pixelOffset[1]
-      ];
-      tiler9.scale(_projection.scale() * 2 * Math.PI).translate(translate);
-      _tileOrigin = [
-        _projection.scale() * Math.PI - translate[0],
-        _projection.scale() * Math.PI - translate[1]
-      ];
-      render(selection2);
+    };
+    mode.newFeature = function(val) {
+      if (!arguments.length) return _newFeature;
+      _newFeature = val;
+      return mode;
+    };
+    mode.enter = function() {
+      var note = checkSelectedID();
+      if (!note) return;
+      _behaviors.forEach(context.install);
+      _keybinding.on(_t("inspector.zoom_to.key"), mode.zoomToSelected).on("\u238B", esc, true);
+      select_default2(document).call(_keybinding);
+      selectNote();
+      var sidebar = context.ui().sidebar;
+      sidebar.show(_noteEditor.note(note).newNote(_newFeature));
+      sidebar.expand(sidebar.intersects(note.extent()));
+      context.map().on("drawn.select", selectNote);
+    };
+    mode.exit = function() {
+      _behaviors.forEach(context.uninstall);
+      select_default2(document).call(_keybinding.unbind);
+      context.surface().selectAll(".layer-notes .selected").classed("selected hover", false);
+      context.map().on("drawn.select", null);
+      context.ui().sidebar.hide();
+      context.selectedNoteID(null);
+    };
+    return mode;
+  }
+
+  // modules/modes/add_note.js
+  function modeAddNote(context) {
+    var mode = {
+      id: "add-note",
+      button: "note",
+      description: _t.append("modes.add_note.description"),
+      key: _t("modes.add_note.key")
+    };
+    var behavior = behaviorDraw(context).on("click", add).on("cancel", cancel).on("finish", cancel);
+    function add(loc) {
+      var osm = services.osm;
+      if (!osm) return;
+      var note = osmNote({ loc, status: "open", comments: [] });
+      osm.replaceNote(note);
+      context.map().pan([0, 0]);
+      context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
     }
-    function render(selection2) {
-      if (!_source)
-        return;
-      var requests = [];
-      var showDebug = context.getDebug("tile") && !_source.overlay;
-      if (_source.validZoom(_zoom)) {
-        tiler9.skipNullIsland(!!_source.overlay);
-        tiler9().forEach(function(d2) {
-          addSource(d2);
-          if (d2[3] === "")
-            return;
-          if (typeof d2[3] !== "string")
-            return;
-          requests.push(d2);
-          if (_cache5[d2[3]] === false && lookUp(d2)) {
-            requests.push(addSource(lookUp(d2)));
-          }
-        });
-        requests = uniqueBy(requests, 3).filter(function(r2) {
-          return _cache5[r2[3]] !== false;
-        });
+    function cancel() {
+      context.enter(modeBrowse(context));
+    }
+    mode.enter = function() {
+      context.install(behavior);
+    };
+    mode.exit = function() {
+      context.uninstall(behavior);
+    };
+    return mode;
+  }
+
+  // modules/util/jxon.js
+  var JXON = new function() {
+    var sValueProp = "keyValue", sAttributesProp = "keyAttributes", sAttrPref = "@", aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
+    function parseText(sValue) {
+      if (rIsNull.test(sValue)) {
+        return null;
       }
-      function load(d3_event, d2) {
-        _cache5[d2[3]] = true;
-        select_default2(this).on("error", null).on("load", null).classed("tile-loaded", true);
-        render(selection2);
+      if (rIsBool.test(sValue)) {
+        return sValue.toLowerCase() === "true";
       }
-      function error(d3_event, d2) {
-        _cache5[d2[3]] = false;
-        select_default2(this).on("error", null).on("load", null).remove();
-        render(selection2);
+      if (isFinite(sValue)) {
+        return parseFloat(sValue);
       }
-      function imageTransform(d2) {
-        var ts = _tileSize * Math.pow(2, _zoom - d2[2]);
-        var scale = tileSizeAtZoom(d2, _zoom);
-        return "translate(" + (d2[0] * ts - _tileOrigin[0]) + "px," + (d2[1] * ts - _tileOrigin[1]) + "px) scale(" + scale + "," + scale + ")";
+      if (isFinite(Date.parse(sValue))) {
+        return new Date(sValue);
       }
-      function tileCenter(d2) {
-        var ts = _tileSize * Math.pow(2, _zoom - d2[2]);
-        return [
-          d2[0] * ts - _tileOrigin[0] + ts / 2,
-          d2[1] * ts - _tileOrigin[1] + ts / 2
-        ];
+      return sValue;
+    }
+    function EmptyTree() {
+    }
+    EmptyTree.prototype.toString = function() {
+      return "null";
+    };
+    EmptyTree.prototype.valueOf = function() {
+      return null;
+    };
+    function objectify(vValue) {
+      return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
+    }
+    function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
+      var nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(), bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
+      var sProp, vContent, nLength = 0, sCollectedTxt = "", vResult = bHighVerb ? {} : (
+        /* put here the default value for empty nodes: */
+        true
+      );
+      if (bChildren) {
+        for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
+          oNode = oParentNode.childNodes.item(nItem);
+          if (oNode.nodeType === 4) {
+            sCollectedTxt += oNode.nodeValue;
+          } else if (oNode.nodeType === 3) {
+            sCollectedTxt += oNode.nodeValue.trim();
+          } else if (oNode.nodeType === 1 && !oNode.prefix) {
+            aCache.push(oNode);
+          }
+        }
       }
-      function debugTransform(d2) {
-        var coord2 = tileCenter(d2);
-        return "translate(" + coord2[0] + "px," + coord2[1] + "px)";
+      var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
+      if (!bHighVerb && (bChildren || bAttributes)) {
+        vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
       }
-      var dims = tiler9.size();
-      var mapCenter = [dims[0] / 2, dims[1] / 2];
-      var minDist = Math.max(dims[0], dims[1]);
-      var nearCenter;
-      requests.forEach(function(d2) {
-        var c2 = tileCenter(d2);
-        var dist = geoVecLength(c2, mapCenter);
-        if (dist < minDist) {
-          minDist = dist;
-          nearCenter = d2;
+      for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
+        sProp = aCache[nElId].nodeName.toLowerCase();
+        vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
+        if (vResult.hasOwnProperty(sProp)) {
+          if (vResult[sProp].constructor !== Array) {
+            vResult[sProp] = [vResult[sProp]];
+          }
+          vResult[sProp].push(vContent);
+        } else {
+          vResult[sProp] = vContent;
+          nLength++;
         }
-      });
-      var image = selection2.selectAll("img").data(requests, function(d2) {
-        return d2[3];
-      });
-      image.exit().style(transformProp, imageTransform).classed("tile-removing", true).classed("tile-center", false).each(function() {
-        var tile = select_default2(this);
-        window.setTimeout(function() {
-          if (tile.classed("tile-removing")) {
-            tile.remove();
+      }
+      if (bAttributes) {
+        var nAttrLen = oParentNode.attributes.length, sAPrefix = bNesteAttr ? "" : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
+        for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
+          oAttrib = oParentNode.attributes.item(nAttrib);
+          oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
+        }
+        if (bNesteAttr) {
+          if (bFreeze) {
+            Object.freeze(oAttrParent);
           }
-        }, 300);
-      });
-      image.enter().append("img").attr("class", "tile").attr("alt", "").attr("draggable", "false").style("width", _tileSize + "px").style("height", _tileSize + "px").attr("src", function(d2) {
-        return d2[3];
-      }).on("error", error).on("load", load).merge(image).style(transformProp, imageTransform).classed("tile-debug", showDebug).classed("tile-removing", false).classed("tile-center", function(d2) {
-        return d2 === nearCenter;
-      });
-      var debug2 = selection2.selectAll(".tile-label-debug").data(showDebug ? requests : [], function(d2) {
-        return d2[3];
-      });
-      debug2.exit().remove();
-      if (showDebug) {
-        var debugEnter = debug2.enter().append("div").attr("class", "tile-label-debug");
-        debugEnter.append("div").attr("class", "tile-label-debug-coord");
-        debugEnter.append("div").attr("class", "tile-label-debug-vintage");
-        debug2 = debug2.merge(debugEnter);
-        debug2.style(transformProp, debugTransform);
-        debug2.selectAll(".tile-label-debug-coord").text(function(d2) {
-          return d2[2] + " / " + d2[0] + " / " + d2[1];
-        });
-        debug2.selectAll(".tile-label-debug-vintage").each(function(d2) {
-          var span = select_default2(this);
-          var center = context.projection.invert(tileCenter(d2));
-          _source.getMetadata(center, d2, function(err, result) {
-            if (result && result.vintage && result.vintage.range) {
-              span.text(result.vintage.range);
-            } else {
-              span.text("");
-              span.call(_t.append("info_panels.background.vintage"));
-              span.append("span").text(": ");
-              span.call(_t.append("info_panels.background.unknown"));
-            }
-          });
-        });
+          vResult[sAttributesProp] = oAttrParent;
+          nLength -= nAttrLen - 1;
+        }
+      }
+      if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
+        vResult[sValueProp] = vBuiltVal;
+      } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
+        vResult = vBuiltVal;
+      }
+      if (bFreeze && (bHighVerb || nLength > 0)) {
+        Object.freeze(vResult);
       }
+      aCache.length = nLevelStart;
+      return vResult;
     }
-    background.projection = function(val) {
-      if (!arguments.length)
-        return _projection;
-      _projection = val;
-      return background;
+    function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
+      var vValue, oChild;
+      if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
+        oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
+      } else if (oParentObj.constructor === Date) {
+        oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
+      }
+      for (var sName in oParentObj) {
+        vValue = oParentObj[sName];
+        if (isFinite(sName) || vValue instanceof Function) {
+          continue;
+        }
+        if (sName === sValueProp) {
+          if (vValue !== null && vValue !== true) {
+            oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
+          }
+        } else if (sName === sAttributesProp) {
+          for (var sAttrib in vValue) {
+            oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
+          }
+        } else if (sName.charAt(0) === sAttrPref) {
+          oParentEl.setAttribute(sName.slice(1), vValue);
+        } else if (vValue.constructor === Array) {
+          for (var nItem = 0; nItem < vValue.length; nItem++) {
+            oChild = oXMLDoc.createElement(sName);
+            loadObjTree(oXMLDoc, oChild, vValue[nItem]);
+            oParentEl.appendChild(oChild);
+          }
+        } else {
+          oChild = oXMLDoc.createElement(sName);
+          if (vValue instanceof Object) {
+            loadObjTree(oXMLDoc, oChild, vValue);
+          } else if (vValue !== null && vValue !== true) {
+            oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
+          }
+          oParentEl.appendChild(oChild);
+        }
+      }
+    }
+    this.build = function(oXMLParent, nVerbosity, bFreeze, bNesteAttributes) {
+      var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : (
+        /* put here the default verbosity level: */
+        1
+      );
+      return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
     };
-    background.dimensions = function(val) {
-      if (!arguments.length)
-        return tiler9.size();
-      tiler9.size(val);
-      return background;
+    this.unbuild = function(oObjTree) {
+      var oNewDoc = document.implementation.createDocument("", "", null);
+      loadObjTree(oNewDoc, oNewDoc, oObjTree);
+      return oNewDoc;
     };
-    background.source = function(val) {
-      if (!arguments.length)
-        return _source;
-      _source = val;
-      _tileSize = _source.tileSize;
-      _cache5 = {};
-      tiler9.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
-      return background;
+    this.stringify = function(oObjTree) {
+      return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
     };
-    return background;
-  }
+  }();
 
-  // modules/renderer/background.js
-  var _imageryIndex = null;
-  function rendererBackground(context) {
-    const dispatch14 = dispatch_default("change");
-    const baseLayer = rendererTileLayer(context).projection(context.projection);
-    let _checkedBlocklists = [];
-    let _isValid = true;
-    let _overlayLayers = [];
-    let _brightness = 1;
-    let _contrast = 1;
-    let _saturation = 1;
-    let _sharpness = 1;
-    function ensureImageryIndex() {
-      return _mainFileFetcher.get("imagery").then((sources) => {
-        if (_imageryIndex)
-          return _imageryIndex;
-        _imageryIndex = {
-          imagery: sources,
-          features: {}
-        };
-        const features = sources.map((source) => {
-          if (!source.polygon)
-            return null;
-          const rings = source.polygon.map((ring) => [ring]);
-          const feature3 = {
-            type: "Feature",
-            properties: { id: source.id },
-            geometry: { type: "MultiPolygon", coordinates: rings }
-          };
-          _imageryIndex.features[source.id] = feature3;
-          return feature3;
-        }).filter(Boolean);
-        _imageryIndex.query = (0, import_which_polygon3.default)({ type: "FeatureCollection", features });
-        _imageryIndex.backgrounds = sources.map((source) => {
-          if (source.type === "bing") {
-            return rendererBackgroundSource.Bing(source, dispatch14);
-          } else if (/^EsriWorldImagery/.test(source.id)) {
-            return rendererBackgroundSource.Esri(source);
-          } else {
-            return rendererBackgroundSource(source);
-          }
-        });
-        _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None());
-        let template = corePreferences("background-custom-template") || "";
-        const custom = rendererBackgroundSource.Custom(template);
-        _imageryIndex.backgrounds.unshift(custom);
-        return _imageryIndex;
+  // modules/ui/conflicts.js
+  function uiConflicts(context) {
+    var dispatch14 = dispatch_default("cancel", "save");
+    var keybinding = utilKeybinding("conflicts");
+    var _origChanges;
+    var _conflictList;
+    var _shownConflictIndex;
+    function keybindingOn() {
+      select_default2(document).call(keybinding.on("\u238B", cancel, true));
+    }
+    function keybindingOff() {
+      select_default2(document).call(keybinding.unbind);
+    }
+    function tryAgain() {
+      keybindingOff();
+      dispatch14.call("save");
+    }
+    function cancel() {
+      keybindingOff();
+      dispatch14.call("cancel");
+    }
+    function conflicts(selection2) {
+      keybindingOn();
+      var headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "fr").attr("title", _t("icons.close")).on("click", cancel).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("save.conflict.header"));
+      var bodyEnter = selection2.selectAll(".body").data([0]).enter().append("div").attr("class", "body fillL");
+      var conflictsHelpEnter = bodyEnter.append("div").attr("class", "conflicts-help").call(_t.append("save.conflict.help"));
+      var changeset = new osmChangeset();
+      delete changeset.id;
+      var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
+      var blob = new Blob([data], { type: "text/xml;charset=utf-8;" });
+      var fileName = "changes.osc";
+      var linkEnter = conflictsHelpEnter.selectAll(".download-changes").append("a").attr("class", "download-changes");
+      linkEnter.attr("href", window.URL.createObjectURL(blob)).attr("download", fileName);
+      linkEnter.call(svgIcon("#iD-icon-load", "inline")).append("span").call(_t.append("save.conflict.download_changes"));
+      bodyEnter.append("div").attr("class", "conflict-container fillL3").call(showConflict, 0);
+      bodyEnter.append("div").attr("class", "conflicts-done").attr("opacity", 0).style("display", "none").call(_t.append("save.conflict.done"));
+      var buttonsEnter = bodyEnter.append("div").attr("class", "buttons col12 joined conflicts-buttons");
+      buttonsEnter.append("button").attr("disabled", _conflictList.length > 1).attr("class", "action conflicts-button col6").call(_t.append("save.title")).on("click.try_again", tryAgain);
+      buttonsEnter.append("button").attr("class", "secondary-action conflicts-button col6").call(_t.append("confirm.cancel")).on("click.cancel", cancel);
+    }
+    function showConflict(selection2, index) {
+      index = utilWrap(index, _conflictList.length);
+      _shownConflictIndex = index;
+      var parent = select_default2(selection2.node().parentNode);
+      if (index === _conflictList.length - 1) {
+        window.setTimeout(function() {
+          parent.select(".conflicts-button").attr("disabled", null);
+          parent.select(".conflicts-done").transition().attr("opacity", 1).style("display", "block");
+        }, 250);
+      }
+      var conflict = selection2.selectAll(".conflict").data([_conflictList[index]]);
+      conflict.exit().remove();
+      var conflictEnter = conflict.enter().append("div").attr("class", "conflict");
+      conflictEnter.append("h4").attr("class", "conflict-count").call(_t.append("save.conflict.count", { num: index + 1, total: _conflictList.length }));
+      conflictEnter.append("a").attr("class", "conflict-description").attr("href", "#").text(function(d2) {
+        return d2.name;
+      }).on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        zoomToEntity(d2.id);
+      });
+      var details = conflictEnter.append("div").attr("class", "conflict-detail-container");
+      details.append("ul").attr("class", "conflict-detail-list").selectAll("li").data(function(d2) {
+        return d2.details || [];
+      }).enter().append("li").attr("class", "conflict-detail-item").html(function(d2) {
+        return d2;
+      });
+      details.append("div").attr("class", "conflict-choices").call(addChoices);
+      details.append("div").attr("class", "conflict-nav-buttons joined cf").selectAll("button").data(["previous", "next"]).enter().append("button").attr("class", "conflict-nav-button action col6").attr("disabled", function(d2, i3) {
+        return i3 === 0 && index === 0 || i3 === 1 && index === _conflictList.length - 1 || null;
+      }).on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        var container = parent.selectAll(".conflict-container");
+        var sign2 = d2 === "previous" ? -1 : 1;
+        container.selectAll(".conflict").remove();
+        container.call(showConflict, index + sign2);
+      }).each(function(d2) {
+        _t.append("save.conflict." + d2)(select_default2(this));
       });
     }
-    function background(selection2) {
-      const currSource = baseLayer.source();
-      if (context.map().zoom() > 18) {
-        if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
-          const center = context.map().center();
-          currSource.fetchTilemap(center);
+    function addChoices(selection2) {
+      var choices = selection2.append("ul").attr("class", "layer-list").selectAll("li").data(function(d2) {
+        return d2.choices || [];
+      });
+      var choicesEnter = choices.enter().append("li").attr("class", "layer");
+      var labelEnter = choicesEnter.append("label");
+      labelEnter.append("input").attr("type", "radio").attr("name", function(d2) {
+        return d2.id;
+      }).on("change", function(d3_event, d2) {
+        var ul = this.parentNode.parentNode.parentNode;
+        ul.__data__.chosen = d2.id;
+        choose(d3_event, ul, d2);
+      });
+      labelEnter.append("span").text(function(d2) {
+        return d2.text;
+      });
+      choicesEnter.merge(choices).each(function(d2) {
+        var ul = this.parentNode;
+        if (ul.__data__.chosen === d2.id) {
+          choose(null, ul, d2);
         }
+      });
+    }
+    function choose(d3_event, ul, datum2) {
+      if (d3_event) d3_event.preventDefault();
+      select_default2(ul).selectAll("li").classed("active", function(d2) {
+        return d2 === datum2;
+      }).selectAll("input").property("checked", function(d2) {
+        return d2 === datum2;
+      });
+      var extent = geoExtent();
+      var entity;
+      entity = context.graph().hasEntity(datum2.id);
+      if (entity) extent._extend(entity.extent(context.graph()));
+      datum2.action();
+      entity = context.graph().hasEntity(datum2.id);
+      if (entity) extent._extend(entity.extent(context.graph()));
+      zoomToEntity(datum2.id, extent);
+    }
+    function zoomToEntity(id2, extent) {
+      context.surface().selectAll(".hover").classed("hover", false);
+      var entity = context.graph().hasEntity(id2);
+      if (entity) {
+        if (extent) {
+          context.map().trimmedExtent(extent);
+        } else {
+          context.map().zoomToEase(entity);
+        }
+        context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed("hover", true);
       }
-      const sources = background.sources(context.map().extent());
-      const wasValid = _isValid;
-      _isValid = !!sources.filter((d2) => d2 === currSource).length;
-      if (wasValid !== _isValid) {
-        background.updateImagery();
-      }
-      let baseFilter = "";
-      if (_brightness !== 1) {
-        baseFilter += " brightness(".concat(_brightness, ")");
-      }
-      if (_contrast !== 1) {
-        baseFilter += " contrast(".concat(_contrast, ")");
-      }
-      if (_saturation !== 1) {
-        baseFilter += " saturate(".concat(_saturation, ")");
-      }
-      if (_sharpness < 1) {
-        const blur = number_default(0.5, 5)(1 - _sharpness);
-        baseFilter += " blur(".concat(blur, "px)");
-      }
-      let base = selection2.selectAll(".layer-background").data([0]);
-      base = base.enter().insert("div", ".layer-data").attr("class", "layer layer-background").merge(base);
-      base.style("filter", baseFilter || null);
-      let imagery = base.selectAll(".layer-imagery").data([0]);
-      imagery.enter().append("div").attr("class", "layer layer-imagery").merge(imagery).call(baseLayer);
-      let maskFilter = "";
-      let mixBlendMode = "";
-      if (_sharpness > 1) {
-        mixBlendMode = "overlay";
-        maskFilter = "saturate(0) blur(3px) invert(1)";
-        let contrast = _sharpness - 1;
-        maskFilter += " contrast(".concat(contrast, ")");
-        let brightness = number_default(1, 0.85)(_sharpness - 1);
-        maskFilter += " brightness(".concat(brightness, ")");
-      }
-      let mask = base.selectAll(".layer-unsharp-mask").data(_sharpness > 1 ? [0] : []);
-      mask.exit().remove();
-      mask.enter().append("div").attr("class", "layer layer-mask layer-unsharp-mask").merge(mask).call(baseLayer).style("filter", maskFilter || null).style("mix-blend-mode", mixBlendMode || null);
-      let overlays = selection2.selectAll(".layer-overlay").data(_overlayLayers, (d2) => d2.source().name());
-      overlays.exit().remove();
-      overlays.enter().insert("div", ".layer-data").attr("class", "layer layer-overlay").merge(overlays).each((layer, i3, nodes) => select_default2(nodes[i3]).call(layer));
     }
-    background.updateImagery = function() {
-      let currSource = baseLayer.source();
-      if (context.inIntro() || !currSource)
-        return;
-      let o2 = _overlayLayers.filter((d2) => !d2.source().isLocatorOverlay() && !d2.source().isHidden()).map((d2) => d2.source().id).join(",");
-      const meters = geoOffsetToMeters(currSource.offset());
-      const EPSILON = 0.01;
-      const x2 = +meters[0].toFixed(2);
-      const y2 = +meters[1].toFixed(2);
-      let hash = utilStringQs(window.location.hash);
-      let id2 = currSource.id;
-      if (id2 === "custom") {
-        id2 = "custom:".concat(currSource.template());
+    conflicts.conflictList = function(_2) {
+      if (!arguments.length) return _conflictList;
+      _conflictList = _2;
+      return conflicts;
+    };
+    conflicts.origChanges = function(_2) {
+      if (!arguments.length) return _origChanges;
+      _origChanges = _2;
+      return conflicts;
+    };
+    conflicts.shownEntityIds = function() {
+      if (_conflictList && typeof _shownConflictIndex === "number") {
+        return [_conflictList[_shownConflictIndex].id];
       }
-      if (id2) {
-        hash.background = id2;
+      return [];
+    };
+    return utilRebind(conflicts, dispatch14, "on");
+  }
+
+  // modules/ui/confirm.js
+  function uiConfirm(selection2) {
+    var modalSelection = uiModal(selection2);
+    modalSelection.select(".modal").classed("modal-alert", true);
+    var section = modalSelection.select(".content");
+    section.append("div").attr("class", "modal-section header");
+    section.append("div").attr("class", "modal-section message-text");
+    var buttons = section.append("div").attr("class", "modal-section buttons cf");
+    modalSelection.okButton = function() {
+      buttons.append("button").attr("class", "button ok-button action").on("click.confirm", function() {
+        modalSelection.remove();
+      }).call(_t.append("confirm.okay")).node().focus();
+      return modalSelection;
+    };
+    return modalSelection;
+  }
+
+  // modules/ui/commit.js
+  var import_fast_deep_equal10 = __toESM(require_fast_deep_equal());
+
+  // modules/ui/popover.js
+  var _popoverID = 0;
+  function uiPopover(klass) {
+    var _id = _popoverID++;
+    var _anchorSelection = select_default2(null);
+    var popover = function(selection2) {
+      _anchorSelection = selection2;
+      selection2.each(setup);
+    };
+    var _animation = utilFunctor(false);
+    var _placement = utilFunctor("top");
+    var _alignment = utilFunctor("center");
+    var _scrollContainer = utilFunctor(select_default2(null));
+    var _content;
+    var _displayType = utilFunctor("");
+    var _hasArrow = utilFunctor(true);
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    popover.displayType = function(val) {
+      if (arguments.length) {
+        _displayType = utilFunctor(val);
+        return popover;
       } else {
-        delete hash.background;
+        return _displayType;
       }
-      if (o2) {
-        hash.overlays = o2;
+    };
+    popover.hasArrow = function(val) {
+      if (arguments.length) {
+        _hasArrow = utilFunctor(val);
+        return popover;
       } else {
-        delete hash.overlays;
+        return _hasArrow;
       }
-      if (Math.abs(x2) > EPSILON || Math.abs(y2) > EPSILON) {
-        hash.offset = "".concat(x2, ",").concat(y2);
+    };
+    popover.placement = function(val) {
+      if (arguments.length) {
+        _placement = utilFunctor(val);
+        return popover;
       } else {
-        delete hash.offset;
-      }
-      if (!window.mocha) {
-        window.location.replace("#" + utilQsString(hash, true));
+        return _placement;
       }
-      let imageryUsed = [];
-      let photoOverlaysUsed = [];
-      const currUsed = currSource.imageryUsed();
-      if (currUsed && _isValid) {
-        imageryUsed.push(currUsed);
-      }
-      _overlayLayers.filter((d2) => !d2.source().isLocatorOverlay() && !d2.source().isHidden()).forEach((d2) => imageryUsed.push(d2.source().imageryUsed()));
-      const dataLayer = context.layers().layer("data");
-      if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
-        imageryUsed.push(dataLayer.getSrc());
-      }
-      const photoOverlayLayers = {
-        streetside: "Bing Streetside",
-        mapillary: "Mapillary Images",
-        "mapillary-map-features": "Mapillary Map Features",
-        "mapillary-signs": "Mapillary Signs",
-        kartaview: "KartaView Images",
-        vegbilder: "Norwegian Road Administration Images",
-        mapilio: "Mapilio Images"
-      };
-      for (let layerID in photoOverlayLayers) {
-        const layer = context.layers().layer(layerID);
-        if (layer && layer.enabled()) {
-          photoOverlaysUsed.push(layerID);
-          imageryUsed.push(photoOverlayLayers[layerID]);
-        }
-      }
-      context.history().imageryUsed(imageryUsed);
-      context.history().photoOverlaysUsed(photoOverlaysUsed);
     };
-    background.sources = (extent, zoom, includeCurrent) => {
-      if (!_imageryIndex)
-        return [];
-      let visible = {};
-      (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach((d2) => visible[d2.id] = true);
-      const currSource = baseLayer.source();
-      const osm = context.connection();
-      const blocklists = osm && osm.imageryBlocklists() || [];
-      const blocklistChanged = blocklists.length !== _checkedBlocklists.length || blocklists.some((regex, index) => String(regex) !== _checkedBlocklists[index]);
-      if (blocklistChanged) {
-        _imageryIndex.backgrounds.forEach((source) => {
-          source.isBlocked = blocklists.some((regex) => regex.test(source.template()));
-        });
-        _checkedBlocklists = blocklists.map((regex) => String(regex));
+    popover.alignment = function(val) {
+      if (arguments.length) {
+        _alignment = utilFunctor(val);
+        return popover;
+      } else {
+        return _alignment;
       }
-      return _imageryIndex.backgrounds.filter((source) => {
-        if (includeCurrent && currSource === source)
-          return true;
-        if (source.isBlocked)
-          return false;
-        if (!source.polygon)
-          return true;
-        if (zoom && zoom < 6)
-          return false;
-        return visible[source.id];
-      });
-    };
-    background.dimensions = (val) => {
-      if (!val)
-        return;
-      baseLayer.dimensions(val);
-      _overlayLayers.forEach((layer) => layer.dimensions(val));
     };
-    background.baseLayerSource = function(d2) {
-      if (!arguments.length)
-        return baseLayer.source();
-      const osm = context.connection();
-      if (!osm)
-        return background;
-      const blocklists = osm.imageryBlocklists();
-      const template = d2.template();
-      let fail = false;
-      let tested = 0;
-      let regex;
-      for (let i3 = 0; i3 < blocklists.length; i3++) {
-        regex = blocklists[i3];
-        fail = regex.test(template);
-        tested++;
-        if (fail)
-          break;
-      }
-      if (!tested) {
-        regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
-        fail = regex.test(template);
+    popover.scrollContainer = function(val) {
+      if (arguments.length) {
+        _scrollContainer = utilFunctor(val);
+        return popover;
+      } else {
+        return _scrollContainer;
       }
-      baseLayer.source(!fail ? d2 : background.findSource("none"));
-      dispatch14.call("change");
-      background.updateImagery();
-      return background;
-    };
-    background.findSource = (id2) => {
-      if (!id2 || !_imageryIndex)
-        return null;
-      return _imageryIndex.backgrounds.find((d2) => d2.id && d2.id === id2);
-    };
-    background.bing = () => {
-      background.baseLayerSource(background.findSource("Bing"));
-    };
-    background.showsLayer = (d2) => {
-      const currSource = baseLayer.source();
-      if (!d2 || !currSource)
-        return false;
-      return d2.id === currSource.id || _overlayLayers.some((layer) => d2.id === layer.source().id);
-    };
-    background.overlayLayerSources = () => {
-      return _overlayLayers.map((layer) => layer.source());
     };
-    background.toggleOverlayLayer = (d2) => {
-      let layer;
-      for (let i3 = 0; i3 < _overlayLayers.length; i3++) {
-        layer = _overlayLayers[i3];
-        if (layer.source() === d2) {
-          _overlayLayers.splice(i3, 1);
-          dispatch14.call("change");
-          background.updateImagery();
-          return;
-        }
+    popover.content = function(val) {
+      if (arguments.length) {
+        _content = val;
+        return popover;
+      } else {
+        return _content;
       }
-      layer = rendererTileLayer(context).source(d2).projection(context.projection).dimensions(
-        baseLayer.dimensions()
-      );
-      _overlayLayers.push(layer);
-      dispatch14.call("change");
-      background.updateImagery();
     };
-    background.nudge = (d2, zoom) => {
-      const currSource = baseLayer.source();
-      if (currSource) {
-        currSource.nudge(d2, zoom);
-        dispatch14.call("change");
-        background.updateImagery();
-      }
-      return background;
+    popover.isShown = function() {
+      var popoverSelection = _anchorSelection.select(".popover-" + _id);
+      return !popoverSelection.empty() && popoverSelection.classed("in");
     };
-    background.offset = function(d2) {
-      const currSource = baseLayer.source();
-      if (!arguments.length) {
-        return currSource && currSource.offset() || [0, 0];
-      }
-      if (currSource) {
-        currSource.offset(d2);
-        dispatch14.call("change");
-        background.updateImagery();
-      }
-      return background;
+    popover.show = function() {
+      _anchorSelection.each(show);
     };
-    background.brightness = function(d2) {
-      if (!arguments.length)
-        return _brightness;
-      _brightness = d2;
-      if (context.mode())
-        dispatch14.call("change");
-      return background;
+    popover.updateContent = function() {
+      _anchorSelection.each(updateContent);
     };
-    background.contrast = function(d2) {
-      if (!arguments.length)
-        return _contrast;
-      _contrast = d2;
-      if (context.mode())
-        dispatch14.call("change");
-      return background;
+    popover.hide = function() {
+      _anchorSelection.each(hide);
     };
-    background.saturation = function(d2) {
-      if (!arguments.length)
-        return _saturation;
-      _saturation = d2;
-      if (context.mode())
-        dispatch14.call("change");
-      return background;
+    popover.toggle = function() {
+      _anchorSelection.each(toggle);
     };
-    background.sharpness = function(d2) {
-      if (!arguments.length)
-        return _sharpness;
-      _sharpness = d2;
-      if (context.mode())
-        dispatch14.call("change");
-      return background;
+    popover.destroy = function(selection2, selector) {
+      selector = selector || ".popover-" + _id;
+      selection2.on(_pointerPrefix + "enter.popover", null).on(_pointerPrefix + "leave.popover", null).on(_pointerPrefix + "up.popover", null).on(_pointerPrefix + "down.popover", null).on("click.popover", null).attr("title", function() {
+        return this.getAttribute("data-original-title") || this.getAttribute("title");
+      }).attr("data-original-title", null).selectAll(selector).remove();
     };
-    let _loadPromise;
-    background.ensureLoaded = () => {
-      if (_loadPromise)
-        return _loadPromise;
-      return _loadPromise = ensureImageryIndex();
+    popover.destroyAny = function(selection2) {
+      selection2.call(popover.destroy, ".popover");
     };
-    background.init = () => {
-      const loadPromise = background.ensureLoaded();
-      const hash = utilStringQs(window.location.hash);
-      const requestedBackground = hash.background || hash.layer;
-      const lastUsedBackground = corePreferences("background-last-used");
-      return loadPromise.then((imageryIndex) => {
-        const extent = context.map().extent();
-        const validBackgrounds = background.sources(extent).filter((d2) => d2.id !== "none" && d2.id !== "custom");
-        const first = validBackgrounds.length && validBackgrounds[0];
-        const isLastUsedValid = !!validBackgrounds.find((d2) => d2.id && d2.id === lastUsedBackground);
-        let best;
-        if (!requestedBackground && extent) {
-          const viewArea = extent.area();
-          best = validBackgrounds.find((s2) => {
-            if (!s2.best() || s2.overlay)
-              return false;
-            let bbox2 = es_default(bboxClip(
-              { type: "MultiPolygon", coordinates: [s2.polygon || [extent.polygon()]] },
-              extent.rectangle()
-            ));
-            let area = geoExtent(bbox2.slice(0, 2), bbox2.slice(2, 4)).area();
-            return area / viewArea > 0.5;
-          });
-        }
-        if (requestedBackground && requestedBackground.indexOf("custom:") === 0) {
-          const template = requestedBackground.replace(/^custom:/, "");
-          const custom = background.findSource("custom");
-          background.baseLayerSource(custom.template(template));
-          corePreferences("background-custom-template", template);
-        } else {
-          background.baseLayerSource(
-            background.findSource(requestedBackground) || best || isLastUsedValid && background.findSource(lastUsedBackground) || background.findSource("Bing") || first || background.findSource("none")
-          );
-        }
-        const locator = imageryIndex.backgrounds.find((d2) => d2.overlay && d2.default);
-        if (locator) {
-          background.toggleOverlayLayer(locator);
-        }
-        const overlays = (hash.overlays || "").split(",");
-        overlays.forEach((overlay) => {
-          overlay = background.findSource(overlay);
-          if (overlay) {
-            background.toggleOverlayLayer(overlay);
+    function setup() {
+      var anchor = select_default2(this);
+      var animate = _animation.apply(this, arguments);
+      var popoverSelection = anchor.selectAll(".popover-" + _id).data([0]);
+      var enter = popoverSelection.enter().append("div").attr("class", "popover popover-" + _id + " " + (klass ? klass : "")).classed("arrowed", _hasArrow.apply(this, arguments));
+      enter.append("div").attr("class", "popover-arrow");
+      enter.append("div").attr("class", "popover-inner");
+      popoverSelection = enter.merge(popoverSelection);
+      if (animate) {
+        popoverSelection.classed("fade", true);
+      }
+      var display = _displayType.apply(this, arguments);
+      if (display === "hover") {
+        var _lastNonMouseEnterTime;
+        anchor.on(_pointerPrefix + "enter.popover", function(d3_event) {
+          if (d3_event.pointerType) {
+            if (d3_event.pointerType !== "mouse") {
+              _lastNonMouseEnterTime = d3_event.timeStamp;
+              return;
+            } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
+              return;
+            }
           }
+          if (d3_event.buttons !== 0) return;
+          show.apply(this, arguments);
+        }).on(_pointerPrefix + "leave.popover", function() {
+          hide.apply(this, arguments);
+        }).on("focus.popover", function() {
+          show.apply(this, arguments);
+        }).on("blur.popover", function() {
+          hide.apply(this, arguments);
         });
-        if (hash.gpx) {
-          const gpx2 = context.layers().layer("data");
-          if (gpx2) {
-            gpx2.url(hash.gpx, ".gpx");
+      } else if (display === "clickFocus") {
+        anchor.on(_pointerPrefix + "down.popover", function(d3_event) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+        }).on(_pointerPrefix + "up.popover", function(d3_event) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+        }).on("click.popover", toggle);
+        popoverSelection.attr("tabindex", 0).on("blur.popover", function() {
+          anchor.each(function() {
+            hide.apply(this, arguments);
+          });
+        });
+      }
+    }
+    function show() {
+      var anchor = select_default2(this);
+      var popoverSelection = anchor.selectAll(".popover-" + _id);
+      if (popoverSelection.empty()) {
+        anchor.call(popover.destroy);
+        anchor.each(setup);
+        popoverSelection = anchor.selectAll(".popover-" + _id);
+      }
+      popoverSelection.classed("in", true);
+      var displayType = _displayType.apply(this, arguments);
+      if (displayType === "clickFocus") {
+        anchor.classed("active", true);
+        popoverSelection.node().focus();
+      }
+      anchor.each(updateContent);
+    }
+    function updateContent() {
+      var anchor = select_default2(this);
+      if (_content) {
+        anchor.selectAll(".popover-" + _id + " > .popover-inner").call(_content.apply(this, arguments));
+      }
+      updatePosition.apply(this, arguments);
+      updatePosition.apply(this, arguments);
+      updatePosition.apply(this, arguments);
+    }
+    function updatePosition() {
+      var anchor = select_default2(this);
+      var popoverSelection = anchor.selectAll(".popover-" + _id);
+      var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
+      var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
+      var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
+      var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
+      var placement = _placement.apply(this, arguments);
+      popoverSelection.classed("left", false).classed("right", false).classed("top", false).classed("bottom", false).classed(placement, true);
+      var alignment = _alignment.apply(this, arguments);
+      var alignFactor = 0.5;
+      if (alignment === "leading") {
+        alignFactor = 0;
+      } else if (alignment === "trailing") {
+        alignFactor = 1;
+      }
+      var anchorFrame = getFrame(anchor.node());
+      var popoverFrame = getFrame(popoverSelection.node());
+      var position;
+      switch (placement) {
+        case "top":
+          position = {
+            x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
+            y: anchorFrame.y - popoverFrame.h
+          };
+          break;
+        case "bottom":
+          position = {
+            x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
+            y: anchorFrame.y + anchorFrame.h
+          };
+          break;
+        case "left":
+          position = {
+            x: anchorFrame.x - popoverFrame.w,
+            y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
+          };
+          break;
+        case "right":
+          position = {
+            x: anchorFrame.x + anchorFrame.w,
+            y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
+          };
+          break;
+      }
+      if (position) {
+        if (scrollNode && (placement === "top" || placement === "bottom")) {
+          var initialPosX = position.x;
+          if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
+            position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
+          } else if (position.x < 10) {
+            position.x = 10;
           }
+          var arrow = anchor.selectAll(".popover-" + _id + " > .popover-arrow");
+          var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
+          arrow.style("left", ~~arrowPosX + "px");
         }
-        if (hash.offset) {
-          const offset = hash.offset.replace(/;/g, ",").split(",").map((n3) => !isNaN(n3) && n3);
-          if (offset.length === 2) {
-            background.offset(geoMetersToOffset(offset));
-          }
+        popoverSelection.style("left", ~~position.x + "px").style("top", ~~position.y + "px");
+      } else {
+        popoverSelection.style("left", null).style("top", null);
+      }
+      function getFrame(node) {
+        var positionStyle = select_default2(node).style("position");
+        if (positionStyle === "absolute" || positionStyle === "static") {
+          return {
+            x: node.offsetLeft - scrollLeft,
+            y: node.offsetTop - scrollTop,
+            w: node.offsetWidth,
+            h: node.offsetHeight
+          };
+        } else {
+          return {
+            x: 0,
+            y: 0,
+            w: node.offsetWidth,
+            h: node.offsetHeight
+          };
         }
-      }).catch((err) => {
-        console.error(err);
-      });
-    };
-    return utilRebind(background, dispatch14, "on");
+      }
+    }
+    function hide() {
+      var anchor = select_default2(this);
+      if (_displayType.apply(this, arguments) === "clickFocus") {
+        anchor.classed("active", false);
+      }
+      anchor.selectAll(".popover-" + _id).classed("in", false);
+    }
+    function toggle() {
+      if (select_default2(this).select(".popover-" + _id).classed("in")) {
+        hide.apply(this, arguments);
+      } else {
+        show.apply(this, arguments);
+      }
+    }
+    return popover;
   }
 
-  // modules/renderer/features.js
-  function rendererFeatures(context) {
-    var dispatch14 = dispatch_default("change", "redraw");
-    var features = utilRebind({}, dispatch14, "on");
-    var _deferred2 = /* @__PURE__ */ new Set();
-    var traffic_roads = {
-      "motorway": true,
-      "motorway_link": true,
-      "trunk": true,
-      "trunk_link": true,
-      "primary": true,
-      "primary_link": true,
-      "secondary": true,
-      "secondary_link": true,
-      "tertiary": true,
-      "tertiary_link": true,
-      "residential": true,
-      "unclassified": true,
-      "living_street": true,
-      "busway": true
+  // modules/ui/tooltip.js
+  function uiTooltip(klass) {
+    var tooltip = uiPopover((klass || "") + " tooltip").displayType("hover");
+    var _title = function() {
+      var title = this.getAttribute("data-original-title");
+      if (title) {
+        return title;
+      } else {
+        title = this.getAttribute("title");
+        this.removeAttribute("title");
+        this.setAttribute("data-original-title", title);
+      }
+      return title;
     };
-    var service_roads = {
-      "service": true,
-      "road": true,
-      "track": true
+    var _heading = utilFunctor(null);
+    var _keys = utilFunctor(null);
+    tooltip.title = function(val) {
+      if (!arguments.length) return _title;
+      _title = utilFunctor(val);
+      return tooltip;
     };
-    var paths = {
-      "path": true,
-      "footway": true,
-      "cycleway": true,
-      "bridleway": true,
-      "steps": true,
-      "pedestrian": true
+    tooltip.heading = function(val) {
+      if (!arguments.length) return _heading;
+      _heading = utilFunctor(val);
+      return tooltip;
     };
-    var _cullFactor = 1;
-    var _cache5 = {};
-    var _rules = {};
-    var _stats = {};
-    var _keys = [];
-    var _hidden = [];
-    var _forceVisible = {};
-    function update() {
-      if (!window.mocha) {
-        var hash = utilStringQs(window.location.hash);
-        var disabled = features.disabled();
-        if (disabled.length) {
-          hash.disable_features = disabled.join(",");
-        } else {
-          delete hash.disable_features;
+    tooltip.keys = function(val) {
+      if (!arguments.length) return _keys;
+      _keys = utilFunctor(val);
+      return tooltip;
+    };
+    tooltip.content(function() {
+      var heading2 = _heading.apply(this, arguments);
+      var text = _title.apply(this, arguments);
+      var keys2 = _keys.apply(this, arguments);
+      var headingCallback = typeof heading2 === "function" ? heading2 : (s2) => s2.text(heading2);
+      var textCallback = typeof text === "function" ? text : (s2) => s2.text(text);
+      return function(selection2) {
+        var headingSelect = selection2.selectAll(".tooltip-heading").data(heading2 ? [heading2] : []);
+        headingSelect.exit().remove();
+        headingSelect.enter().append("div").attr("class", "tooltip-heading").merge(headingSelect).text("").call(headingCallback);
+        var textSelect = selection2.selectAll(".tooltip-text").data(text ? [text] : []);
+        textSelect.exit().remove();
+        textSelect.enter().append("div").attr("class", "tooltip-text").merge(textSelect).text("").call(textCallback);
+        var keyhintWrap = selection2.selectAll(".keyhint-wrap").data(keys2 && keys2.length ? [0] : []);
+        keyhintWrap.exit().remove();
+        var keyhintWrapEnter = keyhintWrap.enter().append("div").attr("class", "keyhint-wrap");
+        keyhintWrapEnter.append("span").call(_t.append("tooltip_keyhint"));
+        keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
+        keyhintWrap.selectAll("kbd.shortcut").data(keys2 && keys2.length ? keys2 : []).enter().append("kbd").attr("class", "shortcut").text(function(d2) {
+          return d2;
+        });
+      };
+    });
+    return tooltip;
+  }
+
+  // modules/ui/combobox.js
+  var _comboHideTimerID;
+  function uiCombobox(context, klass) {
+    var dispatch14 = dispatch_default("accept", "cancel", "update");
+    var container = context.container();
+    var _suggestions = [];
+    var _data = [];
+    var _fetched = {};
+    var _selected = null;
+    var _canAutocomplete = true;
+    var _caseSensitive = false;
+    var _cancelFetch = false;
+    var _minItems = 2;
+    var _tDown = 0;
+    var _mouseEnterHandler, _mouseLeaveHandler;
+    var _fetcher = function(val, cb) {
+      cb(_data.filter(function(d2) {
+        var terms = d2.terms || [];
+        terms.push(d2.value);
+        if (d2.key) {
+          terms.push(d2.key);
         }
-        window.location.replace("#" + utilQsString(hash, true));
-        corePreferences("disabled-features", disabled.join(","));
-      }
-      _hidden = features.hidden();
-      dispatch14.call("change");
-      dispatch14.call("redraw");
-    }
-    function defineRule(k2, filter2, max3) {
-      var isEnabled = true;
-      _keys.push(k2);
-      _rules[k2] = {
-        filter: filter2,
-        enabled: isEnabled,
-        // whether the user wants it enabled..
-        count: 0,
-        currentMax: max3 || Infinity,
-        defaultMax: max3 || Infinity,
-        enable: function() {
-          this.enabled = true;
-          this.currentMax = this.defaultMax;
-        },
-        disable: function() {
-          this.enabled = false;
-          this.currentMax = 0;
-        },
-        hidden: function() {
-          return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
-        },
-        autoHidden: function() {
-          return this.hidden() && this.currentMax > 0;
-        }
-      };
-    }
-    defineRule("points", function isPoint(tags, geometry) {
-      return geometry === "point";
-    }, 200);
-    defineRule("traffic_roads", function isTrafficRoad(tags) {
-      return traffic_roads[tags.highway];
-    });
-    defineRule("service_roads", function isServiceRoad(tags) {
-      return service_roads[tags.highway];
-    });
-    defineRule("paths", function isPath(tags) {
-      return paths[tags.highway];
-    });
-    defineRule("buildings", function isBuilding(tags) {
-      return !!tags.building && tags.building !== "no" || tags.parking === "multi-storey" || tags.parking === "sheds" || tags.parking === "carports" || tags.parking === "garage_boxes";
-    }, 250);
-    defineRule("building_parts", function isBuildingPart(tags) {
-      return tags["building:part"];
-    });
-    defineRule("indoor", function isIndoor(tags) {
-      return tags.indoor;
-    });
-    defineRule("landuse", function isLanduse(tags, geometry) {
-      return geometry === "area" && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
-    });
-    defineRule("boundaries", function isBoundary(tags, geometry) {
-      return (geometry === "line" && !!tags.boundary || geometry === "relation" && tags.type === "boundary") && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway] || tags.waterway || tags.railway || tags.landuse || tags.natural || tags.building || tags.power);
-    });
-    defineRule("water", function isWater(tags) {
-      return !!tags.waterway || tags.natural === "water" || tags.natural === "coastline" || tags.natural === "bay" || tags.landuse === "pond" || tags.landuse === "basin" || tags.landuse === "reservoir" || tags.landuse === "salt_pond";
-    });
-    defineRule("rail", function isRail(tags) {
-      return (!!tags.railway || tags.landuse === "railway") && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
-    });
-    defineRule("pistes", function isPiste(tags) {
-      return tags["piste:type"];
-    });
-    defineRule("aerialways", function isPiste(tags) {
-      return tags.aerialway && tags.aerialway !== "yes" && tags.aerialway !== "station";
-    });
-    defineRule("power", function isPower(tags) {
-      return !!tags.power;
-    });
-    defineRule("past_future", function isPastFuture(tags) {
-      if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
-        return false;
-      }
-      var strings = Object.keys(tags);
-      for (var i3 = 0; i3 < strings.length; i3++) {
-        var s2 = strings[i3];
-        if (osmLifecyclePrefixes[s2] || osmLifecyclePrefixes[tags[s2]])
-          return true;
-      }
-      return false;
-    });
-    defineRule("others", function isOther(tags, geometry) {
-      return geometry === "line" || geometry === "area";
-    });
-    features.features = function() {
-      return _rules;
-    };
-    features.keys = function() {
-      return _keys;
-    };
-    features.enabled = function(k2) {
-      if (!arguments.length) {
-        return _keys.filter(function(k3) {
-          return _rules[k3].enabled;
-        });
-      }
-      return _rules[k2] && _rules[k2].enabled;
-    };
-    features.disabled = function(k2) {
-      if (!arguments.length) {
-        return _keys.filter(function(k3) {
-          return !_rules[k3].enabled;
-        });
-      }
-      return _rules[k2] && !_rules[k2].enabled;
-    };
-    features.hidden = function(k2) {
-      if (!arguments.length) {
-        return _keys.filter(function(k3) {
-          return _rules[k3].hidden();
+        return terms.some(function(term) {
+          return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
         });
-      }
-      return _rules[k2] && _rules[k2].hidden();
+      }));
     };
-    features.autoHidden = function(k2) {
-      if (!arguments.length) {
-        return _keys.filter(function(k3) {
-          return _rules[k3].autoHidden();
+    var combobox = function(input, attachTo) {
+      if (!input || input.empty()) return;
+      input.classed("combobox-input", true).on("focus.combo-input", focus).on("blur.combo-input", blur).on("keydown.combo-input", keydown).on("keyup.combo-input", keyup).on("input.combo-input", change).on("mousedown.combo-input", mousedown).each(function() {
+        var parent = this.parentNode;
+        var sibling = this.nextSibling;
+        select_default2(parent).selectAll(".combobox-caret").filter(function(d2) {
+          return d2 === input.node();
+        }).data([input.node()]).enter().insert("div", function() {
+          return sibling;
+        }).attr("class", "combobox-caret").on("mousedown.combo-caret", function(d3_event) {
+          d3_event.preventDefault();
+          input.node().focus();
+          mousedown(d3_event);
+        }).on("mouseup.combo-caret", function(d3_event) {
+          d3_event.preventDefault();
+          mouseup(d3_event);
         });
-      }
-      return _rules[k2] && _rules[k2].autoHidden();
-    };
-    features.enable = function(k2) {
-      if (_rules[k2] && !_rules[k2].enabled) {
-        _rules[k2].enable();
-        update();
-      }
-    };
-    features.enableAll = function() {
-      var didEnable = false;
-      for (var k2 in _rules) {
-        if (!_rules[k2].enabled) {
-          didEnable = true;
-          _rules[k2].enable();
+      });
+      function mousedown(d3_event) {
+        if (d3_event.button !== 0) return;
+        if (input.classed("disabled")) return;
+        _tDown = +/* @__PURE__ */ new Date();
+        var start2 = input.property("selectionStart");
+        var end = input.property("selectionEnd");
+        if (start2 !== end) {
+          var val = utilGetSetValue(input);
+          input.node().setSelectionRange(val.length, val.length);
+          return;
         }
+        input.on("mouseup.combo-input", mouseup);
       }
-      if (didEnable)
-        update();
-    };
-    features.disable = function(k2) {
-      if (_rules[k2] && _rules[k2].enabled) {
-        _rules[k2].disable();
-        update();
-      }
-    };
-    features.disableAll = function() {
-      var didDisable = false;
-      for (var k2 in _rules) {
-        if (_rules[k2].enabled) {
-          didDisable = true;
-          _rules[k2].disable();
+      function mouseup(d3_event) {
+        input.on("mouseup.combo-input", null);
+        if (d3_event.button !== 0) return;
+        if (input.classed("disabled")) return;
+        if (input.node() !== document.activeElement) return;
+        var start2 = input.property("selectionStart");
+        var end = input.property("selectionEnd");
+        if (start2 !== end) return;
+        var combo = container.selectAll(".combobox");
+        if (combo.empty() || combo.datum() !== input.node()) {
+          var tOrig = _tDown;
+          window.setTimeout(function() {
+            if (tOrig !== _tDown) return;
+            fetchComboData("", function() {
+              show();
+              render();
+            });
+          }, 250);
+        } else {
+          hide();
         }
       }
-      if (didDisable)
-        update();
-    };
-    features.toggle = function(k2) {
-      if (_rules[k2]) {
-        (function(f2) {
-          return f2.enabled ? f2.disable() : f2.enable();
-        })(_rules[k2]);
-        update();
+      function focus() {
+        fetchComboData("");
       }
-    };
-    features.resetStats = function() {
-      for (var i3 = 0; i3 < _keys.length; i3++) {
-        _rules[_keys[i3]].count = 0;
+      function blur() {
+        _comboHideTimerID = window.setTimeout(hide, 75);
       }
-      dispatch14.call("change");
-    };
-    features.gatherStats = function(d2, resolver, dimensions) {
-      var needsRedraw = false;
-      var types = utilArrayGroupBy(d2, "type");
-      var entities = [].concat(types.relation || [], types.way || [], types.node || []);
-      var currHidden, geometry, matches, i3, j2;
-      for (i3 = 0; i3 < _keys.length; i3++) {
-        _rules[_keys[i3]].count = 0;
+      function show() {
+        hide();
+        container.insert("div", ":first-child").datum(input.node()).attr("class", "combobox" + (klass ? " combobox-" + klass : "")).style("position", "absolute").style("display", "block").style("left", "0px").on("mousedown.combo-container", function(d3_event) {
+          d3_event.preventDefault();
+        });
+        container.on("scroll.combo-scroll", render, true);
       }
-      _cullFactor = dimensions[0] * dimensions[1] / 1e6;
-      for (i3 = 0; i3 < entities.length; i3++) {
-        geometry = entities[i3].geometry(resolver);
-        matches = Object.keys(features.getMatches(entities[i3], resolver, geometry));
-        for (j2 = 0; j2 < matches.length; j2++) {
-          _rules[matches[j2]].count++;
+      function hide() {
+        if (_comboHideTimerID) {
+          window.clearTimeout(_comboHideTimerID);
+          _comboHideTimerID = void 0;
         }
+        container.selectAll(".combobox").remove();
+        container.on("scroll.combo-scroll", null);
       }
-      currHidden = features.hidden();
-      if (currHidden !== _hidden) {
-        _hidden = currHidden;
-        needsRedraw = true;
-        dispatch14.call("change");
-      }
-      return needsRedraw;
-    };
-    features.stats = function() {
-      for (var i3 = 0; i3 < _keys.length; i3++) {
-        _stats[_keys[i3]] = _rules[_keys[i3]].count;
-      }
-      return _stats;
-    };
-    features.clear = function(d2) {
-      for (var i3 = 0; i3 < d2.length; i3++) {
-        features.clearEntity(d2[i3]);
+      function keydown(d3_event) {
+        var shown = !container.selectAll(".combobox").empty();
+        var tagName = input.node() ? input.node().tagName.toLowerCase() : "";
+        switch (d3_event.keyCode) {
+          case 8:
+          // ⌫ Backspace
+          case 46:
+            d3_event.stopPropagation();
+            _selected = null;
+            render();
+            input.on("input.combo-input", function() {
+              var start2 = input.property("selectionStart");
+              input.node().setSelectionRange(start2, start2);
+              input.on("input.combo-input", change);
+              change(false);
+            });
+            break;
+          case 9:
+            accept(d3_event);
+            break;
+          case 13:
+            d3_event.preventDefault();
+            d3_event.stopPropagation();
+            accept(d3_event);
+            break;
+          case 38:
+            if (tagName === "textarea" && !shown) return;
+            d3_event.preventDefault();
+            if (tagName === "input" && !shown) {
+              show();
+            }
+            nav(-1);
+            break;
+          case 40:
+            if (tagName === "textarea" && !shown) return;
+            d3_event.preventDefault();
+            if (tagName === "input" && !shown) {
+              show();
+            }
+            nav(1);
+            break;
+        }
       }
-    };
-    features.clearEntity = function(entity) {
-      delete _cache5[osmEntity.key(entity)];
-    };
-    features.reset = function() {
-      Array.from(_deferred2).forEach(function(handle) {
-        window.cancelIdleCallback(handle);
-        _deferred2.delete(handle);
-      });
-      _cache5 = {};
-    };
-    function relationShouldBeChecked(relation) {
-      return relation.tags.type === "boundary";
-    }
-    features.getMatches = function(entity, resolver, geometry) {
-      if (geometry === "vertex" || geometry === "relation" && !relationShouldBeChecked(entity))
-        return {};
-      var ent = osmEntity.key(entity);
-      if (!_cache5[ent]) {
-        _cache5[ent] = {};
+      function keyup(d3_event) {
+        switch (d3_event.keyCode) {
+          case 27:
+            cancel();
+            break;
+        }
       }
-      if (!_cache5[ent].matches) {
-        var matches = {};
-        var hasMatch = false;
-        for (var i3 = 0; i3 < _keys.length; i3++) {
-          if (_keys[i3] === "others") {
-            if (hasMatch)
-              continue;
-            if (entity.type === "way") {
-              var parents = features.getParents(entity, resolver, geometry);
-              if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
-              parents.length > 0 && parents.every(function(parent) {
-                return parent.tags.type === "boundary";
-              })) {
-                var pkey = osmEntity.key(parents[0]);
-                if (_cache5[pkey] && _cache5[pkey].matches) {
-                  matches = Object.assign({}, _cache5[pkey].matches);
-                  continue;
-                }
-              }
+      function change(doAutoComplete) {
+        if (doAutoComplete === void 0) doAutoComplete = true;
+        fetchComboData(value(), function(skipAutosuggest) {
+          _selected = null;
+          var val = input.property("value");
+          if (_suggestions.length) {
+            if (doAutoComplete && !skipAutosuggest && input.property("selectionEnd") === val.length) {
+              _selected = tryAutocomplete();
+            }
+            if (!_selected) {
+              _selected = val;
             }
           }
-          if (_rules[_keys[i3]].filter(entity.tags, geometry)) {
-            matches[_keys[i3]] = hasMatch = true;
+          if (val.length) {
+            var combo = container.selectAll(".combobox");
+            if (combo.empty()) {
+              show();
+            }
+          } else {
+            hide();
           }
-        }
-        _cache5[ent].matches = matches;
-      }
-      return _cache5[ent].matches;
-    };
-    features.getParents = function(entity, resolver, geometry) {
-      if (geometry === "point")
-        return [];
-      var ent = osmEntity.key(entity);
-      if (!_cache5[ent]) {
-        _cache5[ent] = {};
-      }
-      if (!_cache5[ent].parents) {
-        var parents = [];
-        if (geometry === "vertex") {
-          parents = resolver.parentWays(entity);
-        } else {
-          parents = resolver.parentRelations(entity);
-        }
-        _cache5[ent].parents = parents;
+          render();
+        });
       }
-      return _cache5[ent].parents;
-    };
-    features.isHiddenPreset = function(preset, geometry) {
-      if (!_hidden.length)
-        return false;
-      if (!preset.tags)
-        return false;
-      var test = preset.setTags({}, geometry);
-      for (var key in _rules) {
-        if (_rules[key].filter(test, geometry)) {
-          if (_hidden.indexOf(key) !== -1) {
-            return key;
+      function nav(dir) {
+        if (_suggestions.length) {
+          var index = -1;
+          for (var i3 = 0; i3 < _suggestions.length; i3++) {
+            if (_selected && _suggestions[i3].value === _selected) {
+              index = i3;
+              break;
+            }
           }
-          return false;
+          index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
+          _selected = _suggestions[index].value;
+          utilGetSetValue(input, _selected);
+          dispatch14.call("update");
         }
+        render();
+        ensureVisible();
       }
-      return false;
-    };
-    features.isHiddenFeature = function(entity, resolver, geometry) {
-      if (!_hidden.length)
-        return false;
-      if (!entity.version)
-        return false;
-      if (_forceVisible[entity.id])
-        return false;
-      var matches = Object.keys(features.getMatches(entity, resolver, geometry));
-      return matches.length && matches.every(function(k2) {
-        return features.hidden(k2);
-      });
-    };
-    features.isHiddenChild = function(entity, resolver, geometry) {
-      if (!_hidden.length)
-        return false;
-      if (!entity.version || geometry === "point")
-        return false;
-      if (_forceVisible[entity.id])
-        return false;
-      var parents = features.getParents(entity, resolver, geometry);
-      if (!parents.length)
-        return false;
-      for (var i3 = 0; i3 < parents.length; i3++) {
-        if (!features.isHidden(parents[i3], resolver, parents[i3].geometry(resolver))) {
-          return false;
+      function ensureVisible() {
+        var combo = container.selectAll(".combobox");
+        if (combo.empty()) return;
+        var containerRect = container.node().getBoundingClientRect();
+        var comboRect = combo.node().getBoundingClientRect();
+        if (comboRect.bottom > containerRect.bottom) {
+          var node = attachTo ? attachTo.node() : input.node();
+          node.scrollIntoView({ behavior: "instant", block: "center" });
+          render();
+        }
+        var selected = combo.selectAll(".combobox-option.selected").node();
+        if (selected) {
+          selected.scrollIntoView({ behavior: "smooth", block: "nearest" });
         }
       }
-      return true;
-    };
-    features.hasHiddenConnections = function(entity, resolver) {
-      if (!_hidden.length)
-        return false;
-      var childNodes, connections;
-      if (entity.type === "midpoint") {
-        childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
-        connections = [];
-      } else {
-        childNodes = entity.nodes ? resolver.childNodes(entity) : [];
-        connections = features.getParents(entity, resolver, entity.geometry(resolver));
-      }
-      connections = childNodes.reduce(function(result, e3) {
-        return resolver.isShared(e3) ? utilArrayUnion(result, resolver.parentWays(e3)) : result;
-      }, connections);
-      return connections.some(function(e3) {
-        return features.isHidden(e3, resolver, e3.geometry(resolver));
-      });
-    };
-    features.isHidden = function(entity, resolver, geometry) {
-      if (!_hidden.length)
-        return false;
-      if (!entity.version)
-        return false;
-      var fn = geometry === "vertex" ? features.isHiddenChild : features.isHiddenFeature;
-      return fn(entity, resolver, geometry);
-    };
-    features.filter = function(d2, resolver) {
-      if (!_hidden.length)
-        return d2;
-      var result = [];
-      for (var i3 = 0; i3 < d2.length; i3++) {
-        var entity = d2[i3];
-        if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
-          result.push(entity);
+      function value() {
+        var value2 = input.property("value");
+        var start2 = input.property("selectionStart");
+        var end = input.property("selectionEnd");
+        if (start2 && end) {
+          value2 = value2.substring(0, start2);
         }
+        return value2;
       }
-      return result;
-    };
-    features.forceVisible = function(entityIDs) {
-      if (!arguments.length)
-        return Object.keys(_forceVisible);
-      _forceVisible = {};
-      for (var i3 = 0; i3 < entityIDs.length; i3++) {
-        _forceVisible[entityIDs[i3]] = true;
-        var entity = context.hasEntity(entityIDs[i3]);
-        if (entity && entity.type === "relation") {
-          for (var j2 in entity.members) {
-            _forceVisible[entity.members[j2].id] = true;
+      function fetchComboData(v2, cb) {
+        _cancelFetch = false;
+        _fetcher.call(input, v2, function(results, skipAutosuggest) {
+          if (_cancelFetch) return;
+          _suggestions = results;
+          results.forEach(function(d2) {
+            _fetched[d2.value] = d2;
+          });
+          if (cb) {
+            cb(skipAutosuggest);
+          }
+        });
+      }
+      function tryAutocomplete() {
+        if (!_canAutocomplete) return;
+        var val = _caseSensitive ? value() : value().toLowerCase();
+        if (!val) return;
+        if (isFinite(val)) return;
+        const suggestionValues = [];
+        _suggestions.forEach((s2) => {
+          suggestionValues.push(s2.value);
+          if (s2.key && s2.key !== s2.value) {
+            suggestionValues.push(s2.key);
+          }
+        });
+        var bestIndex = -1;
+        for (var i3 = 0; i3 < suggestionValues.length; i3++) {
+          var suggestion = suggestionValues[i3];
+          var compare2 = _caseSensitive ? suggestion : suggestion.toLowerCase();
+          if (compare2 === val) {
+            bestIndex = i3;
+            break;
+          } else if (bestIndex === -1 && compare2.indexOf(val) === 0) {
+            bestIndex = i3;
           }
         }
+        if (bestIndex !== -1) {
+          var bestVal = suggestionValues[bestIndex];
+          input.property("value", bestVal);
+          input.node().setSelectionRange(val.length, bestVal.length);
+          dispatch14.call("update");
+          return bestVal;
+        }
       }
-      return features;
-    };
-    features.init = function() {
-      var storage = corePreferences("disabled-features");
-      if (storage) {
-        var storageDisabled = storage.replace(/;/g, ",").split(",");
-        storageDisabled.forEach(features.disable);
-      }
-      var hash = utilStringQs(window.location.hash);
-      if (hash.disable_features) {
-        var hashDisabled = hash.disable_features.replace(/;/g, ",").split(",");
-        hashDisabled.forEach(features.disable);
+      function render() {
+        if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
+          hide();
+          return;
+        }
+        var shown = !container.selectAll(".combobox").empty();
+        if (!shown) return;
+        var combo = container.selectAll(".combobox");
+        var options2 = combo.selectAll(".combobox-option").data(_suggestions, function(d2) {
+          return d2.value;
+        });
+        options2.exit().remove();
+        options2.enter().append("a").attr("class", function(d2) {
+          return "combobox-option " + (d2.klass || "");
+        }).attr("title", function(d2) {
+          return d2.title;
+        }).each(function(d2) {
+          if (d2.display) {
+            d2.display(select_default2(this));
+          } else {
+            select_default2(this).text(d2.value);
+          }
+        }).on("mouseenter", _mouseEnterHandler).on("mouseleave", _mouseLeaveHandler).merge(options2).classed("selected", function(d2) {
+          return d2.value === _selected || d2.key === _selected;
+        }).on("click.combo-option", accept).order();
+        var node = attachTo ? attachTo.node() : input.node();
+        var containerRect = container.node().getBoundingClientRect();
+        var rect = node.getBoundingClientRect();
+        combo.style("left", rect.left + 5 - containerRect.left + "px").style("width", rect.width - 10 + "px").style("top", rect.height + rect.top - containerRect.top + "px");
       }
-    };
-    context.history().on("merge.features", function(newEntities) {
-      if (!newEntities)
-        return;
-      var handle = window.requestIdleCallback(function() {
-        var graph = context.graph();
-        var types = utilArrayGroupBy(newEntities, "type");
-        var entities = [].concat(types.relation || [], types.way || [], types.node || []);
-        for (var i3 = 0; i3 < entities.length; i3++) {
-          var geometry = entities[i3].geometry(graph);
-          features.getMatches(entities[i3], graph, geometry);
+      function accept(d3_event, d2) {
+        _cancelFetch = true;
+        var thiz = input.node();
+        if (d2) {
+          utilGetSetValue(input, d2.value);
+          utilTriggerEvent(input, "change");
         }
-      });
-      _deferred2.add(handle);
-    });
-    return features;
-  }
-
-  // modules/svg/areas.js
-  var import_fast_deep_equal5 = __toESM(require_fast_deep_equal());
-
-  // modules/svg/helpers.js
-  function svgPassiveVertex(node, graph, activeID) {
-    if (!activeID)
-      return 1;
-    if (activeID === node.id)
-      return 0;
-    var parents = graph.parentWays(node);
-    var i3, j2, nodes, isClosed, ix1, ix2, ix3, ix4, max3;
-    for (i3 = 0; i3 < parents.length; i3++) {
-      nodes = parents[i3].nodes;
-      isClosed = parents[i3].isClosed();
-      for (j2 = 0; j2 < nodes.length; j2++) {
-        if (nodes[j2] === node.id) {
-          ix1 = j2 - 2;
-          ix2 = j2 - 1;
-          ix3 = j2 + 1;
-          ix4 = j2 + 2;
-          if (isClosed) {
-            max3 = nodes.length - 1;
-            if (ix1 < 0)
-              ix1 = max3 + ix1;
-            if (ix2 < 0)
-              ix2 = max3 + ix2;
-            if (ix3 > max3)
-              ix3 = ix3 - max3;
-            if (ix4 > max3)
-              ix4 = ix4 - max3;
-          }
-          if (nodes[ix1] === activeID)
-            return 0;
-          else if (nodes[ix2] === activeID)
-            return 2;
-          else if (nodes[ix3] === activeID)
-            return 2;
-          else if (nodes[ix4] === activeID)
-            return 0;
-          else if (isClosed && nodes.indexOf(activeID) !== -1)
-            return 0;
+        var val = utilGetSetValue(input);
+        thiz.setSelectionRange(val.length, val.length);
+        if (!d2) {
+          d2 = _fetched[val];
         }
+        dispatch14.call("accept", thiz, d2, val);
+        hide();
       }
-    }
-    return 1;
-  }
-  function svgMarkerSegments(projection2, graph, dt2, shouldReverse, bothDirections) {
-    return function(entity) {
-      var i3 = 0;
-      var offset = dt2;
-      var segments = [];
-      var clip = identity_default2().clipExtent(projection2.clipExtent()).stream;
-      var coordinates = graph.childNodes(entity).map(function(n3) {
-        return n3.loc;
-      });
-      var a2, b2;
-      if (shouldReverse(entity)) {
-        coordinates.reverse();
+      function cancel() {
+        _cancelFetch = true;
+        var thiz = input.node();
+        var val = utilGetSetValue(input);
+        var start2 = input.property("selectionStart");
+        var end = input.property("selectionEnd");
+        val = val.slice(0, start2) + val.slice(end);
+        utilGetSetValue(input, val);
+        thiz.setSelectionRange(val.length, val.length);
+        dispatch14.call("cancel", thiz);
+        hide();
       }
-      stream_default({
-        type: "LineString",
-        coordinates
-      }, projection2.stream(clip({
-        lineStart: function() {
-        },
-        lineEnd: function() {
-          a2 = null;
-        },
-        point: function(x2, y2) {
-          b2 = [x2, y2];
-          if (a2) {
-            var span = geoVecLength(a2, b2) - offset;
-            if (span >= 0) {
-              var heading2 = geoVecAngle(a2, b2);
-              var dx = dt2 * Math.cos(heading2);
-              var dy = dt2 * Math.sin(heading2);
-              var p2 = [
-                a2[0] + offset * Math.cos(heading2),
-                a2[1] + offset * Math.sin(heading2)
-              ];
-              var coord2 = [a2, p2];
-              for (span -= dt2; span >= 0; span -= dt2) {
-                p2 = geoVecAdd(p2, [dx, dy]);
-                coord2.push(p2);
-              }
-              coord2.push(b2);
-              var segment = "";
-              var j2;
-              for (j2 = 0; j2 < coord2.length; j2++) {
-                segment += (j2 === 0 ? "M" : "L") + coord2[j2][0] + "," + coord2[j2][1];
-              }
-              segments.push({ id: entity.id, index: i3++, d: segment });
-              if (bothDirections(entity)) {
-                segment = "";
-                for (j2 = coord2.length - 1; j2 >= 0; j2--) {
-                  segment += (j2 === coord2.length - 1 ? "M" : "L") + coord2[j2][0] + "," + coord2[j2][1];
-                }
-                segments.push({ id: entity.id, index: i3++, d: segment });
-              }
-            }
-            offset = -span;
-          }
-          a2 = b2;
-        }
-      })));
-      return segments;
     };
-  }
-  function svgPath(projection2, graph, isArea) {
-    var cache = {};
-    var padding = isArea ? 65 : 5;
-    var viewport = projection2.clipExtent();
-    var paddedExtent = [
-      [viewport[0][0] - padding, viewport[0][1] - padding],
-      [viewport[1][0] + padding, viewport[1][1] + padding]
-    ];
-    var clip = identity_default2().clipExtent(paddedExtent).stream;
-    var project = projection2.stream;
-    var path = path_default().projection({ stream: function(output) {
-      return project(clip(output));
-    } });
-    var svgpath = function(entity) {
-      if (entity.id in cache) {
-        return cache[entity.id];
-      } else {
-        return cache[entity.id] = path(entity.asGeoJSON(graph));
-      }
+    combobox.canAutocomplete = function(val) {
+      if (!arguments.length) return _canAutocomplete;
+      _canAutocomplete = val;
+      return combobox;
     };
-    svgpath.geojson = function(d2) {
-      if (d2.__featurehash__ !== void 0) {
-        if (d2.__featurehash__ in cache) {
-          return cache[d2.__featurehash__];
-        } else {
-          return cache[d2.__featurehash__] = path(d2);
-        }
-      } else {
-        return path(d2);
-      }
+    combobox.caseSensitive = function(val) {
+      if (!arguments.length) return _caseSensitive;
+      _caseSensitive = val;
+      return combobox;
     };
-    return svgpath;
-  }
-  function svgPointTransform(projection2) {
-    var svgpoint = function(entity) {
-      var pt2 = projection2(entity.loc);
-      return "translate(" + pt2[0] + "," + pt2[1] + ")";
+    combobox.data = function(val) {
+      if (!arguments.length) return _data;
+      _data = val;
+      return combobox;
     };
-    svgpoint.geojson = function(d2) {
-      return svgpoint(d2.properties.entity);
+    combobox.fetcher = function(val) {
+      if (!arguments.length) return _fetcher;
+      _fetcher = val;
+      return combobox;
     };
-    return svgpoint;
+    combobox.minItems = function(val) {
+      if (!arguments.length) return _minItems;
+      _minItems = val;
+      return combobox;
+    };
+    combobox.itemsMouseEnter = function(val) {
+      if (!arguments.length) return _mouseEnterHandler;
+      _mouseEnterHandler = val;
+      return combobox;
+    };
+    combobox.itemsMouseLeave = function(val) {
+      if (!arguments.length) return _mouseLeaveHandler;
+      _mouseLeaveHandler = val;
+      return combobox;
+    };
+    return utilRebind(combobox, dispatch14, "on");
   }
-  function svgRelationMemberTags(graph) {
-    return function(entity) {
-      var tags = entity.tags;
-      var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
-      graph.parentRelations(entity).forEach(function(relation) {
-        var type2 = relation.tags.type;
-        if (type2 === "multipolygon" && shouldCopyMultipolygonTags || type2 === "boundary") {
-          tags = Object.assign({}, relation.tags, tags);
-        }
-      });
-      return tags;
+  uiCombobox.off = function(input, context) {
+    input.on("focus.combo-input", null).on("blur.combo-input", null).on("keydown.combo-input", null).on("keyup.combo-input", null).on("input.combo-input", null).on("mousedown.combo-input", null).on("mouseup.combo-input", null);
+    context.container().on("scroll.combo-scroll", null);
+  };
+
+  // modules/ui/intro/helper.js
+  function pointBox(loc, context) {
+    var rect = context.surfaceRect();
+    var point = context.curtainProjection(loc);
+    return {
+      left: point[0] + rect.left - 40,
+      top: point[1] + rect.top - 60,
+      width: 80,
+      height: 90
     };
   }
-  function svgSegmentWay(way, graph, activeID) {
-    if (activeID === void 0) {
-      return graph.transient(way, "waySegments", getWaySegments);
+  function pad(locOrBox, padding, context) {
+    var box;
+    if (locOrBox instanceof Array) {
+      var rect = context.surfaceRect();
+      var point = context.curtainProjection(locOrBox);
+      box = {
+        left: point[0] + rect.left,
+        top: point[1] + rect.top
+      };
     } else {
-      return getWaySegments();
+      box = locOrBox;
     }
-    function getWaySegments() {
-      var isActiveWay = way.nodes.indexOf(activeID) !== -1;
-      var features = { passive: [], active: [] };
-      var start2 = {};
-      var end = {};
-      var node, type2;
-      for (var i3 = 0; i3 < way.nodes.length; i3++) {
-        node = graph.entity(way.nodes[i3]);
-        type2 = svgPassiveVertex(node, graph, activeID);
-        end = { node, type: type2 };
-        if (start2.type !== void 0) {
-          if (start2.node.id === activeID || end.node.id === activeID) {
-          } else if (isActiveWay && (start2.type === 2 || end.type === 2)) {
-            pushActive(start2, end, i3);
-          } else if (start2.type === 0 && end.type === 0) {
-            pushActive(start2, end, i3);
+    return {
+      left: box.left - padding,
+      top: box.top - padding,
+      width: (box.width || 0) + 2 * padding,
+      height: (box.width || 0) + 2 * padding
+    };
+  }
+  function icon(name, svgklass, useklass) {
+    return '<svg class="icon ' + (svgklass || "") + '"><use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : "") + "></use></svg>";
+  }
+  var helpStringReplacements;
+  function helpHtml(id2, replacements) {
+    if (!helpStringReplacements) {
+      helpStringReplacements = {
+        // insert icons corresponding to various UI elements
+        point_icon: icon("#iD-icon-point", "inline"),
+        line_icon: icon("#iD-icon-line", "inline"),
+        area_icon: icon("#iD-icon-area", "inline"),
+        note_icon: icon("#iD-icon-note", "inline add-note"),
+        plus: icon("#iD-icon-plus", "inline"),
+        minus: icon("#iD-icon-minus", "inline"),
+        layers_icon: icon("#iD-icon-layers", "inline"),
+        data_icon: icon("#iD-icon-data", "inline"),
+        inspect: icon("#iD-icon-inspect", "inline"),
+        help_icon: icon("#iD-icon-help", "inline"),
+        undo_icon: icon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-redo" : "#iD-icon-undo", "inline"),
+        redo_icon: icon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-undo" : "#iD-icon-redo", "inline"),
+        save_icon: icon("#iD-icon-save", "inline"),
+        // operation icons
+        circularize_icon: icon("#iD-operation-circularize", "inline operation"),
+        continue_icon: icon("#iD-operation-continue", "inline operation"),
+        copy_icon: icon("#iD-operation-copy", "inline operation"),
+        delete_icon: icon("#iD-operation-delete", "inline operation"),
+        disconnect_icon: icon("#iD-operation-disconnect", "inline operation"),
+        downgrade_icon: icon("#iD-operation-downgrade", "inline operation"),
+        extract_icon: icon("#iD-operation-extract", "inline operation"),
+        merge_icon: icon("#iD-operation-merge", "inline operation"),
+        move_icon: icon("#iD-operation-move", "inline operation"),
+        orthogonalize_icon: icon("#iD-operation-orthogonalize", "inline operation"),
+        paste_icon: icon("#iD-operation-paste", "inline operation"),
+        reflect_long_icon: icon("#iD-operation-reflect-long", "inline operation"),
+        reflect_short_icon: icon("#iD-operation-reflect-short", "inline operation"),
+        reverse_icon: icon("#iD-operation-reverse", "inline operation"),
+        rotate_icon: icon("#iD-operation-rotate", "inline operation"),
+        split_icon: icon("#iD-operation-split", "inline operation"),
+        straighten_icon: icon("#iD-operation-straighten", "inline operation"),
+        // interaction icons
+        leftclick: icon("#iD-walkthrough-mouse-left", "inline operation"),
+        rightclick: icon("#iD-walkthrough-mouse-right", "inline operation"),
+        mousewheel_icon: icon("#iD-walkthrough-mousewheel", "inline operation"),
+        tap_icon: icon("#iD-walkthrough-tap", "inline operation"),
+        doubletap_icon: icon("#iD-walkthrough-doubletap", "inline operation"),
+        longpress_icon: icon("#iD-walkthrough-longpress", "inline operation"),
+        touchdrag_icon: icon("#iD-walkthrough-touchdrag", "inline operation"),
+        pinch_icon: icon("#iD-walkthrough-pinch-apart", "inline operation"),
+        // insert keys; may be localized and platform-dependent
+        shift: uiCmd.display("\u21E7"),
+        alt: uiCmd.display("\u2325"),
+        return: uiCmd.display("\u21B5"),
+        esc: _t.html("shortcuts.key.esc"),
+        space: _t.html("shortcuts.key.space"),
+        add_note_key: _t.html("modes.add_note.key"),
+        help_key: _t.html("help.key"),
+        shortcuts_key: _t.html("shortcuts.toggle.key"),
+        // reference localized UI labels directly so that they'll always match
+        save: _t.html("save.title"),
+        undo: _t.html("undo.title"),
+        redo: _t.html("redo.title"),
+        upload: _t.html("commit.save"),
+        point: _t.html("modes.add_point.title"),
+        line: _t.html("modes.add_line.title"),
+        area: _t.html("modes.add_area.title"),
+        note: _t.html("modes.add_note.label"),
+        circularize: _t.html("operations.circularize.title"),
+        continue: _t.html("operations.continue.title"),
+        copy: _t.html("operations.copy.title"),
+        delete: _t.html("operations.delete.title"),
+        disconnect: _t.html("operations.disconnect.title"),
+        downgrade: _t.html("operations.downgrade.title"),
+        extract: _t.html("operations.extract.title"),
+        merge: _t.html("operations.merge.title"),
+        move: _t.html("operations.move.title"),
+        orthogonalize: _t.html("operations.orthogonalize.title"),
+        paste: _t.html("operations.paste.title"),
+        reflect_long: _t.html("operations.reflect.title.long"),
+        reflect_short: _t.html("operations.reflect.title.short"),
+        reverse: _t.html("operations.reverse.title"),
+        rotate: _t.html("operations.rotate.title"),
+        split: _t.html("operations.split.title"),
+        straighten: _t.html("operations.straighten.title"),
+        map_data: _t.html("map_data.title"),
+        osm_notes: _t.html("map_data.layers.notes.title"),
+        fields: _t.html("inspector.fields"),
+        tags: _t.html("inspector.tags"),
+        relations: _t.html("inspector.relations"),
+        new_relation: _t.html("inspector.new_relation"),
+        turn_restrictions: _t.html("_tagging.presets.fields.restrictions.label"),
+        background_settings: _t.html("background.description"),
+        imagery_offset: _t.html("background.fix_misalignment"),
+        start_the_walkthrough: _t.html("splash.walkthrough"),
+        help: _t.html("help.title"),
+        ok: _t.html("intro.ok")
+      };
+      for (var key in helpStringReplacements) {
+        helpStringReplacements[key] = { html: helpStringReplacements[key] };
+      }
+    }
+    var reps;
+    if (replacements) {
+      reps = Object.assign(replacements, helpStringReplacements);
+    } else {
+      reps = helpStringReplacements;
+    }
+    return _t.html(id2, reps).replace(/\`(.*?)\`/g, "<kbd>$1</kbd>");
+  }
+  function slugify(text) {
+    return text.toString().toLowerCase().replace(/\s+/g, "-").replace(/[^\w\-]+/g, "").replace(/\-\-+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
+  }
+  var missingStrings = {};
+  function checkKey(key, text) {
+    if (_t(key, { default: void 0 }) === void 0) {
+      if (missingStrings.hasOwnProperty(key)) return;
+      missingStrings[key] = text;
+      var missing = key + ": " + text;
+      if (typeof console !== "undefined") console.log(missing);
+    }
+  }
+  function localize(obj) {
+    var key;
+    var name = obj.tags && obj.tags.name;
+    if (name) {
+      key = "intro.graph.name." + slugify(name);
+      obj.tags.name = _t(key, { default: name });
+      checkKey(key, name);
+    }
+    var street = obj.tags && obj.tags["addr:street"];
+    if (street) {
+      key = "intro.graph.name." + slugify(street);
+      obj.tags["addr:street"] = _t(key, { default: street });
+      checkKey(key, street);
+      var addrTags = [
+        "block_number",
+        "city",
+        "county",
+        "district",
+        "hamlet",
+        "neighbourhood",
+        "postcode",
+        "province",
+        "quarter",
+        "state",
+        "subdistrict",
+        "suburb"
+      ];
+      addrTags.forEach(function(k2) {
+        var key2 = "intro.graph." + k2;
+        var tag2 = "addr:" + k2;
+        var val = obj.tags && obj.tags[tag2];
+        var str = _t(key2, { default: val });
+        if (str) {
+          if (str.match(/^<.*>$/) !== null) {
+            delete obj.tags[tag2];
           } else {
-            pushPassive(start2, end, i3);
+            obj.tags[tag2] = str;
           }
         }
-        start2 = end;
-      }
-      return features;
-      function pushActive(start3, end2, index) {
-        features.active.push({
-          type: "Feature",
-          id: way.id + "-" + index + "-nope",
-          properties: {
-            nope: true,
-            target: true,
-            entity: way,
-            nodes: [start3.node, end2.node],
-            index
-          },
-          geometry: {
-            type: "LineString",
-            coordinates: [start3.node.loc, end2.node.loc]
-          }
-        });
-      }
-      function pushPassive(start3, end2, index) {
-        features.passive.push({
-          type: "Feature",
-          id: way.id + "-" + index,
-          properties: {
-            target: true,
-            entity: way,
-            nodes: [start3.node, end2.node],
-            index
-          },
-          geometry: {
-            type: "LineString",
-            coordinates: [start3.node.loc, end2.node.loc]
-          }
-        });
+      });
+    }
+    return obj;
+  }
+  function isMostlySquare(points) {
+    var threshold = 15;
+    var lowerBound = Math.cos((90 - threshold) * Math.PI / 180);
+    var upperBound = Math.cos(threshold * Math.PI / 180);
+    for (var i3 = 0; i3 < points.length; i3++) {
+      var a2 = points[(i3 - 1 + points.length) % points.length];
+      var origin = points[i3];
+      var b2 = points[(i3 + 1) % points.length];
+      var dotp = geoVecNormalizedDot(a2, b2, origin);
+      var mag = Math.abs(dotp);
+      if (mag > lowerBound && mag < upperBound) {
+        return false;
       }
     }
+    return true;
+  }
+  function selectMenuItem(context, operation2) {
+    return context.container().select(".edit-menu .edit-menu-item-" + operation2);
+  }
+  function transitionTime(point1, point2) {
+    var distance = geoSphericalDistance(point1, point2);
+    if (distance === 0) {
+      return 0;
+    } else if (distance < 80) {
+      return 500;
+    } else {
+      return 1e3;
+    }
   }
 
-  // modules/svg/tag_classes.js
-  function svgTagClasses() {
-    var primaries = [
-      "building",
-      "highway",
-      "railway",
-      "waterway",
-      "aeroway",
-      "aerialway",
-      "piste:type",
-      "boundary",
-      "power",
+  // modules/ui/field_help.js
+  function uiFieldHelp(context, fieldName) {
+    var fieldHelp = {};
+    var _inspector = select_default2(null);
+    var _wrap = select_default2(null);
+    var _body = select_default2(null);
+    var fieldHelpKeys = {
+      restrictions: [
+        ["about", [
+          "about",
+          "from_via_to",
+          "maxdist",
+          "maxvia"
+        ]],
+        ["inspecting", [
+          "about",
+          "from_shadow",
+          "allow_shadow",
+          "restrict_shadow",
+          "only_shadow",
+          "restricted",
+          "only"
+        ]],
+        ["modifying", [
+          "about",
+          "indicators",
+          "allow_turn",
+          "restrict_turn",
+          "only_turn"
+        ]],
+        ["tips", [
+          "simple",
+          "simple_example",
+          "indirect",
+          "indirect_example",
+          "indirect_noedit"
+        ]]
+      ]
+    };
+    var fieldHelpHeadings = {};
+    var replacements = {
+      distField: { html: _t.html("restriction.controls.distance") },
+      viaField: { html: _t.html("restriction.controls.via") },
+      fromShadow: { html: icon("#iD-turn-shadow", "inline shadow from") },
+      allowShadow: { html: icon("#iD-turn-shadow", "inline shadow allow") },
+      restrictShadow: { html: icon("#iD-turn-shadow", "inline shadow restrict") },
+      onlyShadow: { html: icon("#iD-turn-shadow", "inline shadow only") },
+      allowTurn: { html: icon("#iD-turn-yes", "inline turn") },
+      restrictTurn: { html: icon("#iD-turn-no", "inline turn") },
+      onlyTurn: { html: icon("#iD-turn-only", "inline turn") }
+    };
+    var docs = fieldHelpKeys[fieldName].map(function(key) {
+      var helpkey = "help.field." + fieldName + "." + key[0];
+      var text = key[1].reduce(function(all, part) {
+        var subkey = helpkey + "." + part;
+        var depth = fieldHelpHeadings[subkey];
+        var hhh = depth ? Array(depth + 1).join("#") + " " : "";
+        return all + hhh + _t.html(subkey, replacements) + "\n\n";
+      }, "");
+      return {
+        key: helpkey,
+        title: _t.html(helpkey + ".title"),
+        html: marked(text.trim())
+      };
+    });
+    function show() {
+      updatePosition();
+      _body.classed("hide", false).style("opacity", "0").transition().duration(200).style("opacity", "1");
+    }
+    function hide() {
+      _body.classed("hide", true).transition().duration(200).style("opacity", "0").on("end", function() {
+        _body.classed("hide", true);
+      });
+    }
+    function clickHelp(index) {
+      var d2 = docs[index];
+      var tkeys = fieldHelpKeys[fieldName][index][1];
+      _body.selectAll(".field-help-nav-item").classed("active", function(d4, i3) {
+        return i3 === index;
+      });
+      var content = _body.selectAll(".field-help-content").html(d2.html);
+      content.selectAll("p").attr("class", function(d4, i3) {
+        return tkeys[i3];
+      });
+      if (d2.key === "help.field.restrictions.inspecting") {
+        content.insert("img", "p.from_shadow").attr("class", "field-help-image cf").attr("src", context.imagePath("tr_inspect.gif"));
+      } else if (d2.key === "help.field.restrictions.modifying") {
+        content.insert("img", "p.allow_turn").attr("class", "field-help-image cf").attr("src", context.imagePath("tr_modify.gif"));
+      }
+    }
+    fieldHelp.button = function(selection2) {
+      if (_body.empty()) return;
+      var button = selection2.selectAll(".field-help-button").data([0]);
+      button.enter().append("button").attr("class", "field-help-button").call(svgIcon("#iD-icon-help")).merge(button).on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        if (_body.classed("hide")) {
+          show();
+        } else {
+          hide();
+        }
+      });
+    };
+    function updatePosition() {
+      var wrap2 = _wrap.node();
+      var inspector = _inspector.node();
+      var wRect = wrap2.getBoundingClientRect();
+      var iRect = inspector.getBoundingClientRect();
+      _body.style("top", wRect.top + inspector.scrollTop - iRect.top + "px");
+    }
+    fieldHelp.body = function(selection2) {
+      _wrap = selection2.selectAll(".form-field-input-wrap");
+      if (_wrap.empty()) return;
+      _inspector = context.container().select(".sidebar .entity-editor-pane .inspector-body");
+      if (_inspector.empty()) return;
+      _body = _inspector.selectAll(".field-help-body").data([0]);
+      var enter = _body.enter().append("div").attr("class", "field-help-body hide");
+      var titleEnter = enter.append("div").attr("class", "field-help-title cf");
+      titleEnter.append("h2").attr("class", _mainLocalizer.textDirection() === "rtl" ? "fr" : "fl").call(_t.append("help.field." + fieldName + ".title"));
+      titleEnter.append("button").attr("class", "fr close").attr("title", _t("icons.close")).on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        hide();
+      }).call(svgIcon("#iD-icon-close"));
+      var navEnter = enter.append("div").attr("class", "field-help-nav cf");
+      var titles = docs.map(function(d2) {
+        return d2.title;
+      });
+      navEnter.selectAll(".field-help-nav-item").data(titles).enter().append("div").attr("class", "field-help-nav-item").html(function(d2) {
+        return d2;
+      }).on("click", function(d3_event, d2) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        clickHelp(titles.indexOf(d2));
+      });
+      enter.append("div").attr("class", "field-help-content");
+      _body = _body.merge(enter);
+      clickHelp(0);
+    };
+    return fieldHelp;
+  }
+
+  // modules/ui/fields/check.js
+  function uiFieldCheck(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var options2 = field.options;
+    var values = [];
+    var texts = [];
+    var _tags;
+    var input = select_default2(null);
+    var text = select_default2(null);
+    var label = select_default2(null);
+    var reverser = select_default2(null);
+    var _impliedYes;
+    var _entityIDs = [];
+    var _value;
+    var stringsField = field.resolveReference("stringsCrossReference");
+    if (!options2 && stringsField.options) {
+      options2 = stringsField.options;
+    }
+    if (options2) {
+      for (var i3 in options2) {
+        var v2 = options2[i3];
+        values.push(v2 === "undefined" ? void 0 : v2);
+        texts.push(stringsField.t.html("options." + v2, { "default": v2 }));
+      }
+    } else {
+      values = [void 0, "yes"];
+      texts = [_t.html("inspector.unknown"), _t.html("inspector.check.yes")];
+      if (field.type !== "defaultCheck") {
+        values.push("no");
+        texts.push(_t.html("inspector.check.no"));
+      }
+    }
+    function checkImpliedYes() {
+      _impliedYes = field.id === "oneway_yes";
+      if (field.id === "oneway") {
+        var entity = context.entity(_entityIDs[0]);
+        for (var key in entity.tags) {
+          if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
+            _impliedYes = true;
+            texts[0] = _t.html("_tagging.presets.fields.oneway_yes.options.undefined");
+            break;
+          }
+        }
+      }
+    }
+    function reverserHidden() {
+      if (!context.container().select("div.inspector-hover").empty()) return true;
+      return !(_value === "yes" || _impliedYes && !_value);
+    }
+    function reverserSetText(selection2) {
+      var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
+      if (reverserHidden() || !entity) return selection2;
+      var first = entity.first();
+      var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
+      var pseudoDirection = first < last;
+      var icon2 = pseudoDirection ? "#iD-icon-forward" : "#iD-icon-backward";
+      selection2.selectAll(".reverser-span").html("").call(_t.append("inspector.check.reverser")).call(svgIcon(icon2, "inline"));
+      return selection2;
+    }
+    var check = function(selection2) {
+      checkImpliedYes();
+      label = selection2.selectAll(".form-field-input-wrap").data([0]);
+      var enter = label.enter().append("label").attr("class", "form-field-input-wrap form-field-input-check");
+      enter.append("input").property("indeterminate", field.type !== "defaultCheck").attr("type", "checkbox").attr("id", field.domId);
+      enter.append("span").html(texts[0]).attr("class", "value");
+      if (field.type === "onewayCheck") {
+        enter.append("button").attr("class", "reverser" + (reverserHidden() ? " hide" : "")).append("span").attr("class", "reverser-span");
+      }
+      label = label.merge(enter);
+      input = label.selectAll("input");
+      text = label.selectAll("span.value");
+      input.on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        var t2 = {};
+        if (Array.isArray(_tags[field.key])) {
+          if (values.indexOf("yes") !== -1) {
+            t2[field.key] = "yes";
+          } else {
+            t2[field.key] = values[0];
+          }
+        } else {
+          t2[field.key] = values[(values.indexOf(_value) + 1) % values.length];
+        }
+        if (t2[field.key] === "reversible" || t2[field.key] === "alternating") {
+          t2[field.key] = values[0];
+        }
+        dispatch14.call("change", this, t2);
+      });
+      if (field.type === "onewayCheck") {
+        reverser = label.selectAll(".reverser");
+        reverser.call(reverserSetText).on("click", function(d3_event) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          context.perform(
+            function(graph) {
+              for (var i4 in _entityIDs) {
+                graph = actionReverse(_entityIDs[i4])(graph);
+              }
+              return graph;
+            },
+            _t("operations.reverse.annotation.line", { n: 1 })
+          );
+          context.validator().validate();
+          select_default2(this).call(reverserSetText);
+        });
+      }
+    };
+    check.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return check;
+    };
+    check.tags = function(tags) {
+      _tags = tags;
+      function isChecked(val) {
+        return val !== "no" && val !== "" && val !== void 0 && val !== null;
+      }
+      function textFor(val) {
+        if (val === "") val = void 0;
+        var index = values.indexOf(val);
+        return index !== -1 ? texts[index] : '"' + val + '"';
+      }
+      checkImpliedYes();
+      var isMixed = Array.isArray(tags[field.key]);
+      _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
+      if (field.type === "onewayCheck" && (_value === "1" || _value === "-1")) {
+        _value = "yes";
+      }
+      input.property("indeterminate", isMixed || field.type !== "defaultCheck" && !_value).property("checked", isChecked(_value));
+      text.html(isMixed ? _t.html("inspector.multiple_values") : textFor(_value)).classed("mixed", isMixed);
+      label.classed("set", !!_value);
+      if (field.type === "onewayCheck") {
+        reverser.classed("hide", reverserHidden()).call(reverserSetText);
+      }
+    };
+    check.focus = function() {
+      input.node().focus();
+    };
+    return utilRebind(check, dispatch14, "on");
+  }
+
+  // modules/svg/areas.js
+  var import_fast_deep_equal5 = __toESM(require_fast_deep_equal());
+
+  // modules/svg/helpers.js
+  function svgPassiveVertex(node, graph, activeID) {
+    if (!activeID) return 1;
+    if (activeID === node.id) return 0;
+    var parents = graph.parentWays(node);
+    var i3, j2, nodes, isClosed, ix1, ix2, ix3, ix4, max3;
+    for (i3 = 0; i3 < parents.length; i3++) {
+      nodes = parents[i3].nodes;
+      isClosed = parents[i3].isClosed();
+      for (j2 = 0; j2 < nodes.length; j2++) {
+        if (nodes[j2] === node.id) {
+          ix1 = j2 - 2;
+          ix2 = j2 - 1;
+          ix3 = j2 + 1;
+          ix4 = j2 + 2;
+          if (isClosed) {
+            max3 = nodes.length - 1;
+            if (ix1 < 0) ix1 = max3 + ix1;
+            if (ix2 < 0) ix2 = max3 + ix2;
+            if (ix3 > max3) ix3 = ix3 - max3;
+            if (ix4 > max3) ix4 = ix4 - max3;
+          }
+          if (nodes[ix1] === activeID) return 0;
+          else if (nodes[ix2] === activeID) return 2;
+          else if (nodes[ix3] === activeID) return 2;
+          else if (nodes[ix4] === activeID) return 0;
+          else if (isClosed && nodes.indexOf(activeID) !== -1) return 0;
+        }
+      }
+    }
+    return 1;
+  }
+  function svgMarkerSegments(projection2, graph, dt2, shouldReverse, bothDirections) {
+    return function(entity) {
+      var i3 = 0;
+      var offset = dt2;
+      var segments = [];
+      var clip = identity_default2().clipExtent(projection2.clipExtent()).stream;
+      var coordinates = graph.childNodes(entity).map(function(n3) {
+        return n3.loc;
+      });
+      var a2, b2;
+      if (shouldReverse(entity)) {
+        coordinates.reverse();
+      }
+      stream_default({
+        type: "LineString",
+        coordinates
+      }, projection2.stream(clip({
+        lineStart: function() {
+        },
+        lineEnd: function() {
+          a2 = null;
+        },
+        point: function(x2, y2) {
+          b2 = [x2, y2];
+          if (a2) {
+            var span = geoVecLength(a2, b2) - offset;
+            if (span >= 0) {
+              var heading2 = geoVecAngle(a2, b2);
+              var dx = dt2 * Math.cos(heading2);
+              var dy = dt2 * Math.sin(heading2);
+              var p2 = [
+                a2[0] + offset * Math.cos(heading2),
+                a2[1] + offset * Math.sin(heading2)
+              ];
+              var coord2 = [a2, p2];
+              for (span -= dt2; span >= 0; span -= dt2) {
+                p2 = geoVecAdd(p2, [dx, dy]);
+                coord2.push(p2);
+              }
+              coord2.push(b2);
+              var segment = "";
+              var j2;
+              for (j2 = 0; j2 < coord2.length; j2++) {
+                segment += (j2 === 0 ? "M" : "L") + coord2[j2][0] + "," + coord2[j2][1];
+              }
+              segments.push({ id: entity.id, index: i3++, d: segment });
+              if (bothDirections(entity)) {
+                segment = "";
+                for (j2 = coord2.length - 1; j2 >= 0; j2--) {
+                  segment += (j2 === coord2.length - 1 ? "M" : "L") + coord2[j2][0] + "," + coord2[j2][1];
+                }
+                segments.push({ id: entity.id, index: i3++, d: segment });
+              }
+            }
+            offset = -span;
+          }
+          a2 = b2;
+        }
+      })));
+      return segments;
+    };
+  }
+  function svgPath(projection2, graph, isArea) {
+    var cache = {};
+    var padding = isArea ? 65 : 5;
+    var viewport = projection2.clipExtent();
+    var paddedExtent = [
+      [viewport[0][0] - padding, viewport[0][1] - padding],
+      [viewport[1][0] + padding, viewport[1][1] + padding]
+    ];
+    var clip = identity_default2().clipExtent(paddedExtent).stream;
+    var project = projection2.stream;
+    var path = path_default().projection({ stream: function(output) {
+      return project(clip(output));
+    } });
+    var svgpath = function(entity) {
+      if (entity.id in cache) {
+        return cache[entity.id];
+      } else {
+        return cache[entity.id] = path(entity.asGeoJSON(graph));
+      }
+    };
+    svgpath.geojson = function(d2) {
+      if (d2.__featurehash__ !== void 0) {
+        if (d2.__featurehash__ in cache) {
+          return cache[d2.__featurehash__];
+        } else {
+          return cache[d2.__featurehash__] = path(d2);
+        }
+      } else {
+        return path(d2);
+      }
+    };
+    return svgpath;
+  }
+  function svgPointTransform(projection2) {
+    var svgpoint = function(entity) {
+      var pt2 = projection2(entity.loc);
+      return "translate(" + pt2[0] + "," + pt2[1] + ")";
+    };
+    svgpoint.geojson = function(d2) {
+      return svgpoint(d2.properties.entity);
+    };
+    return svgpoint;
+  }
+  function svgRelationMemberTags(graph) {
+    return function(entity) {
+      var tags = entity.tags;
+      var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
+      graph.parentRelations(entity).forEach(function(relation) {
+        var type2 = relation.tags.type;
+        if (type2 === "multipolygon" && shouldCopyMultipolygonTags || type2 === "boundary") {
+          tags = Object.assign({}, relation.tags, tags);
+        }
+      });
+      return tags;
+    };
+  }
+  function svgSegmentWay(way, graph, activeID) {
+    if (activeID === void 0) {
+      return graph.transient(way, "waySegments", getWaySegments);
+    } else {
+      return getWaySegments();
+    }
+    function getWaySegments() {
+      var isActiveWay = way.nodes.indexOf(activeID) !== -1;
+      var features = { passive: [], active: [] };
+      var start2 = {};
+      var end = {};
+      var node, type2;
+      for (var i3 = 0; i3 < way.nodes.length; i3++) {
+        node = graph.entity(way.nodes[i3]);
+        type2 = svgPassiveVertex(node, graph, activeID);
+        end = { node, type: type2 };
+        if (start2.type !== void 0) {
+          if (start2.node.id === activeID || end.node.id === activeID) {
+          } else if (isActiveWay && (start2.type === 2 || end.type === 2)) {
+            pushActive(start2, end, i3);
+          } else if (start2.type === 0 && end.type === 0) {
+            pushActive(start2, end, i3);
+          } else {
+            pushPassive(start2, end, i3);
+          }
+        }
+        start2 = end;
+      }
+      return features;
+      function pushActive(start3, end2, index) {
+        features.active.push({
+          type: "Feature",
+          id: way.id + "-" + index + "-nope",
+          properties: {
+            nope: true,
+            target: true,
+            entity: way,
+            nodes: [start3.node, end2.node],
+            index
+          },
+          geometry: {
+            type: "LineString",
+            coordinates: [start3.node.loc, end2.node.loc]
+          }
+        });
+      }
+      function pushPassive(start3, end2, index) {
+        features.passive.push({
+          type: "Feature",
+          id: way.id + "-" + index,
+          properties: {
+            target: true,
+            entity: way,
+            nodes: [start3.node, end2.node],
+            index
+          },
+          geometry: {
+            type: "LineString",
+            coordinates: [start3.node.loc, end2.node.loc]
+          }
+        });
+      }
+    }
+  }
+
+  // modules/svg/tag_classes.js
+  function svgTagClasses() {
+    var primaries = [
+      "building",
+      "highway",
+      "railway",
+      "waterway",
+      "aeroway",
+      "aerialway",
+      "piste:type",
+      "boundary",
+      "power",
       "amenity",
       "natural",
       "landuse",
       for (i3 = 0; i3 < primaries.length; i3++) {
         k2 = primaries[i3];
         v2 = t2[k2];
-        if (!v2 || v2 === "no")
-          continue;
+        if (!v2 || v2 === "no") continue;
         if (k2 === "piste:type") {
           k2 = "piste";
         } else if (k2 === "building:part") {
           for (j2 = 0; j2 < primaries.length; j2++) {
             k2 = statuses[i3] + ":" + primaries[j2];
             v2 = t2[k2];
-            if (!v2 || v2 === "no")
-              continue;
+            if (!v2 || v2 === "no") continue;
             status = statuses[i3];
             break;
           }
         for (i3 = 0; i3 < statuses.length; i3++) {
           k2 = statuses[i3];
           v2 = t2[k2];
-          if (!v2 || v2 === "no")
-            continue;
+          if (!v2 || v2 === "no") continue;
           if (v2 === "yes") {
             status = k2;
           } else if (primary && primary === v2) {
             primary = v2;
             classes.push("tag-" + v2);
           }
-          if (status)
-            break;
+          if (status) break;
         }
       }
       if (status) {
       for (i3 = 0; i3 < secondaries.length; i3++) {
         k2 = secondaries[i3];
         v2 = t2[k2];
-        if (!v2 || v2 === "no" || k2 === primary)
-          continue;
+        if (!v2 || v2 === "no" || k2 === primary) continue;
         classes.push("tag-" + k2);
         classes.push("tag-" + k2 + "-" + v2);
       }
       return classes.filter((klass) => /^[-_a-z0-9]+$/.test(klass)).join(" ").trim();
     };
     tagClasses.tags = function(val) {
-      if (!arguments.length)
-        return _tags;
+      if (!arguments.length) return _tags;
       _tags = val;
       return tagClasses;
     };
     }
     for (var tag2 in patterns) {
       var entityValue = tags[tag2];
-      if (!entityValue)
-        continue;
+      if (!entityValue) continue;
       if (typeof patterns[tag2] === "string") {
         return "pattern-" + patterns[tag2];
       } else {
         var values = patterns[tag2];
         for (var value in values) {
-          if (entityValue !== value)
-            continue;
+          if (entityValue !== value) continue;
           var rules = values[value];
           if (typeof rules === "string") {
             return "pattern-" + rules;
       var base = context.history().base();
       for (var i3 = 0; i3 < entities.length; i3++) {
         var entity = entities[i3];
-        if (entity.geometry(graph) !== "area")
-          continue;
+        if (entity.geometry(graph) !== "area") continue;
         if (!areas[entity.id]) {
           areas[entity.id] = {
             entity,
     };
   }
   function extractProperties(node) {
-    var _a2;
+    var _a3;
     const properties = getMulti(node, [
       "name",
       "cmt",
     ]);
     const extensions = Array.from(node.getElementsByTagNameNS("http://www.garmin.com/xmlschemas/GpxExtensions/v3", "*"));
     for (const child of extensions) {
-      if (((_a2 = child.parentNode) == null ? void 0 : _a2.parentNode) === node) {
+      if (((_a3 = child.parentNode) == null ? void 0 : _a3.parentNode) === node) {
         properties[child.tagName.replace(":", "_")] = nodeVal(child);
       }
     }
         yield feature3;
     }
     for (const waypoint of $(node, "wpt")) {
-      const point2 = getPoint(waypoint);
-      if (point2)
-        yield point2;
+      const point = getPoint(waypoint);
+      if (point)
+        yield point;
     }
   }
   function gpx(node) {
     };
   }
   function getPlacemark(node, styleMap, schema, options2) {
-    var _a2;
+    var _a3;
     const { coordTimes, geometries } = getGeometry(node);
     const geometry = geometryListToGeometry(geometries);
     if (!geometry && options2.skipNullGeometry) {
         }
       } : {})
     };
-    if (((_a2 = feature3.properties) == null ? void 0 : _a2.visibility) !== void 0) {
+    if (((_a3 = feature3.properties) == null ? void 0 : _a3.visibility) !== void 0) {
       feature3.properties.visibility = feature3.properties.visibility !== "0";
     }
     const id2 = node.getAttribute("id");
     return null;
   }
   function getGroundOverlay(node, styleMap, schema, options2) {
-    var _a2;
+    var _a3;
     const box = getGroundOverlayBox(node);
     const geometry = (box == null ? void 0 : box.geometry) || null;
     if (!geometry && options2.skipNullGeometry) {
     if (box == null ? void 0 : box.bbox) {
       feature3.bbox = box.bbox;
     }
-    if (((_a2 = feature3.properties) == null ? void 0 : _a2.visibility) !== void 0) {
+    if (((_a3 = feature3.properties) == null ? void 0 : _a3.visibility) !== void 0) {
       feature3.properties.visibility = feature3.properties.visibility !== "0";
     }
     const id2 = node.getAttribute("id");
       ".json"
     ];
     function init2() {
-      if (_initialized)
-        return;
+      if (_initialized) return;
       _geojson = {};
       _enabled = true;
       function over(d3_event) {
       context.container().attr("dropzone", "copy").on("drop.svgData", function(d3_event) {
         d3_event.stopPropagation();
         d3_event.preventDefault();
-        if (!detected.filedrop)
-          return;
+        if (!detected.filedrop) return;
         var f2 = d3_event.dataTransfer.files[0];
         var extension = getExtension(f2.name);
-        if (!supportedFormats.includes(extension))
-          return;
+        if (!supportedFormats.includes(extension)) return;
         drawData.fileList(d3_event.dataTransfer.files);
       }).on("dragenter.svgData", over).on("dragexit.svgData", over).on("dragover.svgData", over);
       _initialized = true;
       layer.style("display", "none");
     }
     function ensureIDs(gj) {
-      if (!gj)
-        return null;
+      if (!gj) return null;
       if (gj.type === "FeatureCollection") {
         for (var i3 = 0; i3 < gj.features.length; i3++) {
           ensureFeatureID(gj.features[i3]);
       return gj;
     }
     function ensureFeatureID(feature3) {
-      if (!feature3)
-        return;
+      if (!feature3) return;
       feature3.__featurehash__ = utilHashcode((0, import_fast_json_stable_stringify.default)(feature3));
       return feature3;
     }
     function getFeatures(gj) {
-      if (!gj)
-        return [];
+      if (!gj) return [];
       if (gj.type === "FeatureCollection") {
         return gj.features;
       } else {
       layer.exit().remove();
       layer = layer.enter().append("g").attr("class", "layer-mapdata").merge(layer);
       var surface = context.surface();
-      if (!surface || surface.empty())
-        return;
+      if (!surface || surface.empty()) return;
       var geoData, polygonData;
       if (_template && vtService) {
         var sourceID = _template;
       }
     }
     function getExtension(fileName) {
-      if (!fileName)
-        return;
+      if (!fileName) return;
       var re3 = /\.(gpx|kml|(geo)?json|png)$/i;
       var match = fileName.toLowerCase().match(re3);
       return match && match.length && match[0];
       return this;
     };
     drawData.showLabels = function(val) {
-      if (!arguments.length)
-        return _showLabels;
+      if (!arguments.length) return _showLabels;
       _showLabels = val;
       return this;
     };
     drawData.enabled = function(val) {
-      if (!arguments.length)
-        return _enabled;
+      if (!arguments.length) return _enabled;
       _enabled = val;
       if (_enabled) {
         showLayer();
       return !!(_template || Object.keys(gj).length);
     };
     drawData.template = function(val, src) {
-      if (!arguments.length)
-        return _template;
+      if (!arguments.length) return _template;
       var osm = context.connection();
       if (osm) {
         var blocklists = osm.imageryBlocklists();
           regex = blocklists[i3];
           fail = regex.test(val);
           tested++;
-          if (fail)
-            break;
+          if (fail) break;
         }
         if (!tested) {
           regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
       return this;
     };
     drawData.geojson = function(gj, src) {
-      if (!arguments.length)
-        return _geojson;
+      if (!arguments.length) return _geojson;
       _template = null;
       _fileList = null;
       _geojson = null;
       return this;
     };
     drawData.fileList = function(fileList) {
-      if (!arguments.length)
-        return _fileList;
+      if (!arguments.length) return _fileList;
       _template = null;
       _geojson = null;
       _src = null;
       _fileList = fileList;
-      if (!fileList || !fileList.length)
-        return this;
+      if (!fileList || !fileList.length) return this;
       var f2 = fileList[0];
       var extension = getExtension(f2.name);
       var reader = new FileReader();
     };
     drawData.fitZoom = function() {
       var features = getFeatures(_geojson);
-      if (!features.length)
-        return;
+      if (!features.length) return;
       var map2 = context.map();
       var viewport = map2.trimmedExtent().polygon();
       var coords = features.reduce(function(coords2, feature3) {
         var geom = feature3.geometry;
-        if (!geom)
-          return coords2;
+        if (!geom) return coords2;
         var c2 = geom.coordinates;
         switch (geom.type) {
           case "Point":
   var _qaService;
   function svgKeepRight(projection2, context, dispatch14) {
     const throttledRedraw = throttle_default(() => dispatch14.call("change"), 1e3);
-    const minZoom4 = 12;
+    const minZoom5 = 12;
     let touchLayer = select_default2(null);
     let drawLayer = select_default2(null);
     let layerVisible = false;
       });
     }
     function updateMarkers() {
-      if (!layerVisible || !_layerEnabled)
-        return;
+      if (!layerVisible || !_layerEnabled) return;
       const service = getService();
       const selectedID = context.selectedErrorID();
       const data = service ? service.getItems(projection2) : [];
       markersEnter.append("path").call(markerPath, "shadow");
       markersEnter.append("use").attr("class", "qaItem-fill").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").attr("xlink:href", "#iD-icon-bolt");
       markers.merge(markersEnter).sort(sortY).classed("selected", (d2) => d2.id === selectedID).attr("transform", getTransform);
-      if (touchLayer.empty())
-        return;
+      if (touchLayer.empty()) return;
       const fillClass = context.getDebug("target") ? "pink " : "nocolor ";
       const targets = touchLayer.selectAll(".qaItem.keepRight").data(data, (d2) => d2.id);
       targets.exit().remove();
       drawLayer.exit().remove();
       drawLayer = drawLayer.enter().append("g").attr("class", "layer-keepRight").style("display", _layerEnabled ? "block" : "none").merge(drawLayer);
       if (_layerEnabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           service.loadIssues(projection2);
           updateMarkers();
       }
     }
     drawKeepRight.enabled = function(val) {
-      if (!arguments.length)
-        return _layerEnabled;
+      if (!arguments.length) return _layerEnabled;
       _layerEnabled = val;
       if (_layerEnabled) {
         layerOn();
     var layer = select_default2(null);
     var _position;
     function init2() {
-      if (svgGeolocate.initialized)
-        return;
+      if (svgGeolocate.initialized) return;
       svgGeolocate.enabled = false;
       svgGeolocate.initialized = true;
     }
       }
     }
     drawLocation.enabled = function(position, enabled) {
-      if (!arguments.length)
-        return svgGeolocate.enabled;
+      if (!arguments.length) return svgGeolocate.enabled;
       _position = position;
       svgGeolocate.enabled = enabled;
       if (svgGeolocate.enabled) {
   }
 
   // modules/svg/labels.js
-  var import_rbush6 = __toESM(require_rbush_min());
   function svgLabels(projection2, context) {
     var path = path_default(projection2);
     var detected = utilDetect();
     var baselineHack = detected.ie || detected.browser.toLowerCase() === "edge" || detected.browser.toLowerCase() === "firefox" && detected.version >= 70;
-    var _rdrawn = new import_rbush6.default();
-    var _rskipped = new import_rbush6.default();
+    var _rdrawn = new RBush();
+    var _rskipped = new RBush();
     var _textWidthCache = {};
     var _entitybboxes = {};
     var labelStack = [
     }
     function textWidth(text, size, elem) {
       var c2 = _textWidthCache[size];
-      if (!c2)
-        c2 = _textWidthCache[size] = {};
+      if (!c2) c2 = _textWidthCache[size] = {};
       if (c2[text]) {
         return c2[text];
       } else if (elem) {
         }
         var preset = geometry === "area" && _mainPresetIndex.match(entity, graph);
         var icon2 = preset && !shouldSkipIcon(preset) && preset.icon;
-        if (!icon2 && !utilDisplayName(entity))
-          continue;
+        if (!icon2 && !utilDisplayName(entity)) continue;
         for (k2 = 0; k2 < labelStack.length; k2++) {
           var matchGeom = labelStack[k2][0];
           var matchKey = labelStack[k2][1];
           var width = name && textWidth(name, fontSize);
           var p2 = null;
           if (geometry === "point" || geometry === "vertex") {
-            if (wireframe)
-              continue;
+            if (wireframe) continue;
             var renderAs = renderNodeAs[entity.id];
-            if (renderAs === "vertex" && zoom < 17)
-              continue;
+            if (renderAs === "vertex" && zoom < 17) continue;
             p2 = getPointLabel(entity, width, fontSize, renderAs);
           } else if (geometry === "line") {
             p2 = getLineLabel(entity, width, fontSize);
           return projection2(node.loc);
         });
         var length2 = geoPathLength(points);
-        if (length2 < width2 + 20)
-          return;
+        if (length2 < width2 + 20) return;
         var lineOffsets = [
           50,
           45,
           var offset = lineOffsets[i4];
           var middle = offset / 100 * length2;
           var start2 = middle - width2 / 2;
-          if (start2 < 0 || start2 + width2 > length2)
-            continue;
+          if (start2 < 0 || start2 + width2 > length2) continue;
           var sub = subpath(points, start2, start2 + width2);
           if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
             continue;
         var centroid = path.centroid(entity2.asGeoJSON(graph));
         var extent = entity2.extent(graph);
         var areaWidth = projection2(extent[1])[0] - projection2(extent[0])[0];
-        if (isNaN(centroid[0]) || areaWidth < 20)
-          return;
+        if (isNaN(centroid[0]) || areaWidth < 20) return;
         var preset2 = _mainPresetIndex.match(entity2, context.graph());
         var picon = preset2 && preset2.icon;
         var iconSize = 17;
   var a = !!s;
   var o = (e3) => e3;
   function l(e3, t2 = o) {
-    if (n2)
-      try {
-        return "function" == typeof __require ? Promise.resolve(t2(__require(e3))) : import(
-          /* webpackIgnore: true */
-          e3
-        ).then(t2);
-      } catch (t3) {
-        console.warn("Couldn't load ".concat(e3));
-      }
+    if (n2) try {
+      return "function" == typeof __require ? Promise.resolve(t2(__require(e3))) : import(
+        /* webpackIgnore: true */
+        e3
+      ).then(t2);
+    } catch (t3) {
+      console.warn("Couldn't load ".concat(e3));
+    }
   }
   var h = e.fetch;
   var u = (e3) => h = e3;
   }
   function m(e3) {
     return "" === (e3 = function(e4) {
-      for (; e4.endsWith("\0"); )
-        e4 = e4.slice(0, -1);
+      for (; e4.endsWith("\0"); ) e4 = e4.slice(0, -1);
       return e4;
     }(e3).trim()) ? void 0 : e3;
   }
       return e3 instanceof this && e3.le === t2 ? e3 : new _I(e3, void 0, void 0, t2);
     }
     constructor(e3, t2 = 0, i3, n3) {
-      if ("boolean" == typeof n3 && (this.le = n3), Array.isArray(e3) && (e3 = new Uint8Array(e3)), 0 === e3)
-        this.byteOffset = 0, this.byteLength = 0;
+      if ("boolean" == typeof n3 && (this.le = n3), Array.isArray(e3) && (e3 = new Uint8Array(e3)), 0 === e3) this.byteOffset = 0, this.byteLength = 0;
       else if (e3 instanceof ArrayBuffer) {
         void 0 === i3 && (i3 = e3.byteLength - t2);
         let n4 = new DataView(e3, t2, i3);
       } else if ("number" == typeof e3) {
         let t3 = new DataView(new ArrayBuffer(e3));
         this._swapDataView(t3);
-      } else
-        g2("Invalid input argument for BufferView: " + e3);
+      } else g2("Invalid input argument for BufferView: " + e3);
     }
     _swapArrayBuffer(e3) {
       this._swapDataView(new DataView(e3));
     }
     getUnicodeString(e3 = 0, t2 = this.byteLength) {
       const i3 = [];
-      for (let n3 = 0; n3 < t2 && e3 + n3 < this.byteLength; n3 += 2)
-        i3.push(this.getUint16(e3 + n3));
+      for (let n3 = 0; n3 < t2 && e3 + n3 < this.byteLength; n3 += 2) i3.push(this.getUint16(e3 + n3));
       return C(i3);
     }
     getInt8(e3) {
   };
   function U(e3, t2, i3) {
     let n3 = new L();
-    for (let [e4, t3] of i3)
-      n3.set(e4, t3);
-    if (Array.isArray(t2))
-      for (let i4 of t2)
-        e3.set(i4, n3);
-    else
-      e3.set(t2, n3);
+    for (let [e4, t3] of i3) n3.set(e4, t3);
+    if (Array.isArray(t2)) for (let i4 of t2) e3.set(i4, n3);
+    else e3.set(t2, n3);
     return n3;
   }
   function F(e3, t2, i3) {
     let n3, s2 = e3.get(t2);
-    for (n3 of i3)
-      s2.set(n3[0], n3[1]);
+    for (n3 of i3) s2.set(n3[0], n3[1]);
   }
   var E = /* @__PURE__ */ new Map();
   var B = /* @__PURE__ */ new Map();
       return this.enabled || this.deps.size > 0;
     }
     constructor(e3, t2, i3, n3) {
-      if (super(), c(this, "enabled", false), c(this, "skip", /* @__PURE__ */ new Set()), c(this, "pick", /* @__PURE__ */ new Set()), c(this, "deps", /* @__PURE__ */ new Set()), c(this, "translateKeys", false), c(this, "translateValues", false), c(this, "reviveValues", false), this.key = e3, this.enabled = t2, this.parse = this.enabled, this.applyInheritables(n3), this.canBeFiltered = H.includes(e3), this.canBeFiltered && (this.dict = E.get(e3)), void 0 !== i3)
-        if (Array.isArray(i3))
-          this.parse = this.enabled = true, this.canBeFiltered && i3.length > 0 && this.translateTagSet(i3, this.pick);
-        else if ("object" == typeof i3) {
-          if (this.enabled = true, this.parse = false !== i3.parse, this.canBeFiltered) {
-            let { pick: e4, skip: t3 } = i3;
-            e4 && e4.length > 0 && this.translateTagSet(e4, this.pick), t3 && t3.length > 0 && this.translateTagSet(t3, this.skip);
-          }
-          this.applyInheritables(i3);
-        } else
-          true === i3 || false === i3 ? this.parse = this.enabled = i3 : g2("Invalid options argument: ".concat(i3));
+      if (super(), c(this, "enabled", false), c(this, "skip", /* @__PURE__ */ new Set()), c(this, "pick", /* @__PURE__ */ new Set()), c(this, "deps", /* @__PURE__ */ new Set()), c(this, "translateKeys", false), c(this, "translateValues", false), c(this, "reviveValues", false), this.key = e3, this.enabled = t2, this.parse = this.enabled, this.applyInheritables(n3), this.canBeFiltered = H.includes(e3), this.canBeFiltered && (this.dict = E.get(e3)), void 0 !== i3) if (Array.isArray(i3)) this.parse = this.enabled = true, this.canBeFiltered && i3.length > 0 && this.translateTagSet(i3, this.pick);
+      else if ("object" == typeof i3) {
+        if (this.enabled = true, this.parse = false !== i3.parse, this.canBeFiltered) {
+          let { pick: e4, skip: t3 } = i3;
+          e4 && e4.length > 0 && this.translateTagSet(e4, this.pick), t3 && t3.length > 0 && this.translateTagSet(t3, this.skip);
+        }
+        this.applyInheritables(i3);
+      } else true === i3 || false === i3 ? this.parse = this.enabled = i3 : g2("Invalid options argument: ".concat(i3));
     }
     applyInheritables(e3) {
       let t2, i3;
-      for (t2 of K)
-        i3 = e3[t2], void 0 !== i3 && (this[t2] = i3);
+      for (t2 of K) i3 = e3[t2], void 0 !== i3 && (this[t2] = i3);
     }
     translateTagSet(e3, t2) {
       if (this.dict) {
         let i3, n3, { tagKeys: s2, tagValues: r2 } = this.dict;
-        for (i3 of e3)
-          "string" == typeof i3 ? (n3 = r2.indexOf(i3), -1 === n3 && (n3 = s2.indexOf(Number(i3))), -1 !== n3 && t2.add(Number(s2[n3]))) : t2.add(i3);
-      } else
-        for (let i3 of e3)
-          t2.add(i3);
+        for (i3 of e3) "string" == typeof i3 ? (n3 = r2.indexOf(i3), -1 === n3 && (n3 = s2.indexOf(Number(i3))), -1 !== n3 && t2.add(Number(s2[n3]))) : t2.add(i3);
+      } else for (let i3 of e3) t2.add(i3);
     }
     finalizeFilters() {
       !this.enabled && this.deps.size > 0 ? (this.enabled = true, ee(this.pick, this.deps)) : this.enabled && this.pick.size > 0 && ee(this.pick, this.deps);
     }
     setupFromUndefined() {
       let e3;
-      for (e3 of G)
-        this[e3] = $2[e3];
-      for (e3 of X)
-        this[e3] = $2[e3];
-      for (e3 of W)
-        this[e3] = $2[e3];
-      for (e3 of j)
-        this[e3] = new Y(e3, $2[e3], void 0, this);
+      for (e3 of G) this[e3] = $2[e3];
+      for (e3 of X) this[e3] = $2[e3];
+      for (e3 of W) this[e3] = $2[e3];
+      for (e3 of j) this[e3] = new Y(e3, $2[e3], void 0, this);
     }
     setupFromTrue() {
       let e3;
-      for (e3 of G)
-        this[e3] = $2[e3];
-      for (e3 of X)
-        this[e3] = $2[e3];
-      for (e3 of W)
-        this[e3] = true;
-      for (e3 of j)
-        this[e3] = new Y(e3, true, void 0, this);
+      for (e3 of G) this[e3] = $2[e3];
+      for (e3 of X) this[e3] = $2[e3];
+      for (e3 of W) this[e3] = true;
+      for (e3 of j) this[e3] = new Y(e3, true, void 0, this);
     }
     setupFromArray(e3) {
       let t2;
-      for (t2 of G)
-        this[t2] = $2[t2];
-      for (t2 of X)
-        this[t2] = $2[t2];
-      for (t2 of W)
-        this[t2] = $2[t2];
-      for (t2 of j)
-        this[t2] = new Y(t2, false, void 0, this);
+      for (t2 of G) this[t2] = $2[t2];
+      for (t2 of X) this[t2] = $2[t2];
+      for (t2 of W) this[t2] = $2[t2];
+      for (t2 of j) this[t2] = new Y(t2, false, void 0, this);
       this.setupGlobalFilters(e3, void 0, H);
     }
     setupFromObject(e3) {
       let t2;
-      for (t2 of (H.ifd0 = H.ifd0 || H.image, H.ifd1 = H.ifd1 || H.thumbnail, Object.assign(this, e3), G))
-        this[t2] = Z(e3[t2], $2[t2]);
-      for (t2 of X)
-        this[t2] = Z(e3[t2], $2[t2]);
-      for (t2 of W)
-        this[t2] = Z(e3[t2], $2[t2]);
-      for (t2 of z)
-        this[t2] = new Y(t2, $2[t2], e3[t2], this);
-      for (t2 of H)
-        this[t2] = new Y(t2, $2[t2], e3[t2], this.tiff);
+      for (t2 of (H.ifd0 = H.ifd0 || H.image, H.ifd1 = H.ifd1 || H.thumbnail, Object.assign(this, e3), G)) this[t2] = Z(e3[t2], $2[t2]);
+      for (t2 of X) this[t2] = Z(e3[t2], $2[t2]);
+      for (t2 of W) this[t2] = Z(e3[t2], $2[t2]);
+      for (t2 of z) this[t2] = new Y(t2, $2[t2], e3[t2], this);
+      for (t2 of H) this[t2] = new Y(t2, $2[t2], e3[t2], this.tiff);
       this.setupGlobalFilters(e3.pick, e3.skip, H, j), true === e3.tiff ? this.batchEnableWithBool(H, true) : false === e3.tiff ? this.batchEnableWithUserValue(H, e3) : Array.isArray(e3.tiff) ? this.setupGlobalFilters(e3.tiff, void 0, H) : "object" == typeof e3.tiff && this.setupGlobalFilters(e3.tiff.pick, e3.tiff.skip, H);
     }
     batchEnableWithBool(e3, t2) {
-      for (let i3 of e3)
-        this[i3].enabled = t2;
+      for (let i3 of e3) this[i3].enabled = t2;
     }
     batchEnableWithUserValue(e3, t2) {
       for (let i3 of e3) {
     }
     setupGlobalFilters(e3, t2, i3, n3 = i3) {
       if (e3 && e3.length) {
-        for (let e4 of n3)
-          this[e4].enabled = false;
+        for (let e4 of n3) this[e4].enabled = false;
         let t3 = Q(e3, i3);
-        for (let [e4, i4] of t3)
-          ee(this[e4].pick, i4), this[e4].enabled = true;
+        for (let [e4, i4] of t3) ee(this[e4].pick, i4), this[e4].enabled = true;
       } else if (t2 && t2.length) {
         let e4 = Q(t2, i3);
-        for (let [t3, i4] of e4)
-          ee(this[t3].skip, i4);
+        for (let [t3, i4] of e4) ee(this[t3].skip, i4);
       }
     }
     filterNestedSegmentTags() {
     traverseTiffDependencyTree() {
       let { ifd0: e3, exif: t2, gps: i3, interop: n3 } = this;
       n3.needed && (t2.deps.add(40965), e3.deps.add(40965)), t2.needed && e3.deps.add(34665), i3.needed && e3.deps.add(34853), this.tiff.enabled = H.some((e4) => true === this[e4].enabled) || this.makerNote || this.userComment;
-      for (let e4 of H)
-        this[e4].finalizeFilters();
+      for (let e4 of H) this[e4].finalizeFilters();
     }
     get onlyTiff() {
       return !V.map((e3) => this[e3].enabled).some((e3) => true === e3) && this.tiff.enabled;
     }
     checkLoadedPlugins() {
-      for (let e3 of z)
-        this[e3].enabled && !T.has(e3) && P("segment parser", e3);
+      for (let e3 of z) this[e3].enabled && !T.has(e3) && P("segment parser", e3);
     }
   };
   function Q(e3, t2) {
     let i3, n3, s2, r2, a2 = [];
     for (s2 of t2) {
-      for (r2 of (i3 = E.get(s2), n3 = [], i3))
-        (e3.includes(r2[0]) || e3.includes(r2[1])) && n3.push(r2[0]);
+      for (r2 of (i3 = E.get(s2), n3 = [], i3)) (e3.includes(r2[0]) || e3.includes(r2[1])) && n3.push(r2[0]);
       n3.length && a2.push([s2, n3]);
     }
     return a2;
     return void 0 !== e3 ? e3 : void 0 !== t2 ? t2 : void 0;
   }
   function ee(e3, t2) {
-    for (let i3 of t2)
-      e3.add(i3);
+    for (let i3 of t2) e3.add(i3);
   }
   c(q, "default", $2);
   var te = class {
       this.file = await D(e3, this.options);
     }
     setup() {
-      if (this.fileParser)
-        return;
+      if (this.fileParser) return;
       let { file: e3 } = this, t2 = e3.getUint16(0);
-      for (let [i3, n3] of w)
-        if (n3.canHandle(e3, t2))
-          return this.fileParser = new n3(this.options, this.file, this.parsers), e3[i3] = true;
+      for (let [i3, n3] of w) if (n3.canHandle(e3, t2)) return this.fileParser = new n3(this.options, this.file, this.parsers), e3[i3] = true;
       this.file.close && this.file.close(), g2("Unknown file format");
     }
     async parse() {
       this.setup();
       let { options: e3, file: t2 } = this, i3 = T.get("tiff", e3);
       var n3;
-      if (t2.tiff ? n3 = { start: 0, type: "tiff" } : t2.jpeg && (n3 = await this.fileParser.getOrFindSegment("tiff")), void 0 === n3)
-        return;
+      if (t2.tiff ? n3 = { start: 0, type: "tiff" } : t2.jpeg && (n3 = await this.fileParser.getOrFindSegment("tiff")), void 0 === n3) return;
       let s2 = await this.fileParser.ensureSegmentChunk(n3), r2 = this.parsers.tiff = new i3(s2, e3, t2), a2 = await r2.extractThumbnail();
       return t2.close && t2.close(), a2;
     }
     constructor(e3, t2, i3) {
       c(this, "errors", []), c(this, "ensureSegmentChunk", async (e4) => {
         let t3 = e4.start, i4 = e4.size || 65536;
-        if (this.file.chunked)
-          if (this.file.available(t3, i4))
-            e4.chunk = this.file.subarray(t3, i4);
-          else
-            try {
-              e4.chunk = await this.file.readChunk(t3, i4);
-            } catch (t4) {
-              g2("Couldn't read segment: ".concat(JSON.stringify(e4), ". ").concat(t4.message));
-            }
-        else
-          this.file.byteLength > t3 + i4 ? e4.chunk = this.file.subarray(t3, i4) : void 0 === e4.size ? e4.chunk = this.file.subarray(t3) : g2("Segment unreachable: " + JSON.stringify(e4));
+        if (this.file.chunked) if (this.file.available(t3, i4)) e4.chunk = this.file.subarray(t3, i4);
+        else try {
+          e4.chunk = await this.file.readChunk(t3, i4);
+        } catch (t4) {
+          g2("Couldn't read segment: ".concat(JSON.stringify(e4), ". ").concat(t4.message));
+        }
+        else this.file.byteLength > t3 + i4 ? e4.chunk = this.file.subarray(t3, i4) : void 0 === e4.size ? e4.chunk = this.file.subarray(t3) : g2("Segment unreachable: " + JSON.stringify(e4));
         return e4.chunk;
       }), this.extendOptions && this.extendOptions(e3), this.options = e3, this.file = t2, this.parsers = i3;
     }
     }
     constructor(e3, t2 = {}, i3) {
       c(this, "errors", []), c(this, "raw", /* @__PURE__ */ new Map()), c(this, "handleError", (e4) => {
-        if (!this.options.silentErrors)
-          throw e4;
+        if (!this.options.silentErrors) throw e4;
         this.errors.push(e4.message);
       }), this.chunk = this.normalizeInput(e3), this.file = i3, this.type = this.constructor.type, this.globalOptions = this.options = t2, this.localOptions = t2[this.type], this.canTranslate = this.localOptions && this.localOptions.translate;
     }
     }
     translateBlock(e3, t2) {
       let i3 = N.get(t2), n3 = B.get(t2), s2 = E.get(t2), r2 = this.options[t2], a2 = r2.reviveValues && !!i3, o2 = r2.translateValues && !!n3, l2 = r2.translateKeys && !!s2, h2 = {};
-      for (let [t3, r3] of e3)
-        a2 && i3.has(t3) ? r3 = i3.get(t3)(r3) : o2 && n3.has(t3) && (r3 = this.translateValue(r3, n3.get(t3))), l2 && s2.has(t3) && (t3 = s2.get(t3) || t3), h2[t3] = r3;
+      for (let [t3, r3] of e3) a2 && i3.has(t3) ? r3 = i3.get(t3)(r3) : o2 && n3.has(t3) && (r3 = this.translateValue(r3, n3.get(t3))), l2 && s2.has(t3) && (t3 = s2.get(t3) || t3), h2[t3] = r3;
       return h2;
     }
     translateValue(e3, t2) {
       this.assignObjectToOutput(e3, this.constructor.type, t2);
     }
     assignObjectToOutput(e3, t2, i3) {
-      if (this.globalOptions.mergeOutput)
-        return Object.assign(e3, i3);
+      if (this.globalOptions.mergeOutput) return Object.assign(e3, i3);
       e3[t2] ? Object.assign(e3[t2], i3) : e3[t2] = i3;
     }
   };
     return e3 >= 224 && e3 <= 239;
   }
   function le(e3, t2, i3) {
-    for (let [n3, s2] of T)
-      if (s2.canHandle(e3, t2, i3))
-        return n3;
+    for (let [n3, s2] of T) if (s2.canHandle(e3, t2, i3)) return n3;
   }
   var he = class extends se {
     constructor(...e3) {
         let t3 = false;
         for (; r2.size > 0 && !t3 && (i3.canReadNextChunk || this.unfinishedMultiSegment); ) {
           let { nextChunkOffset: n4 } = i3, s3 = this.appSegments.some((e4) => !this.file.available(e4.offset || e4.start, e4.length || e4.size));
-          if (t3 = e3 > n4 && !s3 ? !await i3.readNextChunk(e3) : !await i3.readNextChunk(n4), void 0 === (e3 = this.findAppSegmentsInRange(e3, i3.byteLength)))
-            return;
+          if (t3 = e3 > n4 && !s3 ? !await i3.readNextChunk(e3) : !await i3.readNextChunk(n4), void 0 === (e3 = this.findAppSegmentsInRange(e3, i3.byteLength))) return;
         }
       }
     }
     findAppSegmentsInRange(e3, t2) {
       t2 -= 2;
       let i3, n3, s2, r2, a2, o2, { file: l2, findAll: h2, wanted: u2, remaining: c2, options: f2 } = this;
-      for (; e3 < t2; e3++)
-        if (255 === l2.getUint8(e3)) {
-          if (i3 = l2.getUint8(e3 + 1), oe(i3)) {
-            if (n3 = l2.getUint16(e3 + 2), s2 = le(l2, e3, n3), s2 && u2.has(s2) && (r2 = T.get(s2), a2 = r2.findPosition(l2, e3), o2 = f2[s2], a2.type = s2, this.appSegments.push(a2), !h2 && (r2.multiSegment && o2.multiSegment ? (this.unfinishedMultiSegment = a2.chunkNumber < a2.chunkCount, this.unfinishedMultiSegment || c2.delete(s2)) : c2.delete(s2), 0 === c2.size)))
-              break;
-            f2.recordUnknownSegments && (a2 = re2.findPosition(l2, e3), a2.marker = i3, this.unknownSegments.push(a2)), e3 += n3 + 1;
-          } else if (ae(i3)) {
-            if (n3 = l2.getUint16(e3 + 2), 218 === i3 && false !== f2.stopAfterSos)
-              return;
-            f2.recordJpegSegments && this.jpegSegments.push({ offset: e3, length: n3, marker: i3 }), e3 += n3 + 1;
-          }
+      for (; e3 < t2; e3++) if (255 === l2.getUint8(e3)) {
+        if (i3 = l2.getUint8(e3 + 1), oe(i3)) {
+          if (n3 = l2.getUint16(e3 + 2), s2 = le(l2, e3, n3), s2 && u2.has(s2) && (r2 = T.get(s2), a2 = r2.findPosition(l2, e3), o2 = f2[s2], a2.type = s2, this.appSegments.push(a2), !h2 && (r2.multiSegment && o2.multiSegment ? (this.unfinishedMultiSegment = a2.chunkNumber < a2.chunkCount, this.unfinishedMultiSegment || c2.delete(s2)) : c2.delete(s2), 0 === c2.size))) break;
+          f2.recordUnknownSegments && (a2 = re2.findPosition(l2, e3), a2.marker = i3, this.unknownSegments.push(a2)), e3 += n3 + 1;
+        } else if (ae(i3)) {
+          if (n3 = l2.getUint16(e3 + 2), 218 === i3 && false !== f2.stopAfterSos) return;
+          f2.recordJpegSegments && this.jpegSegments.push({ offset: e3, length: n3, marker: i3 }), e3 += n3 + 1;
         }
+      }
       return e3;
     }
     mergeMultiSegments() {
-      if (!this.appSegments.some((e4) => e4.multiSegment))
-        return;
+      if (!this.appSegments.some((e4) => e4.multiSegment)) return;
       let e3 = function(e4, t2) {
         let i3, n3, s2, r2 = /* @__PURE__ */ new Map();
-        for (let a2 = 0; a2 < e4.length; a2++)
-          i3 = e4[a2], n3 = i3[t2], r2.has(n3) ? s2 = r2.get(n3) : r2.set(n3, s2 = []), s2.push(i3);
+        for (let a2 = 0; a2 < e4.length; a2++) i3 = e4[a2], n3 = i3[t2], r2.has(n3) ? s2 = r2.get(n3) : r2.set(n3, s2 = []), s2.push(i3);
         return Array.from(r2);
       }(this.appSegments, "type");
       this.mergedAppSegments = e3.map(([e4, t2]) => {
       for (let l2 = 0; l2 < o2; l2++) {
         let o3 = this.chunk.getUint16(e3);
         if (r2) {
-          if (n3.has(o3) && (i3.set(o3, this.parseTag(e3, o3, t2)), n3.delete(o3), 0 === n3.size))
-            break;
-        } else
-          !a2 && s2.has(o3) || i3.set(o3, this.parseTag(e3, o3, t2));
+          if (n3.has(o3) && (i3.set(o3, this.parseTag(e3, o3, t2)), n3.delete(o3), 0 === n3.size)) break;
+        } else !a2 && s2.has(o3) || i3.set(o3, this.parseTag(e3, o3, t2));
         e3 += 12;
       }
       return i3;
     }
     parseTag(e3, t2, i3) {
       let { chunk: n3 } = this, s2 = n3.getUint16(e3 + 2), r2 = n3.getUint32(e3 + 4), a2 = ue[s2];
-      if (a2 * r2 <= 4 ? e3 += 8 : e3 = n3.getUint32(e3 + 8), (s2 < 1 || s2 > 13) && g2("Invalid TIFF value type. block: ".concat(i3.toUpperCase(), ", tag: ").concat(t2.toString(16), ", type: ").concat(s2, ", offset ").concat(e3)), e3 > n3.byteLength && g2("Invalid TIFF value offset. block: ".concat(i3.toUpperCase(), ", tag: ").concat(t2.toString(16), ", type: ").concat(s2, ", offset ").concat(e3, " is outside of chunk size ").concat(n3.byteLength)), 1 === s2)
-        return n3.getUint8Array(e3, r2);
-      if (2 === s2)
-        return m(n3.getString(e3, r2));
-      if (7 === s2)
-        return n3.getUint8Array(e3, r2);
-      if (1 === r2)
-        return this.parseTagValue(s2, e3);
+      if (a2 * r2 <= 4 ? e3 += 8 : e3 = n3.getUint32(e3 + 8), (s2 < 1 || s2 > 13) && g2("Invalid TIFF value type. block: ".concat(i3.toUpperCase(), ", tag: ").concat(t2.toString(16), ", type: ").concat(s2, ", offset ").concat(e3)), e3 > n3.byteLength && g2("Invalid TIFF value offset. block: ".concat(i3.toUpperCase(), ", tag: ").concat(t2.toString(16), ", type: ").concat(s2, ", offset ").concat(e3, " is outside of chunk size ").concat(n3.byteLength)), 1 === s2) return n3.getUint8Array(e3, r2);
+      if (2 === s2) return m(n3.getString(e3, r2));
+      if (7 === s2) return n3.getUint8Array(e3, r2);
+      if (1 === r2) return this.parseTagValue(s2, e3);
       {
         let t3 = new (function(e4) {
           switch (e4) {
               return Array;
           }
         }(s2))(r2), i4 = a2;
-        for (let n4 = 0; n4 < r2; n4++)
-          t3[n4] = this.parseTagValue(s2, e3), e3 += i4;
+        for (let n4 = 0; n4 < r2; n4++) t3[n4] = this.parseTagValue(s2, e3), e3 += i4;
         return t3;
       }
     }
       return this[t2] = i3, this.parseTags(e3, t2, i3), i3;
     }
     async parseIfd0Block() {
-      if (this.ifd0)
-        return;
+      if (this.ifd0) return;
       let { file: e3 } = this;
       this.findIfd0Offset(), this.ifd0Offset < 8 && g2("Malformed EXIF data"), !e3.chunked && this.ifd0Offset > e3.byteLength && g2("IFD0 offset points to outside of file.\nthis.ifd0Offset: ".concat(this.ifd0Offset, ", file.byteLength: ").concat(e3.byteLength)), e3.tiff && await e3.ensureChunk(this.ifd0Offset, S(this.options));
       let t2 = this.parseBlock(this.ifd0Offset, "ifd0");
       return 0 !== t2.size ? (this.exifOffset = t2.get(34665), this.interopOffset = t2.get(40965), this.gpsOffset = t2.get(34853), this.xmp = t2.get(700), this.iptc = t2.get(33723), this.icc = t2.get(34675), this.options.sanitize && (t2.delete(34665), t2.delete(40965), t2.delete(34853), t2.delete(700), t2.delete(33723), t2.delete(34675)), t2) : void 0;
     }
     async parseExifBlock() {
-      if (this.exif)
-        return;
-      if (this.ifd0 || await this.parseIfd0Block(), void 0 === this.exifOffset)
-        return;
+      if (this.exif) return;
+      if (this.ifd0 || await this.parseIfd0Block(), void 0 === this.exifOffset) return;
       this.file.tiff && await this.file.ensureChunk(this.exifOffset, S(this.options));
       let e3 = this.parseBlock(this.exifOffset, "exif");
       return this.interopOffset || (this.interopOffset = e3.get(40965)), this.makerNote = e3.get(37500), this.userComment = e3.get(37510), this.options.sanitize && (e3.delete(40965), e3.delete(37500), e3.delete(37510)), this.unpack(e3, 41728), this.unpack(e3, 41729), e3;
       i3 && 1 === i3.length && e3.set(t2, i3[0]);
     }
     async parseGpsBlock() {
-      if (this.gps)
-        return;
-      if (this.ifd0 || await this.parseIfd0Block(), void 0 === this.gpsOffset)
-        return;
+      if (this.gps) return;
+      if (this.ifd0 || await this.parseIfd0Block(), void 0 === this.gpsOffset) return;
       let e3 = this.parseBlock(this.gpsOffset, "gps");
       return e3 && e3.has(2) && e3.has(4) && (e3.set("latitude", de(...e3.get(2), e3.get(1))), e3.set("longitude", de(...e3.get(4), e3.get(3)))), e3;
     }
     async parseInteropBlock() {
-      if (!this.interop && (this.ifd0 || await this.parseIfd0Block(), void 0 !== this.interopOffset || this.exif || await this.parseExifBlock(), void 0 !== this.interopOffset))
-        return this.parseBlock(this.interopOffset, "interop");
+      if (!this.interop && (this.ifd0 || await this.parseIfd0Block(), void 0 !== this.interopOffset || this.exif || await this.parseExifBlock(), void 0 !== this.interopOffset)) return this.parseBlock(this.interopOffset, "interop");
     }
     async parseThumbnailBlock(e3 = false) {
-      if (!this.ifd1 && !this.ifd1Parsed && (!this.options.mergeOutput || e3))
-        return this.findIfd1Offset(), this.ifd1Offset > 0 && (this.parseBlock(this.ifd1Offset, "ifd1"), this.ifd1Parsed = true), this.ifd1;
+      if (!this.ifd1 && !this.ifd1Parsed && (!this.options.mergeOutput || e3)) return this.findIfd1Offset(), this.ifd1Offset > 0 && (this.parseBlock(this.ifd1Offset, "ifd1"), this.ifd1Parsed = true), this.ifd1;
     }
     async extractThumbnail() {
-      if (this.headerParsed || this.parseHeader(), this.ifd1Parsed || await this.parseThumbnailBlock(true), void 0 === this.ifd1)
-        return;
+      if (this.headerParsed || this.parseHeader(), this.ifd1Parsed || await this.parseThumbnailBlock(true), void 0 === this.ifd1) return;
       let e3 = this.ifd1.get(513), t2 = this.ifd1.get(514);
       return this.chunk.getUint8Array(e3, t2);
     }
     }
     createOutput() {
       let e3, t2, i3, n3 = {};
-      for (t2 of H)
-        if (e3 = this[t2], !p(e3))
-          if (i3 = this.canTranslate ? this.translateBlock(e3, t2) : Object.fromEntries(e3), this.options.mergeOutput) {
-            if ("ifd1" === t2)
-              continue;
-            Object.assign(n3, i3);
-          } else
-            n3[t2] = i3;
+      for (t2 of H) if (e3 = this[t2], !p(e3)) if (i3 = this.canTranslate ? this.translateBlock(e3, t2) : Object.fromEntries(e3), this.options.mergeOutput) {
+        if ("ifd1" === t2) continue;
+        Object.assign(n3, i3);
+      } else n3[t2] = i3;
       return this.makerNote && (n3.makerNote = this.makerNote), this.userComment && (n3.userComment = this.userComment), n3;
     }
     assignToOutput(e3, t2) {
-      if (this.globalOptions.mergeOutput)
-        Object.assign(e3, t2);
-      else
-        for (let [i3, n3] of Object.entries(t2))
-          this.assignObjectToOutput(e3, i3, n3);
+      if (this.globalOptions.mergeOutput) Object.assign(e3, t2);
+      else for (let [i3, n3] of Object.entries(t2)) this.assignObjectToOutput(e3, i3, n3);
     }
   };
   function de(e3, t2, i3, n3) {
     let t2 = new te(Ie);
     await t2.read(e3);
     let i3 = await t2.parse();
-    if (i3 && i3.ifd0)
-      return i3.ifd0[274];
+    if (i3 && i3.ifd0) return i3.ifd0[274];
   }
   var ke = Object.freeze({ 1: { dimensionSwapped: false, scaleX: 1, scaleY: 1, deg: 0, rad: 0 }, 2: { dimensionSwapped: false, scaleX: -1, scaleY: 1, deg: 0, rad: 0 }, 3: { dimensionSwapped: false, scaleX: 1, scaleY: 1, deg: 180, rad: 180 * Math.PI / 180 }, 4: { dimensionSwapped: false, scaleX: -1, scaleY: 1, deg: 180, rad: 180 * Math.PI / 180 }, 5: { dimensionSwapped: true, scaleX: 1, scaleY: -1, deg: 90, rad: 90 * Math.PI / 180 }, 6: { dimensionSwapped: true, scaleX: 1, scaleY: 1, deg: 90, rad: 90 * Math.PI / 180 }, 7: { dimensionSwapped: true, scaleX: 1, scaleY: -1, deg: 270, rad: 270 * Math.PI / 180 }, 8: { dimensionSwapped: true, scaleX: 1, scaleY: 1, deg: 270, rad: 270 * Math.PI / 180 } });
   var we = true;
         e3 = Math.min(e3, ...s2.map((e4) => e4.offset)), n3 = Math.max(n3, ...s2.map((e4) => e4.end)), t2 = n3 - e3;
         let i4 = s2.shift();
         i4.offset = e3, i4.length = t2, i4.end = n3, this.list = this.list.filter((e4) => !s2.includes(e4));
-      } else
-        this.list.push({ offset: e3, length: t2, end: n3 });
+      } else this.list.push({ offset: e3, length: t2, end: n3 });
     }
     available(e3, t2) {
       let i3 = e3 + t2;
       this.chunked = true, await this.readChunk(0, this.options.firstChunkSize);
     }
     async readNextChunk(e3 = this.nextChunkOffset) {
-      if (this.fullyRead)
-        return this.chunksRead++, false;
+      if (this.fullyRead) return this.chunksRead++, false;
       let t2 = this.options.chunkSize, i3 = await this.readChunk(e3, t2);
       return !!i3 && i3.byteLength === t2;
     }
     async readChunk(e3, t2) {
-      if (this.chunksRead++, 0 !== (t2 = this.safeWrapAddress(e3, t2)))
-        return this._readChunk(e3, t2);
+      if (this.chunksRead++, 0 !== (t2 = this.safeWrapAddress(e3, t2))) return this._readChunk(e3, t2);
     }
     safeWrapAddress(e3, t2) {
       return void 0 !== this.size && e3 + t2 > this.size ? Math.max(0, this.size - e3) : t2;
     }
     get nextChunkOffset() {
-      if (0 !== this.ranges.list.length)
-        return this.ranges.list[0].length;
+      if (0 !== this.ranges.list.length) return this.ranges.list[0].length;
     }
     get canReadNextChunk() {
       return this.chunksRead < this.options.chunkLimit;
       let i3 = t2 ? e3 + t2 - 1 : void 0, n3 = this.options.httpHeaders || {};
       (e3 || i3) && (n3.range = "bytes=".concat([e3, i3].join("-")));
       let s2 = await h(this.input, { headers: n3 }), r2 = await s2.arrayBuffer(), a2 = r2.byteLength;
-      if (416 !== s2.status)
-        return a2 !== t2 && (this.size = e3 + a2), this.set(r2, e3, true);
+      if (416 !== s2.status) return a2 !== t2 && (this.size = e3 + a2), this.set(r2, e3, true);
     }
   });
   I.prototype.getUint64 = function(e3) {
       let t2 = [];
       for (; e3 < this.file.byteLength - 4; ) {
         let i3 = this.parseBoxHead(e3);
-        if (t2.push(i3), 0 === i3.length)
-          break;
+        if (t2.push(i3), 0 === i3.length) break;
         e3 += i3.length;
       }
       return t2;
       return 1 === t2 && (t2 = this.file.getUint64(e3 + 8), n3 += 8), { offset: e3, length: t2, kind: i3, start: n3 };
     }
     parseBoxFullHead(e3) {
-      if (void 0 !== e3.version)
-        return;
+      if (void 0 !== e3.version) return;
       let t2 = this.file.getUint32(e3.start);
       e3.version = t2 >> 24, e3.start += 4;
     }
   };
   var Le = class extends Re {
     static canHandle(e3, t2) {
-      if (0 !== t2)
-        return false;
+      if (0 !== t2) return false;
       let i3 = e3.getUint16(2);
-      if (i3 > 50)
-        return false;
+      if (i3 > 50) return false;
       let n3 = 16, s2 = [];
-      for (; n3 < i3; )
-        s2.push(e3.getString(n3, 4)), n3 += 4;
+      for (; n3 < i3; ) s2.push(e3.getString(n3, 4)), n3 += 4;
       return s2.includes(this.type);
     }
     async parse() {
       let e3 = this.file.getUint32(0), t2 = this.parseBoxHead(e3);
-      for (; "meta" !== t2.kind; )
-        e3 += t2.length, await this.file.ensureChunk(e3, 16), t2 = this.parseBoxHead(e3);
+      for (; "meta" !== t2.kind; ) e3 += t2.length, await this.file.ensureChunk(e3, 16), t2 = this.parseBoxHead(e3);
       await this.file.ensureChunk(t2.offset, t2.length), this.parseBoxFullHead(t2), this.parseSubBoxes(t2), this.options.icc.enabled && await this.findIcc(t2), this.options.tiff.enabled && await this.findExif(t2);
     }
     async registerSegment(e3, t2, i3) {
     }
     async findIcc(e3) {
       let t2 = this.findBox(e3, "iprp");
-      if (void 0 === t2)
-        return;
+      if (void 0 === t2) return;
       let i3 = this.findBox(t2, "ipco");
-      if (void 0 === i3)
-        return;
+      if (void 0 === i3) return;
       let n3 = this.findBox(i3, "colr");
       void 0 !== n3 && await this.registerSegment("icc", n3.offset + 12, n3.length);
     }
     async findExif(e3) {
       let t2 = this.findBox(e3, "iinf");
-      if (void 0 === t2)
-        return;
+      if (void 0 === t2) return;
       let i3 = this.findBox(e3, "iloc");
-      if (void 0 === i3)
-        return;
+      if (void 0 === i3) return;
       let n3 = this.findExifLocIdInIinf(t2), s2 = this.findExtentInIloc(i3, n3);
-      if (void 0 === s2)
-        return;
+      if (void 0 === s2) return;
       let [r2, a2] = s2;
       await this.file.ensureChunk(r2, a2);
       let o2 = 4 + this.file.getUint32(r2);
       this.parseBoxFullHead(e3);
       let t2, i3, n3, s2, r2 = e3.start, a2 = this.file.getUint16(r2);
       for (r2 += 2; a2--; ) {
-        if (t2 = this.parseBoxHead(r2), this.parseBoxFullHead(t2), i3 = t2.start, t2.version >= 2 && (n3 = 3 === t2.version ? 4 : 2, s2 = this.file.getString(i3 + n3 + 2, 4), "Exif" === s2))
-          return this.file.getUintBytes(i3, n3);
+        if (t2 = this.parseBoxHead(r2), this.parseBoxFullHead(t2), i3 = t2.start, t2.version >= 2 && (n3 = 3 === t2.version ? 4 : 2, s2 = this.file.getString(i3 + n3 + 2, 4), "Exif" === s2)) return this.file.getUintBytes(i3, n3);
         r2 += t2.length;
       }
     }
         let e4 = this.file.getUintBytes(i3, o2);
         i3 += o2 + l2 + 2 + r2;
         let u3 = this.file.getUint16(i3);
-        if (i3 += 2, e4 === t2)
-          return u3 > 1 && console.warn("ILOC box has more than one extent but we're only processing one\nPlease create an issue at https://github.com/MikeKovarik/exifr with this file"), [this.file.getUintBytes(i3 + a2, n3), this.file.getUintBytes(i3 + a2 + n3, s2)];
+        if (i3 += 2, e4 === t2) return u3 > 1 && console.warn("ILOC box has more than one extent but we're only processing one\nPlease create an issue at https://github.com/MikeKovarik/exifr with this file"), [this.file.getUintBytes(i3 + a2, n3), this.file.getUintBytes(i3 + a2 + n3, s2)];
         i3 += u3 * h2;
       }
     }
     }
   }
   function He(e3) {
-    if ("string" == typeof e3)
-      return e3;
+    if ("string" == typeof e3) return e3;
     let t2 = [];
-    if (0 === e3[1] && 0 === e3[e3.length - 1])
-      for (let i3 = 0; i3 < e3.length; i3 += 2)
-        t2.push(je(e3[i3 + 1], e3[i3]));
-    else
-      for (let i3 = 0; i3 < e3.length; i3 += 2)
-        t2.push(je(e3[i3], e3[i3 + 1]));
+    if (0 === e3[1] && 0 === e3[e3.length - 1]) for (let i3 = 0; i3 < e3.length; i3 += 2) t2.push(je(e3[i3 + 1], e3[i3]));
+    else for (let i3 = 0; i3 < e3.length; i3 += 2) t2.push(je(e3[i3], e3[i3 + 1]));
     return m(String.fromCodePoint(...t2));
   }
   function je(e3, t2) {
       return "string" == typeof e3 ? e3 : I.from(e3).getString();
     }
     parse(e3 = this.chunk) {
-      if (!this.localOptions.parse)
-        return e3;
+      if (!this.localOptions.parse) return e3;
       e3 = function(e4) {
         let t3 = {}, i4 = {};
-        for (let e6 of Ze)
-          t3[e6] = [], i4[e6] = 0;
+        for (let e6 of Ze) t3[e6] = [], i4[e6] = 0;
         return e4.replace(et, (e6, n4, s2) => {
           if ("<" === n4) {
             let n5 = ++i4[s2];
       let t2 = Xe.findAll(e3, "rdf", "Description");
       0 === t2.length && t2.push(new Xe("rdf", "Description", void 0, e3));
       let i3, n3 = {};
-      for (let e4 of t2)
-        for (let t3 of e4.properties)
-          i3 = Je(t3.ns, n3), _e(t3, i3);
+      for (let e4 of t2) for (let t3 of e4.properties) i3 = Je(t3.ns, n3), _e(t3, i3);
       return function(e4) {
         let t3;
-        for (let i4 in e4)
-          t3 = e4[i4] = f(e4[i4]), void 0 === t3 && delete e4[i4];
+        for (let i4 in e4) t3 = e4[i4] = f(e4[i4]), void 0 === t3 && delete e4[i4];
         return f(e4);
       }(n3);
     }
     assignToOutput(e3, t2) {
-      if (this.localOptions.parse)
-        for (let [i3, n3] of Object.entries(t2))
-          switch (i3) {
-            case "tiff":
-              this.assignObjectToOutput(e3, "ifd0", n3);
-              break;
-            case "exif":
-              this.assignObjectToOutput(e3, "exif", n3);
-              break;
-            case "xmlns":
-              break;
-            default:
-              this.assignObjectToOutput(e3, i3, n3);
-          }
-      else
-        e3.xmp = t2;
+      if (this.localOptions.parse) for (let [i3, n3] of Object.entries(t2)) switch (i3) {
+        case "tiff":
+          this.assignObjectToOutput(e3, "ifd0", n3);
+          break;
+        case "exif":
+          this.assignObjectToOutput(e3, "exif", n3);
+          break;
+        case "xmlns":
+          break;
+        default:
+          this.assignObjectToOutput(e3, i3, n3);
+      }
+      else e3.xmp = t2;
     }
   };
   c(We, "type", "xmp"), c(We, "multiSegment", true), T.set("xmp", We);
       if (void 0 !== t2 || void 0 !== i3) {
         t2 = t2 || "[\\w\\d-]+", i3 = i3 || "[\\w\\d-]+";
         var n3 = new RegExp("<(".concat(t2, "):(").concat(i3, ")(#\\d+)?((\\s+?[\\w\\d-:]+=(\"[^\"]*\"|'[^']*'))*\\s*)(\\/>|>([\\s\\S]*?)<\\/\\1:\\2\\3>)"), "gm");
-      } else
-        n3 = /<([\w\d-]+):([\w\d-]+)(#\d+)?((\s+?[\w\d-:]+=("[^"]*"|'[^']*'))*\s*)(\/>|>([\s\S]*?)<\/\1:\2\3>)/gm;
+      } else n3 = /<([\w\d-]+):([\w\d-]+)(#\d+)?((\s+?[\w\d-:]+=("[^"]*"|'[^']*'))*\s*)(\/>|>([\s\S]*?)<\/\1:\2\3>)/gm;
       return qe(e3, n3).map(_Xe.unpackMatch);
     }
     static unpackMatch(e3) {
       return "rdf" === this.ns && "li" === this.name;
     }
     serialize() {
-      if (0 === this.properties.length && void 0 === this.value)
-        return;
-      if (this.isPrimitive)
-        return this.value;
-      if (this.isListContainer)
-        return this.children[0].serialize();
-      if (this.isList)
-        return $e(this.children.map(Ye));
-      if (this.isListItem && 1 === this.children.length && 0 === this.attrs.length)
-        return this.children[0].serialize();
+      if (0 === this.properties.length && void 0 === this.value) return;
+      if (this.isPrimitive) return this.value;
+      if (this.isListContainer) return this.children[0].serialize();
+      if (this.isList) return $e(this.children.map(Ye));
+      if (this.isListItem && 1 === this.children.length && 0 === this.attrs.length) return this.children[0].serialize();
       let e3 = {};
-      for (let t2 of this.properties)
-        _e(t2, e3);
+      for (let t2 of this.properties) _e(t2, e3);
       return void 0 !== this.value && (e3.value = this.value), f(e3);
     }
   };
   var Je = (e3, t2) => t2[e3] ? t2[e3] : t2[e3] = {};
   function qe(e3, t2) {
     let i3, n3 = [];
-    if (!e3)
-      return n3;
-    for (; null !== (i3 = t2.exec(e3)); )
-      n3.push(i3);
+    if (!e3) return n3;
+    for (; null !== (i3 = t2.exec(e3)); ) n3.push(i3);
     return n3;
   }
   function Qe(e3) {
     if (function(e4) {
       return null == e4 || "null" === e4 || "undefined" === e4 || "" === e4 || "" === e4.trim();
-    }(e3))
-      return;
+    }(e3)) return;
     let t2 = Number(e3);
-    if (!Number.isNaN(t2))
-      return t2;
+    if (!Number.isNaN(t2)) return t2;
     let i3 = e3.toLowerCase();
     return "true" === i3 || "false" !== i3 && e3.trim();
   }
       }
       {
         let t3 = this.subarray(e3, h2, true), i4 = atob(r2), s2 = t3.toUint8();
-        for (let e4 = 0; e4 < h2; e4++)
-          s2[e4] = i4.charCodeAt(n3 + e4);
+        for (let e4 = 0; e4 < h2; e4++) s2[e4] = i4.charCodeAt(n3 + e4);
         return t3;
       }
     }
     }
     async findIcc() {
       let e3 = this.metaChunks.find((e4) => "iccp" === e4.type);
-      if (!e3)
-        return;
+      if (!e3) return;
       let { chunk: t2 } = e3, i3 = t2.getUint8Array(0, 81), s2 = 0;
-      for (; s2 < 80 && 0 !== i3[s2]; )
-        s2++;
+      for (; s2 < 80 && 0 !== i3[s2]; ) s2++;
       let r2 = s2 + 2, a2 = t2.getString(0, s2);
       if (this.injectKeyValToIhdr("ProfileName", a2), n2) {
         let e4 = await lt, i4 = t2.getUint8Array(r2);
       return function(e4) {
         let t2 = function(e6) {
           let t3 = e6[0].constructor, i3 = 0;
-          for (let t4 of e6)
-            i3 += t4.length;
+          for (let t4 of e6) i3 += t4.length;
           let n3 = new t3(i3), s2 = 0;
-          for (let t4 of e6)
-            n3.set(t4, s2), s2 += t4.length;
+          for (let t4 of e6) n3.set(t4, s2), s2 += t4.length;
           return n3;
         }(e4.map((e6) => e6.chunk.toUint8()));
         return new I(t2);
     parseTags() {
       let e3, t2, i3, n3, s2, { raw: r2 } = this, a2 = this.chunk.getUint32(128), o2 = 132, l2 = this.chunk.byteLength;
       for (; a2--; ) {
-        if (e3 = this.chunk.getString(o2, 4), t2 = this.chunk.getUint32(o2 + 4), i3 = this.chunk.getUint32(o2 + 8), n3 = this.chunk.getString(t2, 4), t2 + i3 > l2)
-          return void console.warn("reached the end of the first ICC chunk. Enable options.tiff.multiSegment to read all ICC segments.");
+        if (e3 = this.chunk.getString(o2, 4), t2 = this.chunk.getUint32(o2 + 4), i3 = this.chunk.getUint32(o2 + 8), n3 = this.chunk.getString(t2, 4), t2 + i3 > l2) return void console.warn("reached the end of the first ICC chunk. Enable options.tiff.multiSegment to read all ICC segments.");
         s2 = this.parseTag(n3, t2, i3), void 0 !== s2 && "\0\0\0\0" !== s2 && r2.set(e3, s2), o2 += 12;
       }
     }
         case "sig ":
           return this.parseSig(t2);
       }
-      if (!(t2 + i3 > this.chunk.byteLength))
-        return this.chunk.getUint8Array(t2, i3);
+      if (!(t2 + i3 > this.chunk.byteLength)) return this.chunk.getUint8Array(t2, i3);
     }
     parseDesc(e3) {
       let t2 = this.chunk.getUint32(e3 + 8) - 1;
     }
     static headerLength(e3, t2, i3) {
       let n3, s2 = this.containsIptc8bim(e3, t2, i3);
-      if (void 0 !== s2)
-        return n3 = e3.getUint8(t2 + s2 + 7), n3 % 2 != 0 && (n3 += 1), 0 === n3 && (n3 = 4), s2 + 8 + n3;
+      if (void 0 !== s2) return n3 = e3.getUint8(t2 + s2 + 7), n3 % 2 != 0 && (n3 += 1), 0 === n3 && (n3 = 4), s2 + 8 + n3;
     }
     static containsIptc8bim(e3, t2, i3) {
-      for (let n3 = 0; n3 < i3; n3++)
-        if (this.isIptcSegmentHead(e3, t2 + n3))
-          return n3;
+      for (let n3 = 0; n3 < i3; n3++) if (this.isIptcSegmentHead(e3, t2 + n3)) return n3;
     }
     static isIptcSegmentHead(e3, t2) {
       return 56 === e3.getUint8(t2) && 943868237 === e3.getUint32(t2) && 1028 === e3.getUint16(t2 + 4);
     }
     parse() {
       let { raw: e3 } = this, t2 = this.chunk.byteLength - 1, i3 = false;
-      for (let n3 = 0; n3 < t2; n3++)
-        if (28 === this.chunk.getUint8(n3) && 2 === this.chunk.getUint8(n3 + 1)) {
-          i3 = true;
-          let t3 = this.chunk.getUint16(n3 + 3), s2 = this.chunk.getUint8(n3 + 2), r2 = this.chunk.getLatin1String(n3 + 5, t3);
-          e3.set(s2, this.pluralizeValue(e3.get(s2), r2)), n3 += 4 + t3;
-        } else if (i3)
-          break;
+      for (let n3 = 0; n3 < t2; n3++) if (28 === this.chunk.getUint8(n3) && 2 === this.chunk.getUint8(n3 + 1)) {
+        i3 = true;
+        let t3 = this.chunk.getUint16(n3 + 3), s2 = this.chunk.getUint8(n3 + 2), r2 = this.chunk.getLatin1String(n3 + 5, t3);
+        e3.set(s2, this.pluralizeValue(e3.get(s2), r2)), n3 += 4 + t3;
+      } else if (i3) break;
       return this.translate(), this.output;
     }
     pluralizeValue(e3, t2) {
   var full_esm_default = tt;
 
   // modules/services/plane_photo.js
-  var dispatch6 = dispatch_default("viewerChanged");
+  var dispatch5 = dispatch_default("viewerChanged");
   var _photo;
   var _wrapper;
   var imgZoom;
   }
   var plane_photo_default = {
     init: async function(context, selection2) {
-      this.event = utilRebind(this, dispatch6, "on");
+      this.event = utilRebind(this, dispatch5, "on");
       _wrapper = selection2.append("div").attr("class", "photo-frame plane-frame").classed("hide", true);
       _photo = _wrapper.append("img").attr("class", "plane-photo");
       context.ui().photoviewer.on("resize.plane", () => {
       context.select("photo-frame.plane-frame").classed("hide", false);
       return this;
     },
-    selectPhoto: function(data, keepOrientation) {
-      dispatch6.call("viewerChanged");
+    selectPhoto: function(data) {
+      dispatch5.call("viewerChanged");
       loadImage(_photo, "");
       loadImage(_photo, data.image_path).then(() => {
-        if (!keepOrientation) {
-          imgZoom = zoomBeahvior();
-          _wrapper.call(imgZoom);
-          _wrapper.call(imgZoom.transform, identity2.translate(-_widthOverflow / 2, 0));
-        }
+        imgZoom = zoomBeahvior();
+        _wrapper.call(imgZoom);
+        _wrapper.call(imgZoom.transform, identity2.translate(-_widthOverflow / 2, 0));
       });
       return this;
     },
     let _idAutoinc = 0;
     let _photoFrame;
     function init2() {
-      if (_initialized2)
-        return;
+      if (_initialized2) return;
       _enabled2 = true;
       function over(d3_event) {
         d3_event.stopPropagation();
       context.container().attr("dropzone", "copy").on("drop.svgLocalPhotos", function(d3_event) {
         d3_event.stopPropagation();
         d3_event.preventDefault();
-        if (!detected.filedrop)
-          return;
+        if (!detected.filedrop) return;
         drawPhotos.fileList(d3_event.dataTransfer.files, (loaded) => {
           if (loaded.length > 0) {
             drawPhotos.fitZoom(false);
       const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
       viewfields.exit().remove();
       viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", function() {
-        var _a2;
+        var _a3;
         const d2 = this.parentNode.__data__;
-        return "rotate(".concat(Math.round((_a2 = d2.direction) != null ? _a2 : 0), ",0,0),scale(1.5,1.5),translate(-8,-13)");
+        return "rotate(".concat(Math.round((_a3 = d2.direction) != null ? _a3 : 0), ",0,0),scale(1.5,1.5),translate(-8,-13)");
       }).attr("d", "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z").style("visibility", function() {
         const d2 = this.parentNode.__data__;
         return isNumber_default(d2.direction) ? "visible" : "hidden";
         } catch {
         }
       }
-      if (typeof callback === "function")
-        callback(loaded);
+      if (typeof callback === "function") callback(loaded);
       dispatch14.call("change");
     }
     drawPhotos.setFiles = function(fileList, callback) {
       return this;
     };
     drawPhotos.fileList = function(fileList, callback) {
-      if (!arguments.length)
-        return _fileList;
+      if (!arguments.length) return _fileList;
       _fileList = fileList;
-      if (!fileList || !fileList.length)
-        return this;
+      if (!fileList || !fileList.length) return this;
       drawPhotos.setFiles(_fileList, callback);
       return this;
     };
     drawPhotos.openPhoto = click;
     drawPhotos.fitZoom = function(force) {
       const coords = _photos.map((image) => image.loc).filter((l2) => isArray_default(l2) && isNumber_default(l2[0]) && isNumber_default(l2[1]));
-      if (coords.length === 0)
-        return;
+      if (coords.length === 0) return;
       const extent = coords.map((l2) => geoExtent(l2, l2)).reduce((a2, b2) => a2.extend(b2));
       const map2 = context.map();
       var viewport = map2.trimmedExtent().polygon();
       });
     }
     drawPhotos.enabled = function(val) {
-      if (!arguments.length)
-        return _enabled2;
+      if (!arguments.length) return _enabled2;
       _enabled2 = val;
       if (_enabled2) {
         showLayer();
     return drawPhotos;
   }
 
-  // modules/svg/improveOSM.js
+  // modules/svg/osmose.js
   var _layerEnabled2 = false;
   var _qaService2;
-  function svgImproveOSM(projection2, context, dispatch14) {
+  function svgOsmose(projection2, context, dispatch14) {
     const throttledRedraw = throttle_default(() => dispatch14.call("change"), 1e3);
-    const minZoom4 = 12;
+    const minZoom5 = 12;
     let touchLayer = select_default2(null);
     let drawLayer = select_default2(null);
     let layerVisible = false;
       selection2.attr("class", klass).attr("transform", "translate(-10, -28)").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
     }
     function getService() {
-      if (services.improveOSM && !_qaService2) {
-        _qaService2 = services.improveOSM;
+      if (services.osmose && !_qaService2) {
+        _qaService2 = services.osmose;
         _qaService2.on("loaded", throttledRedraw);
-      } else if (!services.improveOSM && _qaService2) {
+      } else if (!services.osmose && _qaService2) {
         _qaService2 = null;
       }
       return _qaService2;
         drawLayer.style("display", "block");
       }
     }
-    function editOff() {
-      if (layerVisible) {
-        layerVisible = false;
-        drawLayer.style("display", "none");
-        drawLayer.selectAll(".qaItem.improveOSM").remove();
-        touchLayer.selectAll(".qaItem.improveOSM").remove();
-      }
-    }
-    function layerOn() {
-      editOn();
-      drawLayer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", () => dispatch14.call("change"));
-    }
-    function layerOff() {
-      throttledRedraw.cancel();
-      drawLayer.interrupt();
-      touchLayer.selectAll(".qaItem.improveOSM").remove();
-      drawLayer.transition().duration(250).style("opacity", 0).on("end interrupt", () => {
-        editOff();
-        dispatch14.call("change");
-      });
-    }
-    function updateMarkers() {
-      if (!layerVisible || !_layerEnabled2)
-        return;
-      const service = getService();
-      const selectedID = context.selectedErrorID();
-      const data = service ? service.getItems(projection2) : [];
-      const getTransform = svgPointTransform(projection2);
-      const markers = drawLayer.selectAll(".qaItem.improveOSM").data(data, (d2) => d2.id);
-      markers.exit().remove();
-      const markersEnter = markers.enter().append("g").attr("class", (d2) => "qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.itemType));
-      markersEnter.append("polygon").call(markerPath, "shadow");
-      markersEnter.append("ellipse").attr("cx", 0).attr("cy", 0).attr("rx", 4.5).attr("ry", 2).attr("class", "stroke");
-      markersEnter.append("polygon").attr("fill", "currentColor").call(markerPath, "qaItem-fill");
-      markersEnter.append("use").attr("class", "icon-annotation").attr("transform", "translate(-6, -22)").attr("width", "12px").attr("height", "12px").attr("xlink:href", (d2) => d2.icon ? "#" + d2.icon : "");
-      markers.merge(markersEnter).sort(sortY).classed("selected", (d2) => d2.id === selectedID).attr("transform", getTransform);
-      if (touchLayer.empty())
-        return;
-      const fillClass = context.getDebug("target") ? "pink " : "nocolor ";
-      const targets = touchLayer.selectAll(".qaItem.improveOSM").data(data, (d2) => d2.id);
-      targets.exit().remove();
-      targets.enter().append("rect").attr("width", "20px").attr("height", "30px").attr("x", "-10px").attr("y", "-28px").merge(targets).sort(sortY).attr("class", (d2) => "qaItem ".concat(d2.service, " target ").concat(fillClass, " itemId-").concat(d2.id)).attr("transform", getTransform);
-      function sortY(a2, b2) {
-        return a2.id === selectedID ? 1 : b2.id === selectedID ? -1 : b2.loc[1] - a2.loc[1];
-      }
-    }
-    function drawImproveOSM(selection2) {
-      const service = getService();
-      const surface = context.surface();
-      if (surface && !surface.empty()) {
-        touchLayer = surface.selectAll(".data-layer.touch .layer-touch.markers");
-      }
-      drawLayer = selection2.selectAll(".layer-improveOSM").data(service ? [0] : []);
-      drawLayer.exit().remove();
-      drawLayer = drawLayer.enter().append("g").attr("class", "layer-improveOSM").style("display", _layerEnabled2 ? "block" : "none").merge(drawLayer);
-      if (_layerEnabled2) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
-          editOn();
-          service.loadIssues(projection2);
-          updateMarkers();
-        } else {
-          editOff();
-        }
-      }
-    }
-    drawImproveOSM.enabled = function(val) {
-      if (!arguments.length)
-        return _layerEnabled2;
-      _layerEnabled2 = val;
-      if (_layerEnabled2) {
-        layerOn();
-      } else {
-        layerOff();
-        if (context.selectedErrorID()) {
-          context.enter(modeBrowse(context));
-        }
-      }
-      dispatch14.call("change");
-      return this;
-    };
-    drawImproveOSM.supported = () => !!getService();
-    return drawImproveOSM;
-  }
-
-  // modules/svg/osmose.js
-  var _layerEnabled3 = false;
-  var _qaService3;
-  function svgOsmose(projection2, context, dispatch14) {
-    const throttledRedraw = throttle_default(() => dispatch14.call("change"), 1e3);
-    const minZoom4 = 12;
-    let touchLayer = select_default2(null);
-    let drawLayer = select_default2(null);
-    let layerVisible = false;
-    function markerPath(selection2, klass) {
-      selection2.attr("class", klass).attr("transform", "translate(-10, -28)").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
-    }
-    function getService() {
-      if (services.osmose && !_qaService3) {
-        _qaService3 = services.osmose;
-        _qaService3.on("loaded", throttledRedraw);
-      } else if (!services.osmose && _qaService3) {
-        _qaService3 = null;
-      }
-      return _qaService3;
-    }
-    function editOn() {
-      if (!layerVisible) {
-        layerVisible = true;
-        drawLayer.style("display", "block");
-      }
-    }
     function editOff() {
       if (layerVisible) {
         layerVisible = false;
       });
     }
     function updateMarkers() {
-      if (!layerVisible || !_layerEnabled3)
-        return;
+      if (!layerVisible || !_layerEnabled2) return;
       const service = getService();
       const selectedID = context.selectedErrorID();
       const data = service ? service.getItems(projection2) : [];
       markersEnter.append("polygon").attr("fill", (d2) => service.getColor(d2.item)).call(markerPath, "qaItem-fill");
       markersEnter.append("use").attr("class", "icon-annotation").attr("transform", "translate(-6, -22)").attr("width", "12px").attr("height", "12px").attr("xlink:href", (d2) => d2.icon ? "#" + d2.icon : "");
       markers.merge(markersEnter).sort(sortY).classed("selected", (d2) => d2.id === selectedID).attr("transform", getTransform);
-      if (touchLayer.empty())
-        return;
+      if (touchLayer.empty()) return;
       const fillClass = context.getDebug("target") ? "pink" : "nocolor";
       const targets = touchLayer.selectAll(".qaItem.osmose").data(data, (d2) => d2.id);
       targets.exit().remove();
       }
       drawLayer = selection2.selectAll(".layer-osmose").data(service ? [0] : []);
       drawLayer.exit().remove();
-      drawLayer = drawLayer.enter().append("g").attr("class", "layer-osmose").style("display", _layerEnabled3 ? "block" : "none").merge(drawLayer);
-      if (_layerEnabled3) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+      drawLayer = drawLayer.enter().append("g").attr("class", "layer-osmose").style("display", _layerEnabled2 ? "block" : "none").merge(drawLayer);
+      if (_layerEnabled2) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           service.loadIssues(projection2);
           updateMarkers();
       }
     }
     drawOsmose.enabled = function(val) {
-      if (!arguments.length)
-        return _layerEnabled3;
-      _layerEnabled3 = val;
-      if (_layerEnabled3) {
+      if (!arguments.length) return _layerEnabled2;
+      _layerEnabled2 = val;
+      if (_layerEnabled2) {
         getService().loadStrings().then(layerOn).catch((err) => {
           console.log(err);
         });
     var throttledRedraw = throttle_default(function() {
       dispatch14.call("change");
     }, 1e3);
-    var minZoom4 = 14;
+    var minZoom5 = 14;
     var minMarkerZoom = 16;
     var minViewfieldZoom2 = 18;
     var layer = select_default2(null);
     var _selectedSequence = null;
     var _streetside;
     function init2() {
-      if (svgStreetside.initialized)
-        return;
+      if (svgStreetside.initialized) return;
       svgStreetside.enabled = false;
       svgStreetside.initialized = true;
     }
     }
     function showLayer() {
       var service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       editOn();
       layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
         dispatch14.call("change");
     }
     function click(d3_event, d2) {
       var service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       if (d2.sequenceKey !== _selectedSequence) {
         _viewerYaw = 0;
       }
     }
     function mouseover(d3_event, d2) {
       var service = getService();
-      if (service)
-        service.setStyles(context, d2);
+      if (service) service.setStyles(context, d2);
     }
     function mouseout() {
       var service = getService();
-      if (service)
-        service.setStyles(context, null);
+      if (service) service.setStyles(context, null);
     }
     function transform2(d2) {
       var t2 = svgPointTransform(projection2)(d2);
     }
     function viewerChanged() {
       var service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       var viewer = service.viewer();
-      if (!viewer)
-        return;
+      if (!viewer) return;
       _viewerYaw = viewer.getYaw();
-      if (context.map().isTransformed())
-        return;
+      if (context.map().isTransformed()) return;
       layer.selectAll(".viewfield-group.currentView").attr("transform", transform2);
     }
     function filterBubbles(bubbles) {
       layerEnter.append("g").attr("class", "markers");
       layer = layerEnter.merge(layer);
       if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           update();
           service.loadBubbles(projection2);
       }
     }
     drawImages.enabled = function(_2) {
-      if (!arguments.length)
-        return svgStreetside.enabled;
+      if (!arguments.length) return svgStreetside.enabled;
       svgStreetside.enabled = _2;
       if (svgStreetside.enabled) {
         showLayer();
       return !!getService();
     };
     drawImages.rendered = function(zoom) {
-      return zoom >= minZoom4;
+      return zoom >= minZoom5;
     };
     init2();
     return drawImages;
   // modules/svg/vegbilder.js
   function svgVegbilder(projection2, context, dispatch14) {
     const throttledRedraw = throttle_default(() => dispatch14.call("change"), 1e3);
-    const minZoom4 = 14;
+    const minZoom5 = 14;
     const minMarkerZoom = 16;
     const minViewfieldZoom2 = 18;
     let layer = select_default2(null);
     let _viewerYaw = 0;
     let _vegbilder;
     function init2() {
-      if (svgVegbilder.initialized)
-        return;
+      if (svgVegbilder.initialized) return;
       svgVegbilder.enabled = false;
       svgVegbilder.initialized = true;
     }
     }
     function showLayer() {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       editOn();
       layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", () => dispatch14.call("change"));
     }
     }
     function click(d3_event, d2) {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       service.ensureViewerLoaded(context).then(() => {
         service.selectImage(context, d2.key).showViewer(context);
       });
     }
     function mouseover(d3_event, d2) {
       const service = getService();
-      if (service)
-        service.setStyles(context, d2);
+      if (service) service.setStyles(context, d2);
     }
     function mouseout() {
       const service = getService();
-      if (service)
-        service.setStyles(context, null);
+      if (service) service.setStyles(context, null);
     }
     function transform2(d2, selected) {
       let t2 = svgPointTransform(projection2)(d2);
     }
     function viewerChanged() {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       const frame2 = service.photoFrame();
       _viewerYaw = frame2.getYaw();
-      if (context.map().isTransformed())
-        return;
+      if (context.map().isTransformed()) return;
       layer.selectAll(".viewfield-group.currentView").attr("transform", (d2) => transform2(d2, d2));
     }
     function filterImages(images) {
       layerEnter.append("g").attr("class", "markers");
       layer = layerEnter.merge(layer);
       if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           update();
           service.loadImages(context);
       }
     }
     drawImages.enabled = function(_2) {
-      if (!arguments.length)
-        return svgVegbilder.enabled;
+      if (!arguments.length) return svgVegbilder.enabled;
       svgVegbilder.enabled = _2;
       if (svgVegbilder.enabled) {
         showLayer();
       return !!getService();
     };
     drawImages.rendered = function(zoom) {
-      return zoom >= minZoom4;
+      return zoom >= minZoom5;
     };
     drawImages.validHere = function(extent, zoom) {
-      return zoom >= minZoom4 - 2 && getService().validHere(extent);
+      return zoom >= minZoom5 - 2 && getService().validHere(extent);
     };
     init2();
     return drawImages;
     const throttledRedraw = throttle_default(function() {
       dispatch14.call("change");
     }, 1e3);
-    const minZoom4 = 12;
+    const minZoom5 = 12;
     const minMarkerZoom = 16;
     const minViewfieldZoom2 = 18;
     let layer = select_default2(null);
     let _mapillary;
     function init2() {
-      if (svgMapillaryImages.initialized)
-        return;
+      if (svgMapillaryImages.initialized) return;
       svgMapillaryImages.enabled = false;
       svgMapillaryImages.initialized = true;
     }
     }
     function showLayer() {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       editOn();
       layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
         dispatch14.call("change");
     }
     function click(d3_event, image) {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       service.ensureViewerLoaded(context).then(function() {
         service.selectImage(context, image.id).showViewer(context);
       });
     }
     function mouseover(d3_event, image) {
       const service = getService();
-      if (service)
-        service.setStyles(context, image);
+      if (service) service.setStyles(context, image);
     }
     function mouseout() {
       const service = getService();
-      if (service)
-        service.setStyles(context, null);
+      if (service) service.setStyles(context, null);
     }
     function transform2(d2) {
       let t2 = svgPointTransform(projection2)(d2);
       const toDate = context.photos().toDate();
       if (!showsPano || !showsFlat) {
         images = images.filter(function(image) {
-          if (image.is_pano)
-            return showsPano;
+          if (image.is_pano) return showsPano;
           return showsFlat;
         });
       }
       if (!showsPano || !showsFlat) {
         sequences = sequences.filter(function(sequence) {
           if (sequence.properties.hasOwnProperty("is_pano")) {
-            if (sequence.properties.is_pano)
-              return showsPano;
+            if (sequence.properties.is_pano) return showsPano;
             return showsFlat;
           }
           return false;
       layerEnter.append("g").attr("class", "markers");
       layer = layerEnter.merge(layer);
       if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           update();
           service.loadImages(projection2);
       }
     }
     drawImages.enabled = function(_2) {
-      if (!arguments.length)
-        return svgMapillaryImages.enabled;
+      if (!arguments.length) return svgMapillaryImages.enabled;
       svgMapillaryImages.enabled = _2;
       if (svgMapillaryImages.enabled) {
         showLayer();
       return !!getService();
     };
     drawImages.rendered = function(zoom) {
-      return zoom >= minZoom4;
+      return zoom >= minZoom5;
     };
     init2();
     return drawImages;
     const throttledRedraw = throttle_default(function() {
       update();
     }, 1e3);
-    const minZoom4 = 12;
+    const minZoom5 = 12;
     const minViewfieldZoom2 = 18;
     let layer = select_default2(null);
     let _mapillary;
     let viewerCompassAngle;
     function init2() {
-      if (svgMapillaryPosition.initialized)
-        return;
+      if (svgMapillaryPosition.initialized) return;
       svgMapillaryPosition.initialized = true;
     }
     function getService() {
         _mapillary.event.on("imageChanged", throttledRedraw);
         _mapillary.event.on("bearingChanged", function(e3) {
           viewerCompassAngle = e3.bearing;
-          if (context.map().isTransformed())
-            return;
+          if (context.map().isTransformed()) return;
           layer.selectAll(".viewfield-group.currentView").filter(function(d2) {
             return d2.is_pano;
           }).attr("transform", transform2);
       const layerEnter = layer.enter().append("g").attr("class", "layer-mapillary-position");
       layerEnter.append("g").attr("class", "markers");
       layer = layerEnter.merge(layer);
-      if (service && ~~context.map().zoom() >= minZoom4) {
+      if (service && ~~context.map().zoom() >= minZoom5) {
         editOn();
         update();
       } else {
       return !!getService();
     };
     drawImages.rendered = function(zoom) {
-      return zoom >= minZoom4;
+      return zoom >= minZoom5;
     };
     init2();
     return drawImages;
     const throttledRedraw = throttle_default(function() {
       dispatch14.call("change");
     }, 1e3);
-    const minZoom4 = 12;
+    const minZoom5 = 12;
     let layer = select_default2(null);
     let _mapillary;
     function init2() {
-      if (svgMapillarySigns.initialized)
-        return;
+      if (svgMapillarySigns.initialized) return;
       svgMapillarySigns.enabled = false;
       svgMapillarySigns.initialized = true;
     }
     }
     function showLayer() {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       service.loadSignResources(context);
       editOn();
     }
     }
     function click(d3_event, d2) {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       context.map().centerEase(d2.loc);
       const selectedImageId = service.getActiveImage() && service.getActiveImage().id;
       service.getDetections(d2.id).then((detections) => {
       layer.exit().remove();
       layer = layer.enter().append("g").attr("class", "layer-mapillary-signs layer-mapillary-detections").style("display", enabled ? "block" : "none").merge(layer);
       if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           update();
           service.loadSigns(projection2);
       }
     }
     drawSigns.enabled = function(_2) {
-      if (!arguments.length)
-        return svgMapillarySigns.enabled;
+      if (!arguments.length) return svgMapillarySigns.enabled;
       svgMapillarySigns.enabled = _2;
       if (svgMapillarySigns.enabled) {
         showLayer();
       return !!getService();
     };
     drawSigns.rendered = function(zoom) {
-      return zoom >= minZoom4;
+      return zoom >= minZoom5;
     };
     init2();
     return drawSigns;
     const throttledRedraw = throttle_default(function() {
       dispatch14.call("change");
     }, 1e3);
-    const minZoom4 = 12;
+    const minZoom5 = 12;
     let layer = select_default2(null);
     let _mapillary;
     function init2() {
-      if (svgMapillaryMapFeatures.initialized)
-        return;
+      if (svgMapillaryMapFeatures.initialized) return;
       svgMapillaryMapFeatures.enabled = false;
       svgMapillaryMapFeatures.initialized = true;
     }
     }
     function showLayer() {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       service.loadObjectResources(context);
       editOn();
     }
     }
     function click(d3_event, d2) {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       context.map().centerEase(d2.loc);
       const selectedImageId = service.getActiveImage() && service.getActiveImage().id;
       service.getDetections(d2.id).then((detections) => {
       layer.exit().remove();
       layer = layer.enter().append("g").attr("class", "layer-mapillary-map-features layer-mapillary-detections").style("display", enabled ? "block" : "none").merge(layer);
       if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           update();
           service.loadMapFeatures(projection2);
       }
     }
     drawMapFeatures.enabled = function(_2) {
-      if (!arguments.length)
-        return svgMapillaryMapFeatures.enabled;
+      if (!arguments.length) return svgMapillaryMapFeatures.enabled;
       svgMapillaryMapFeatures.enabled = _2;
       if (svgMapillaryMapFeatures.enabled) {
         showLayer();
       return !!getService();
     };
     drawMapFeatures.rendered = function(zoom) {
-      return zoom >= minZoom4;
+      return zoom >= minZoom5;
     };
     init2();
     return drawMapFeatures;
     var throttledRedraw = throttle_default(function() {
       dispatch14.call("change");
     }, 1e3);
-    var minZoom4 = 12;
+    var minZoom5 = 12;
     var minMarkerZoom = 16;
     var minViewfieldZoom2 = 18;
     var layer = select_default2(null);
     var _kartaview;
     function init2() {
-      if (svgKartaviewImages.initialized)
-        return;
+      if (svgKartaviewImages.initialized) return;
       svgKartaviewImages.enabled = false;
       svgKartaviewImages.initialized = true;
     }
     }
     function showLayer() {
       var service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       editOn();
       layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
         dispatch14.call("change");
     }
     function click(d3_event, d2) {
       var service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       service.ensureViewerLoaded(context).then(function() {
         service.selectImage(context, d2.key).showViewer(context);
       });
     }
     function mouseover(d3_event, d2) {
       var service = getService();
-      if (service)
-        service.setStyles(context, d2);
+      if (service) service.setStyles(context, d2);
     }
     function mouseout() {
       var service = getService();
-      if (service)
-        service.setStyles(context, null);
+      if (service) service.setStyles(context, null);
     }
     function transform2(d2) {
       var t2 = svgPointTransform(projection2)(d2);
       layerEnter.append("g").attr("class", "markers");
       layer = layerEnter.merge(layer);
       if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           update();
           service.loadImages(projection2);
       }
     }
     drawImages.enabled = function(_2) {
-      if (!arguments.length)
-        return svgKartaviewImages.enabled;
+      if (!arguments.length) return svgKartaviewImages.enabled;
       svgKartaviewImages.enabled = _2;
       if (svgKartaviewImages.enabled) {
         showLayer();
       return !!getService();
     };
     drawImages.rendered = function(zoom) {
-      return zoom >= minZoom4;
+      return zoom >= minZoom5;
     };
     init2();
     return drawImages;
     const throttledRedraw = throttle_default(function() {
       dispatch14.call("change");
     }, 1e3);
-    const minZoom4 = 12;
+    const minZoom5 = 12;
     let layer = select_default2(null);
     let _mapilio;
     const viewFieldZoomLevel = 18;
     function init2() {
-      if (svgMapilioImages.initialized)
-        return;
+      if (svgMapilioImages.initialized) return;
       svgMapilioImages.enabled = false;
       svgMapilioImages.initialized = true;
     }
     }
     function showLayer() {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       editOn();
       layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
         dispatch14.call("change");
     }
     function click(d3_event, image) {
       const service = getService();
-      if (!service)
-        return;
+      if (!service) return;
       service.ensureViewerLoaded(context, image.id).then(function() {
         service.selectImage(context, image.id).showViewer(context);
       });
     }
     function mouseover(d3_event, image) {
       const service = getService();
-      if (service)
-        service.setStyles(context, image);
+      if (service) service.setStyles(context, image);
     }
     function mouseout() {
       const service = getService();
-      if (service)
-        service.setStyles(context, null);
+      if (service) service.setStyles(context, null);
     }
     function update() {
       const z2 = ~~context.map().zoom();
       layerEnter.append("g").attr("class", "markers");
       layer = layerEnter.merge(layer);
       if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           update();
           service.loadImages(projection2);
       }
     }
     drawImages.enabled = function(_2) {
-      if (!arguments.length)
-        return svgMapilioImages.enabled;
+      if (!arguments.length) return svgMapilioImages.enabled;
       svgMapilioImages.enabled = _2;
       if (svgMapilioImages.enabled) {
         showLayer();
-        context.photos().on("change.mapilio_images", null);
+        context.photos().on("change.mapilio_images", update);
       } else {
         hideLayer();
         context.photos().on("change.mapilio_images", null);
       return !!getService();
     };
     drawImages.rendered = function(zoom) {
-      return zoom >= minZoom4;
+      return zoom >= minZoom5;
+    };
+    init2();
+    return drawImages;
+  }
+
+  // modules/svg/panoramax_images.js
+  function svgPanoramaxImages(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    const imageMinZoom2 = 15;
+    const lineMinZoom2 = 10;
+    const viewFieldZoomLevel = 18;
+    let layer = select_default2(null);
+    let _panoramax;
+    let _viewerYaw = 0;
+    let _selectedSequence;
+    let _activeUsernameFilter;
+    let _activeIds;
+    function init2() {
+      if (svgPanoramaxImages.initialized) return;
+      svgPanoramaxImages.enabled = false;
+      svgPanoramaxImages.initialized = true;
+    }
+    function getService() {
+      if (services.panoramax && !_panoramax) {
+        _panoramax = services.panoramax;
+        _panoramax.event.on("viewerChanged", viewerChanged).on("loadedLines", throttledRedraw).on("loadedImages", throttledRedraw);
+      } else if (!services.panoramax && _panoramax) {
+        _panoramax = null;
+      }
+      return _panoramax;
+    }
+    async function filterImages(images) {
+      const showsPano = context.photos().showsPanoramic();
+      const showsFlat = context.photos().showsFlat();
+      const fromDate = context.photos().fromDate();
+      const toDate = context.photos().toDate();
+      const username = context.photos().usernames();
+      const service = getService();
+      if (!showsPano || !showsFlat) {
+        images = images.filter(function(image) {
+          if (image.isPano) return showsPano;
+          return showsFlat;
+        });
+      }
+      if (fromDate) {
+        images = images.filter(function(image) {
+          return new Date(image.capture_time).getTime() >= new Date(fromDate).getTime();
+        });
+      }
+      if (toDate) {
+        images = images.filter(function(image) {
+          return new Date(image.capture_time).getTime() <= new Date(toDate).getTime();
+        });
+      }
+      if (username && service) {
+        if (_activeUsernameFilter !== username) {
+          _activeUsernameFilter = username;
+          const tempIds = await service.getUserIds(username);
+          _activeIds = {};
+          tempIds.forEach((id2) => {
+            _activeIds[id2] = true;
+          });
+        }
+        images = images.filter(function(image) {
+          return _activeIds[image.account_id];
+        });
+      }
+      return images;
+    }
+    async function filterSequences(sequences) {
+      const showsPano = context.photos().showsPanoramic();
+      const showsFlat = context.photos().showsFlat();
+      const fromDate = context.photos().fromDate();
+      const toDate = context.photos().toDate();
+      const username = context.photos().usernames();
+      const service = getService();
+      if (!showsPano || !showsFlat) {
+        sequences = sequences.filter(function(sequence) {
+          if (sequence.properties.type === "equirectangular") return showsPano;
+          return showsFlat;
+        });
+      }
+      if (fromDate) {
+        sequences = sequences.filter(function(sequence) {
+          return new Date(sequence.properties.date).getTime() >= new Date(fromDate).getTime().toString();
+        });
+      }
+      if (toDate) {
+        sequences = sequences.filter(function(sequence) {
+          return new Date(sequence.properties.date).getTime() <= new Date(toDate).getTime().toString();
+        });
+      }
+      if (username && service) {
+        if (_activeUsernameFilter !== username) {
+          _activeUsernameFilter = username;
+          const tempIds = await service.getUserIds(username);
+          _activeIds = {};
+          tempIds.forEach((id2) => {
+            _activeIds[id2] = true;
+          });
+        }
+        sequences = sequences.filter(function(sequence) {
+          return _activeIds[sequence.properties.account_id];
+        });
+      }
+      return sequences;
+    }
+    function showLayer() {
+      const service = getService();
+      if (!service) return;
+      editOn();
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
+        dispatch14.call("change");
+      });
+    }
+    function hideLayer() {
+      throttledRedraw.cancel();
+      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
+    }
+    function transform2(d2, selectedImageId) {
+      let t2 = svgPointTransform(projection2)(d2);
+      let rot = d2.heading;
+      if (d2.id === selectedImageId) {
+        rot += _viewerYaw;
+      }
+      if (rot) {
+        t2 += " rotate(" + Math.floor(rot) + ",0,0)";
+      }
+      return t2;
+    }
+    function editOn() {
+      layer.style("display", "block");
+    }
+    function editOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
+    }
+    function click(d3_event, image) {
+      const service = getService();
+      if (!service) return;
+      if (image.sequence_id !== _selectedSequence) {
+        _viewerYaw = 0;
+      }
+      _selectedSequence = image.sequence_id;
+      service.ensureViewerLoaded(context).then(function() {
+        service.selectImage(context, image.id).showViewer(context);
+      });
+      context.map().centerEase(image.loc);
+    }
+    function mouseover(d3_event, image) {
+      const service = getService();
+      if (service) service.setStyles(context, image);
+    }
+    function mouseout() {
+      const service = getService();
+      if (service) service.setStyles(context, null);
+    }
+    async function update() {
+      var _a3;
+      const zoom = ~~context.map().zoom();
+      const showViewfields = zoom >= viewFieldZoomLevel;
+      const service = getService();
+      let sequences = service ? service.sequences(projection2, zoom) : [];
+      let images = service && zoom >= imageMinZoom2 ? service.images(projection2) : [];
+      images = await filterImages(images);
+      sequences = await filterSequences(sequences, service);
+      let traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d2) {
+        return d2.properties.id;
+      });
+      traces.exit().remove();
+      traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
+      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(images, function(d2) {
+        return d2.id;
+      });
+      groups.exit().remove();
+      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      const activeImageId = (_a3 = service.getActiveImage()) == null ? void 0 : _a3.id;
+      const markers = groups.merge(groupsEnter).sort(function(a2, b2) {
+        if (a2.id === activeImageId) return 1;
+        if (b2.id === activeImageId) return -1;
+        return a2.capture_time_parsed - b2.capture_time_parsed;
+      }).attr("transform", (d2) => transform2(d2, activeImageId)).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", viewfieldPath);
+      service.setStyles(context, null);
+      function viewfieldPath() {
+        if (this.parentNode.__data__.isPano) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
+        } else {
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+        }
+      }
+    }
+    function viewerChanged() {
+      const service = getService();
+      if (!service) return;
+      const frame2 = service.photoFrame();
+      if (!frame2) return;
+      _viewerYaw = frame2.getYaw();
+      if (context.map().isTransformed()) return;
+      layer.selectAll(".viewfield-group.currentView").attr("transform", (d2) => transform2(d2, d2.id));
+    }
+    function drawImages(selection2) {
+      const enabled = svgPanoramaxImages.enabled;
+      const service = getService();
+      layer = selection2.selectAll(".layer-panoramax").data(service ? [0] : []);
+      layer.exit().remove();
+      const layerEnter = layer.enter().append("g").attr("class", "layer-panoramax").style("display", enabled ? "block" : "none");
+      layerEnter.append("g").attr("class", "sequences");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (enabled) {
+        let zoom = ~~context.map().zoom();
+        if (service) {
+          if (zoom >= imageMinZoom2) {
+            editOn();
+            update();
+            service.loadImages(projection2);
+          } else if (zoom >= lineMinZoom2) {
+            editOn();
+            update();
+            service.loadLines(projection2, zoom);
+          } else {
+            editOff();
+          }
+        } else {
+          editOff();
+        }
+      }
+    }
+    drawImages.enabled = function(_2) {
+      if (!arguments.length) return svgPanoramaxImages.enabled;
+      svgPanoramaxImages.enabled = _2;
+      if (svgPanoramaxImages.enabled) {
+        showLayer();
+        context.photos().on("change.panoramax_images", update);
+      } else {
+        hideLayer();
+        context.photos().on("change.panoramax_images", null);
+      }
+      dispatch14.call("change");
+      return this;
+    };
+    drawImages.supported = function() {
+      return !!getService();
+    };
+    drawImages.rendered = function(zoom) {
+      return zoom >= lineMinZoom2;
     };
     init2();
     return drawImages;
       });
     }
     drawOsm.enabled = function(val) {
-      if (!arguments.length)
-        return enabled;
+      if (!arguments.length) return enabled;
       enabled = val;
       if (enabled) {
         showLayer();
     var throttledRedraw = throttle_default(function() {
       dispatch14.call("change");
     }, 1e3);
-    var minZoom4 = 12;
+    var minZoom5 = 12;
     var touchLayer = select_default2(null);
     var drawLayer = select_default2(null);
     var _notesVisible = false;
       });
     }
     function updateMarkers() {
-      if (!_notesVisible || !_notesEnabled)
-        return;
+      if (!_notesVisible || !_notesEnabled) return;
       var service = getService();
       var selectedID = context.selectedNoteID();
       var data = service ? service.notes(projection2) : [];
       notesEnter.selectAll(".icon-annotation").data(function(d2) {
         return [d2];
       }).enter().append("use").attr("class", "icon-annotation").attr("width", "10px").attr("height", "10px").attr("x", "-3px").attr("y", "-19px").attr("xlink:href", function(d2) {
-        if (d2.id < 0)
-          return "#iD-icon-plus";
-        if (d2.status === "open")
-          return "#iD-icon-close";
+        if (d2.id < 0) return "#iD-icon-plus";
+        if (d2.status === "open") return "#iD-icon-close";
         return "#iD-icon-apply";
       });
       notes.merge(notesEnter).sort(sortY).classed("selected", function(d2) {
         var isMoving = mode && mode.id === "drag-note";
         return !isMoving && d2.id === selectedID;
       }).attr("transform", getTransform);
-      if (touchLayer.empty())
-        return;
+      if (touchLayer.empty()) return;
       var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
       var targets = touchLayer.selectAll(".note").data(data, function(d2) {
         return d2.id;
         return "note target note-" + d2.id + " " + fillClass + newClass;
       }).attr("transform", getTransform);
       function sortY(a2, b2) {
-        if (a2.id === selectedID)
-          return 1;
-        if (b2.id === selectedID)
-          return -1;
+        if (a2.id === selectedID) return 1;
+        if (b2.id === selectedID) return -1;
         return b2.loc[1] - a2.loc[1];
       }
     }
       drawLayer.exit().remove();
       drawLayer = drawLayer.enter().append("g").attr("class", "layer-notes").style("display", _notesEnabled ? "block" : "none").merge(drawLayer);
       if (_notesEnabled) {
-        if (service && ~~context.map().zoom() >= minZoom4) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
           editOn();
           service.loadNotes(projection2);
           updateMarkers();
       }
     }
     drawNotes.enabled = function(val) {
-      if (!arguments.length)
-        return _notesEnabled;
+      if (!arguments.length) return _notesEnabled;
       _notesEnabled = val;
       if (_notesEnabled) {
         layerOn();
       { id: "notes", layer: svgNotes(projection2, context, dispatch14) },
       { id: "data", layer: svgData(projection2, context, dispatch14) },
       { id: "keepRight", layer: svgKeepRight(projection2, context, dispatch14) },
-      { id: "improveOSM", layer: svgImproveOSM(projection2, context, dispatch14) },
       { id: "osmose", layer: svgOsmose(projection2, context, dispatch14) },
       { id: "streetside", layer: svgStreetside(projection2, context, dispatch14) },
       { id: "mapillary", layer: svgMapillaryImages(projection2, context, dispatch14) },
       { id: "kartaview", layer: svgKartaviewImages(projection2, context, dispatch14) },
       { id: "mapilio", layer: svgMapilioImages(projection2, context, dispatch14) },
       { id: "vegbilder", layer: svgVegbilder(projection2, context, dispatch14) },
+      { id: "panoramax", layer: svgPanoramaxImages(projection2, context, dispatch14) },
       { id: "local-photos", layer: svgLocalPhotos(projection2, context, dispatch14) },
       { id: "debug", layer: svgDebug(projection2, context, dispatch14) },
       { id: "geolocate", layer: svgGeolocate(projection2, context, dispatch14) },
       return this;
     };
     drawLayers.dimensions = function(val) {
-      if (!arguments.length)
-        return utilGetDimensions(svg2);
+      if (!arguments.length) return utilGetDimensions(svg2);
       utilSetDimensions(svg2, val);
       return this;
     };
           graph,
           35,
           function shouldReverse(entity2) {
-            return entity2.tags.oneway === "-1";
+            return entity2.tags.oneway === "-1" || entity2.tags.conveying === "backward";
           },
           function bothDirections(entity2) {
-            return entity2.tags.oneway === "reversible" || entity2.tags.oneway === "alternating";
+            return entity2.tags.oneway === "alternating" || entity2.tags.oneway === "reversible" || entity2.tags.conveying === "reversible";
           }
         );
         onewaydata[k2] = utilArrayFlatten(onewayArr.map(onewaySegments));
       var midpoints = {};
       for (var i3 = 0; i3 < entities.length; i3++) {
         var entity = entities[i3];
-        if (entity.type !== "way")
-          continue;
-        if (!filter2(entity))
-          continue;
-        if (context.selectedIDs().indexOf(entity.id) < 0)
-          continue;
+        if (entity.type !== "way") continue;
+        if (!filter2(entity)) continue;
+        if (context.selectedIDs().indexOf(entity.id) < 0) continue;
         var nodes = graph.childNodes(entity);
         for (var j2 = 0; j2 < nodes.length - 1; j2++) {
           var a2 = nodes[j2];
           if (midpoints[id2]) {
             midpoints[id2].parents.push(entity);
           } else if (geoVecLength(projection2(a2.loc), projection2(b2.loc)) > 40) {
-            var point2 = geoVecInterp(a2.loc, b2.loc, 0.5);
+            var point = geoVecInterp(a2.loc, b2.loc, 0.5);
             var loc = null;
-            if (extent.intersects(point2)) {
-              loc = point2;
+            if (extent.intersects(point)) {
+              loc = point;
             } else {
               for (var k2 = 0; k2 < 4; k2++) {
-                point2 = geoLineIntersection([a2.loc, b2.loc], [poly[k2], poly[k2 + 1]]);
-                if (point2 && geoVecLength(projection2(a2.loc), projection2(point2)) > 20 && geoVecLength(projection2(b2.loc), projection2(point2)) > 20) {
-                  loc = point2;
+                point = geoLineIntersection([a2.loc, b2.loc], [poly[k2], poly[k2 + 1]]);
+                if (point && geoVecLength(projection2(a2.loc), projection2(point)) > 20 && geoVecLength(projection2(b2.loc), projection2(point)) > 20) {
+                  loc = point;
                   break;
                 }
               }
         }
       }
       function midpointFilter(d2) {
-        if (midpoints[d2.id])
-          return true;
+        if (midpoints[d2.id]) return true;
         for (var i4 = 0; i4 < d2.parents.length; i4++) {
           if (filter2(d2.parents[i4])) {
             return true;
       var activeID = context.activeID();
       var data = [];
       entities.forEach(function(node) {
-        if (activeID === node.id)
-          return;
+        if (activeID === node.id) return;
         data.push({
           type: "Feature",
           id: node.id,
   function svgTurns(projection2, context) {
     function icon2(turn) {
       var u2 = turn.u ? "-u" : "";
-      if (turn.no)
-        return "#iD-turn-no" + u2;
-      if (turn.only)
-        return "#iD-turn-only" + u2;
+      if (turn.no) return "#iD-turn-no" + u2;
+      if (turn.only) return "#iD-turn-only" + u2;
       return "#iD-turn-yes" + u2;
     }
     function drawTurns(selection2, graph, turns) {
       var base = context.history().base();
       function getIcon(d2) {
         var entity = graph.entity(d2.id);
-        if (entity.id in icons)
-          return icons[entity.id];
+        if (entity.id in icons) return icons[entity.id];
         icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
         return icons[entity.id];
       }
       function getDirections(entity) {
-        if (entity.id in directions)
-          return directions[entity.id];
+        if (entity.id in directions) return directions[entity.id];
         var angles = entity.directions(graph, projection2);
         directions[entity.id] = angles.length ? angles : false;
         return angles;
         return base.entities[d2.id] && !(0, import_fast_deep_equal8.default)(graph.entities[d2.id].loc, base.entities[d2.id].loc);
       }).classed("retagged", function(d2) {
         return base.entities[d2.id] && !(0, import_fast_deep_equal8.default)(graph.entities[d2.id].tags, base.entities[d2.id].tags);
-      }).call(updateAttributes);
+      }).call(svgTagClasses()).call(updateAttributes);
       var iconUse = groups.selectAll(".icon").data(function data(d2) {
         return zoom >= 17 && getIcon(d2) ? [d2] : [];
       }, fastEntityKey);
       var activeID = context.activeID();
       var data = { targets: [], nopes: [] };
       entities.forEach(function(node) {
-        if (activeID === node.id)
-          return;
+        if (activeID === node.id) return;
         var vertexType = svgPassiveVertex(node, graph, activeID);
         if (vertexType !== 0) {
           data.targets.push({
       var results = {};
       var seenIds = {};
       function addChildVertices(entity) {
-        if (seenIds[entity.id])
-          return;
+        if (seenIds[entity.id]) return;
         seenIds[entity.id] = true;
         var geometry = entity.geometry(graph);
         if (!context.features().isHiddenFeature(entity, graph, geometry)) {
       }
       ids.forEach(function(id2) {
         var entity = graph.hasEntity(id2);
-        if (!entity)
-          return;
+        if (!entity) return;
         if (entity.type === "node") {
           if (renderAsVertex(entity, graph, wireframe, zoom)) {
             results[entity.id] = entity;
         _currSelected = {};
         context.selectedIDs().forEach(function(id2) {
           var entity = graph.hasEntity(id2);
-          if (!entity)
-            return;
+          if (!entity) return;
           if (entity.type === "node") {
             if (renderAsVertex(entity, graph, wireframe, zoom)) {
               _currSelected[entity.id] = entity;
       drawVertices(selection2, graph, Object.values(_prevSelected), filter2, extent, false);
     };
     drawVertices.drawHover = function(selection2, graph, target, extent) {
-      if (target === _currHoverTarget)
-        return;
+      if (target === _currHoverTarget) return;
       var wireframe = context.surface().classed("fill-wireframe");
       var zoom = geoScaleToZoom(projection2.scale());
       _prevHover = _currHover || {};
     return drawVertices;
   }
 
-  // modules/util/bind_once.js
-  function utilBindOnce(target, type2, listener, capture) {
-    var typeOnce = type2 + ".once";
-    function one2() {
-      target.on(typeOnce, null);
-      listener.apply(this, arguments);
-    }
-    target.on(typeOnce, one2, capture);
-    return this;
-  }
-
-  // modules/util/zoom_pan.js
-  function defaultFilter3(d3_event) {
-    return !d3_event.ctrlKey && !d3_event.button;
-  }
-  function defaultExtent2() {
-    var e3 = this;
-    if (e3 instanceof SVGElement) {
-      e3 = e3.ownerSVGElement || e3;
-      if (e3.hasAttribute("viewBox")) {
-        e3 = e3.viewBox.baseVal;
-        return [[e3.x, e3.y], [e3.x + e3.width, e3.y + e3.height]];
-      }
-      return [[0, 0], [e3.width.baseVal.value, e3.height.baseVal.value]];
-    }
-    return [[0, 0], [e3.clientWidth, e3.clientHeight]];
-  }
-  function defaultWheelDelta2(d3_event) {
-    return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 2e-3);
-  }
-  function defaultConstrain2(transform2, extent, translateExtent) {
-    var dx0 = transform2.invertX(extent[0][0]) - translateExtent[0][0], dx1 = transform2.invertX(extent[1][0]) - translateExtent[1][0], dy0 = transform2.invertY(extent[0][1]) - translateExtent[0][1], dy1 = transform2.invertY(extent[1][1]) - translateExtent[1][1];
-    return transform2.translate(
-      dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
-      dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
-    );
-  }
-  function utilZoomPan() {
-    var filter2 = defaultFilter3, extent = defaultExtent2, constrain = defaultConstrain2, wheelDelta = defaultWheelDelta2, scaleExtent = [0, Infinity], translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], interpolate = zoom_default, dispatch14 = dispatch_default("start", "zoom", "end"), _wheelDelay = 150, _transform = identity2, _activeGesture;
-    function zoom(selection2) {
-      selection2.on("pointerdown.zoom", pointerdown).on("wheel.zoom", wheeled).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
-      select_default2(window).on("pointermove.zoompan", pointermove).on("pointerup.zoompan pointercancel.zoompan", pointerup);
-    }
-    zoom.transform = function(collection, transform2, point2) {
-      var selection2 = collection.selection ? collection.selection() : collection;
-      if (collection !== selection2) {
-        schedule(collection, transform2, point2);
+  // modules/ui/length_indicator.js
+  function uiLengthIndicator(maxChars) {
+    var _wrap = select_default2(null);
+    var _tooltip = uiPopover("tooltip max-length-warning").placement("bottom").hasArrow(true).content(() => (selection2) => {
+      selection2.text("");
+      selection2.call(svgIcon("#iD-icon-alert", "inline"));
+      selection2.call(_t.append("inspector.max_length_reached", { maxChars }));
+    });
+    var _silent = false;
+    var lengthIndicator = function(selection2) {
+      _wrap = selection2.selectAll("span.length-indicator-wrap").data([0]);
+      _wrap = _wrap.enter().append("span").merge(_wrap).classed("length-indicator-wrap", true);
+      selection2.call(_tooltip);
+    };
+    lengthIndicator.update = function(val) {
+      const strLen = utilUnicodeCharsCount(utilCleanOsmString(val, Number.POSITIVE_INFINITY));
+      let indicator = _wrap.selectAll("span.length-indicator").data([strLen]);
+      indicator.enter().append("span").merge(indicator).classed("length-indicator", true).classed("limit-reached", (d2) => d2 > maxChars).style("border-right-width", (d2) => "".concat(Math.abs(maxChars - d2) * 2, "px")).style("margin-right", (d2) => d2 > maxChars ? "".concat((maxChars - d2) * 2, "px") : 0).style("opacity", (d2) => d2 > maxChars * 0.8 ? Math.min(1, (d2 / maxChars - 0.8) / (1 - 0.8)) : 0).style("pointer-events", (d2) => d2 > maxChars * 0.8 ? null : "none");
+      if (_silent) return;
+      if (strLen > maxChars) {
+        _tooltip.show();
       } else {
-        selection2.interrupt().each(function() {
-          gesture(this, arguments).start(null).zoom(null, null, typeof transform2 === "function" ? transform2.apply(this, arguments) : transform2).end(null);
-        });
+        _tooltip.hide();
       }
     };
-    zoom.scaleBy = function(selection2, k2, p2) {
-      zoom.scaleTo(selection2, function() {
-        var k0 = _transform.k, k1 = typeof k2 === "function" ? k2.apply(this, arguments) : k2;
-        return k0 * k1;
-      }, p2);
-    };
-    zoom.scaleTo = function(selection2, k2, p2) {
-      zoom.transform(selection2, function() {
-        var e3 = extent.apply(this, arguments), t0 = _transform, p02 = !p2 ? centroid(e3) : typeof p2 === "function" ? p2.apply(this, arguments) : p2, p1 = t0.invert(p02), k1 = typeof k2 === "function" ? k2.apply(this, arguments) : k2;
-        return constrain(translate(scale(t0, k1), p02, p1), e3, translateExtent);
-      }, p2);
-    };
-    zoom.translateBy = function(selection2, x2, y2) {
-      zoom.transform(selection2, function() {
-        return constrain(_transform.translate(
-          typeof x2 === "function" ? x2.apply(this, arguments) : x2,
-          typeof y2 === "function" ? y2.apply(this, arguments) : y2
-        ), extent.apply(this, arguments), translateExtent);
-      });
-    };
-    zoom.translateTo = function(selection2, x2, y2, p2) {
-      zoom.transform(selection2, function() {
-        var e3 = extent.apply(this, arguments), t2 = _transform, p02 = !p2 ? centroid(e3) : typeof p2 === "function" ? p2.apply(this, arguments) : p2;
-        return constrain(identity2.translate(p02[0], p02[1]).scale(t2.k).translate(
-          typeof x2 === "function" ? -x2.apply(this, arguments) : -x2,
-          typeof y2 === "function" ? -y2.apply(this, arguments) : -y2
-        ), e3, translateExtent);
-      }, p2);
+    lengthIndicator.silent = function(val) {
+      if (!arguments.length) return _silent;
+      _silent = val;
+      return lengthIndicator;
     };
-    function scale(transform2, k2) {
-      k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k2));
-      return k2 === transform2.k ? transform2 : new Transform(k2, transform2.x, transform2.y);
+    return lengthIndicator;
+  }
+
+  // modules/ui/fields/combo.js
+  function uiFieldCombo(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var _isMulti = field.type === "multiCombo" || field.type === "manyCombo";
+    var _isNetwork = field.type === "networkCombo";
+    var _isSemi = field.type === "semiCombo";
+    var _showTagInfoSuggestions = field.type !== "manyCombo" && field.autoSuggestions !== false;
+    var _allowCustomValues = field.type !== "manyCombo" && field.customValues !== false;
+    var _snake_case = field.snake_case || field.snake_case === void 0;
+    var _combobox = uiCombobox(context, "combo-" + field.safeid).caseSensitive(field.caseSensitive).minItems(1);
+    var _container = select_default2(null);
+    var _inputWrap = select_default2(null);
+    var _input = select_default2(null);
+    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
+    var _comboData = [];
+    var _multiData = [];
+    var _entityIDs = [];
+    var _tags;
+    var _countryCode;
+    var _staticPlaceholder;
+    var _dataDeprecated = [];
+    _mainFileFetcher.get("deprecated").then(function(d2) {
+      _dataDeprecated = d2;
+    }).catch(function() {
+    });
+    if (_isMulti && field.key && /[^:]$/.test(field.key)) {
+      field.key += ":";
     }
-    function translate(transform2, p02, p1) {
-      var x2 = p02[0] - p1[0] * transform2.k, y2 = p02[1] - p1[1] * transform2.k;
-      return x2 === transform2.x && y2 === transform2.y ? transform2 : new Transform(transform2.k, x2, y2);
+    function snake(s2) {
+      return s2.replace(/\s+/g, "_");
     }
-    function centroid(extent2) {
-      return [(+extent2[0][0] + +extent2[1][0]) / 2, (+extent2[0][1] + +extent2[1][1]) / 2];
+    function clean2(s2) {
+      return s2.split(";").map(function(s3) {
+        return s3.trim();
+      }).join(";");
     }
-    function schedule(transition2, transform2, point2) {
-      transition2.on("start.zoom", function() {
-        gesture(this, arguments).start(null);
-      }).on("interrupt.zoom end.zoom", function() {
-        gesture(this, arguments).end(null);
-      }).tween("zoom", function() {
-        var that = this, args = arguments, g3 = gesture(that, args), e3 = extent.apply(that, args), p2 = !point2 ? centroid(e3) : typeof point2 === "function" ? point2.apply(that, args) : point2, w2 = Math.max(e3[1][0] - e3[0][0], e3[1][1] - e3[0][1]), a2 = _transform, b2 = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i3 = interpolate(a2.invert(p2).concat(w2 / a2.k), b2.invert(p2).concat(w2 / b2.k));
-        return function(t2) {
-          if (t2 === 1) {
-            t2 = b2;
-          } else {
-            var l2 = i3(t2);
-            var k2 = w2 / l2[2];
-            t2 = new Transform(k2, p2[0] - l2[0] * k2, p2[1] - l2[1] * k2);
-          }
-          g3.zoom(null, null, t2);
-        };
+    function tagValue(dval) {
+      dval = clean2(dval || "");
+      var found = getOptions(true).find(function(o2) {
+        return o2.key && clean2(o2.value) === dval;
       });
+      if (found) return found.key;
+      if (field.type === "typeCombo" && !dval) {
+        return "yes";
+      }
+      return restrictTagValueSpelling(dval) || void 0;
     }
-    function gesture(that, args, clean2) {
-      return !clean2 && _activeGesture || new Gesture(that, args);
+    function restrictTagValueSpelling(dval) {
+      if (_snake_case) {
+        dval = snake(dval);
+      }
+      if (!field.caseSensitive) {
+        dval = dval.toLowerCase();
+      }
+      return dval;
     }
-    function Gesture(that, args) {
-      this.that = that;
-      this.args = args;
-      this.active = 0;
-      this.extent = extent.apply(that, args);
+    function getLabelId(field2, v2) {
+      return field2.hasTextForStringId("options.".concat(v2, ".title")) ? "options.".concat(v2, ".title") : "options.".concat(v2);
     }
-    Gesture.prototype = {
-      start: function(d3_event) {
-        if (++this.active === 1) {
-          _activeGesture = this;
-          dispatch14.call("start", this, d3_event);
-        }
-        return this;
-      },
-      zoom: function(d3_event, key, transform2) {
-        if (this.mouse && key !== "mouse")
-          this.mouse[1] = transform2.invert(this.mouse[0]);
-        if (this.pointer0 && key !== "touch")
-          this.pointer0[1] = transform2.invert(this.pointer0[0]);
-        if (this.pointer1 && key !== "touch")
-          this.pointer1[1] = transform2.invert(this.pointer1[0]);
-        _transform = transform2;
-        dispatch14.call("zoom", this, d3_event, key, transform2);
-        return this;
-      },
-      end: function(d3_event) {
-        if (--this.active === 0) {
-          _activeGesture = null;
-          dispatch14.call("end", this, d3_event);
-        }
-        return this;
-      }
-    };
-    function wheeled(d3_event) {
-      if (!filter2.apply(this, arguments))
-        return;
-      var g3 = gesture(this, arguments), t2 = _transform, k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t2.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p2 = utilFastMouse(this)(d3_event);
-      if (g3.wheel) {
-        if (g3.mouse[0][0] !== p2[0] || g3.mouse[0][1] !== p2[1]) {
-          g3.mouse[1] = t2.invert(g3.mouse[0] = p2);
-        }
-        clearTimeout(g3.wheel);
-      } else {
-        g3.mouse = [p2, t2.invert(p2)];
-        interrupt_default(this);
-        g3.start(d3_event);
+    function displayValue(tval) {
+      tval = tval || "";
+      var stringsField = field.resolveReference("stringsCrossReference");
+      const labelId = getLabelId(stringsField, tval);
+      if (stringsField.hasTextForStringId(labelId)) {
+        return stringsField.t(labelId, { default: tval });
       }
-      d3_event.preventDefault();
-      d3_event.stopImmediatePropagation();
-      g3.wheel = setTimeout(wheelidled, _wheelDelay);
-      g3.zoom(d3_event, "mouse", constrain(translate(scale(t2, k2), g3.mouse[0], g3.mouse[1]), g3.extent, translateExtent));
-      function wheelidled() {
-        g3.wheel = null;
-        g3.end(d3_event);
+      if (field.type === "typeCombo" && tval.toLowerCase() === "yes") {
+        return "";
       }
+      return tval;
     }
-    var _downPointerIDs = /* @__PURE__ */ new Set();
-    var _pointerLocGetter;
-    function pointerdown(d3_event) {
-      _downPointerIDs.add(d3_event.pointerId);
-      if (!filter2.apply(this, arguments))
-        return;
-      var g3 = gesture(this, arguments, _downPointerIDs.size === 1);
-      var started;
-      d3_event.stopImmediatePropagation();
-      _pointerLocGetter = utilFastMouse(this);
-      var loc = _pointerLocGetter(d3_event);
-      var p2 = [loc, _transform.invert(loc), d3_event.pointerId];
-      if (!g3.pointer0) {
-        g3.pointer0 = p2;
-        started = true;
-      } else if (!g3.pointer1 && g3.pointer0[2] !== p2[2]) {
-        g3.pointer1 = p2;
+    function renderValue(tval) {
+      tval = tval || "";
+      var stringsField = field.resolveReference("stringsCrossReference");
+      const labelId = getLabelId(stringsField, tval);
+      if (stringsField.hasTextForStringId(labelId)) {
+        return stringsField.t.append(labelId, { default: tval });
       }
-      if (started) {
-        interrupt_default(this);
-        g3.start(d3_event);
+      if (field.type === "typeCombo" && tval.toLowerCase() === "yes") {
+        tval = "";
       }
+      return (selection2) => selection2.text(tval);
     }
-    function pointermove(d3_event) {
-      if (!_downPointerIDs.has(d3_event.pointerId))
-        return;
-      if (!_activeGesture || !_pointerLocGetter)
-        return;
-      var g3 = gesture(this, arguments);
-      var isPointer0 = g3.pointer0 && g3.pointer0[2] === d3_event.pointerId;
-      var isPointer1 = !isPointer0 && g3.pointer1 && g3.pointer1[2] === d3_event.pointerId;
-      if ((isPointer0 || isPointer1) && "buttons" in d3_event && !d3_event.buttons) {
-        if (g3.pointer0)
-          _downPointerIDs.delete(g3.pointer0[2]);
-        if (g3.pointer1)
-          _downPointerIDs.delete(g3.pointer1[2]);
-        g3.end(d3_event);
-        return;
+    function objectDifference(a2, b2) {
+      return a2.filter(function(d1) {
+        return !b2.some(function(d2) {
+          return d1.value === d2.value;
+        });
+      });
+    }
+    function initCombo(selection2, attachTo) {
+      if (!_allowCustomValues) {
+        selection2.attr("readonly", "readonly");
       }
-      d3_event.preventDefault();
-      d3_event.stopImmediatePropagation();
-      var loc = _pointerLocGetter(d3_event);
-      var t2, p2, l2;
-      if (isPointer0)
-        g3.pointer0[0] = loc;
-      else if (isPointer1)
-        g3.pointer1[0] = loc;
-      t2 = _transform;
-      if (g3.pointer1) {
-        var p02 = g3.pointer0[0], l0 = g3.pointer0[1], p1 = g3.pointer1[0], l1 = g3.pointer1[1], dp = (dp = p1[0] - p02[0]) * dp + (dp = p1[1] - p02[1]) * dp, dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
-        t2 = scale(t2, Math.sqrt(dp / dl));
-        p2 = [(p02[0] + p1[0]) / 2, (p02[1] + p1[1]) / 2];
-        l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
-      } else if (g3.pointer0) {
-        p2 = g3.pointer0[0];
-        l2 = g3.pointer0[1];
+      if (_showTagInfoSuggestions && services.taginfo) {
+        selection2.call(_combobox.fetcher(setTaginfoValues), attachTo);
+        setTaginfoValues("", setPlaceholder);
       } else {
-        return;
+        selection2.call(_combobox, attachTo);
+        setTimeout(() => setStaticValues(setPlaceholder), 0);
       }
-      g3.zoom(d3_event, "touch", constrain(translate(t2, p2, l2), g3.extent, translateExtent));
     }
-    function pointerup(d3_event) {
-      if (!_downPointerIDs.has(d3_event.pointerId))
-        return;
-      _downPointerIDs.delete(d3_event.pointerId);
-      if (!_activeGesture)
-        return;
-      var g3 = gesture(this, arguments);
-      d3_event.stopImmediatePropagation();
-      if (g3.pointer0 && g3.pointer0[2] === d3_event.pointerId)
-        delete g3.pointer0;
-      else if (g3.pointer1 && g3.pointer1[2] === d3_event.pointerId)
-        delete g3.pointer1;
-      if (g3.pointer1 && !g3.pointer0) {
-        g3.pointer0 = g3.pointer1;
-        delete g3.pointer1;
-      }
-      if (g3.pointer0) {
-        g3.pointer0[1] = _transform.invert(g3.pointer0[0]);
+    function getOptions(allOptions) {
+      var stringsField = field.resolveReference("stringsCrossReference");
+      if (!(field.options || stringsField.options)) return [];
+      let options2;
+      if (allOptions !== true) {
+        options2 = field.options || stringsField.options;
       } else {
-        g3.end(d3_event);
+        options2 = [].concat(field.options, stringsField.options).filter(Boolean);
       }
+      return options2.map(function(v2) {
+        const labelId = getLabelId(stringsField, v2);
+        return {
+          key: v2,
+          value: stringsField.t(labelId, { default: v2 }),
+          title: stringsField.t("options.".concat(v2, ".description"), { default: v2 }),
+          display: addComboboxIcons(stringsField.t.append(labelId, { default: v2 }), v2),
+          klass: stringsField.hasTextForStringId(labelId) ? "" : "raw-option"
+        };
+      });
     }
-    zoom.wheelDelta = function(_2) {
-      return arguments.length ? (wheelDelta = utilFunctor(+_2), zoom) : wheelDelta;
-    };
-    zoom.filter = function(_2) {
-      return arguments.length ? (filter2 = utilFunctor(!!_2), zoom) : filter2;
-    };
-    zoom.extent = function(_2) {
-      return arguments.length ? (extent = utilFunctor([[+_2[0][0], +_2[0][1]], [+_2[1][0], +_2[1][1]]]), zoom) : extent;
-    };
-    zoom.scaleExtent = function(_2) {
-      return arguments.length ? (scaleExtent[0] = +_2[0], scaleExtent[1] = +_2[1], zoom) : [scaleExtent[0], scaleExtent[1]];
-    };
-    zoom.translateExtent = function(_2) {
-      return arguments.length ? (translateExtent[0][0] = +_2[0][0], translateExtent[1][0] = +_2[1][0], translateExtent[0][1] = +_2[0][1], translateExtent[1][1] = +_2[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
-    };
-    zoom.constrain = function(_2) {
-      return arguments.length ? (constrain = _2, zoom) : constrain;
-    };
-    zoom.interpolate = function(_2) {
-      return arguments.length ? (interpolate = _2, zoom) : interpolate;
-    };
-    zoom._transform = function(_2) {
-      return arguments.length ? (_transform = _2, zoom) : _transform;
-    };
-    return utilRebind(zoom, dispatch14, "on");
-  }
-
-  // modules/util/double_up.js
-  function utilDoubleUp() {
-    var dispatch14 = dispatch_default("doubleUp");
-    var _maxTimespan = 500;
-    var _maxDistance = 20;
-    var _pointer;
-    function pointerIsValidFor(loc) {
-      return (/* @__PURE__ */ new Date()).getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
-      geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
+    function hasStaticValues() {
+      return getOptions().length > 0;
     }
-    function pointerdown(d3_event) {
-      if (d3_event.ctrlKey || d3_event.button === 2)
-        return;
-      var loc = [d3_event.clientX, d3_event.clientY];
-      if (_pointer && !pointerIsValidFor(loc)) {
-        _pointer = void 0;
-      }
-      if (!_pointer) {
-        _pointer = {
-          startLoc: loc,
-          startTime: (/* @__PURE__ */ new Date()).getTime(),
-          upCount: 0,
-          pointerId: d3_event.pointerId
-        };
-      } else {
-        _pointer.pointerId = d3_event.pointerId;
+    function setStaticValues(callback, filter2) {
+      _comboData = getOptions();
+      if (filter2 !== void 0) {
+        _comboData = _comboData.filter(filter2);
       }
+      _comboData = objectDifference(_comboData, _multiData);
+      _combobox.data(_comboData);
+      if (callback) callback(_comboData);
     }
-    function pointerup(d3_event) {
-      if (d3_event.ctrlKey || d3_event.button === 2)
-        return;
-      if (!_pointer || _pointer.pointerId !== d3_event.pointerId)
-        return;
-      _pointer.upCount += 1;
-      if (_pointer.upCount === 2) {
-        var loc = [d3_event.clientX, d3_event.clientY];
-        if (pointerIsValidFor(loc)) {
-          var locInThis = utilFastMouse(this)(d3_event);
-          dispatch14.call("doubleUp", this, d3_event, locInThis);
+    function setTaginfoValues(q2, callback) {
+      var queryFilter = (d2) => d2.value.toLowerCase().includes(q2.toLowerCase()) || d2.key.toLowerCase().includes(q2.toLowerCase());
+      if (hasStaticValues()) {
+        setStaticValues(callback, queryFilter);
+      }
+      var stringsField = field.resolveReference("stringsCrossReference");
+      var fn = _isMulti ? "multikeys" : "values";
+      var query = (_isMulti ? field.key : "") + q2;
+      var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q2.toLowerCase()) === 0;
+      if (hasCountryPrefix) {
+        query = _countryCode + ":";
+      }
+      var params = {
+        debounce: q2 !== "",
+        key: field.key,
+        query
+      };
+      if (_entityIDs.length) {
+        params.geometry = context.graph().geometry(_entityIDs[0]);
+      }
+      services.taginfo[fn](params, function(err, data) {
+        if (err) return;
+        data = data.filter((d2) => field.type !== "typeCombo" || d2.value !== "yes");
+        data = data.filter((d2) => {
+          var value = d2.value;
+          if (_isMulti) {
+            value = value.slice(field.key.length);
+          }
+          return value === restrictTagValueSpelling(value);
+        });
+        var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
+        if (deprecatedValues) {
+          data = data.filter((d2) => !deprecatedValues.includes(d2.value));
         }
-        _pointer = void 0;
+        if (hasCountryPrefix) {
+          data = data.filter((d2) => d2.value.toLowerCase().indexOf(_countryCode + ":") === 0);
+        }
+        const additionalOptions = (field.options || stringsField.options || []).filter((v2) => !data.some((dv) => dv.value === (_isMulti ? field.key + v2 : v2))).map((v2) => ({ value: v2 }));
+        _container.classed("empty-combobox", data.length === 0);
+        _comboData = data.concat(additionalOptions).map(function(d2) {
+          var v2 = d2.value;
+          if (_isMulti) v2 = v2.replace(field.key, "");
+          const labelId = getLabelId(stringsField, v2);
+          var isLocalizable = stringsField.hasTextForStringId(labelId);
+          var label = stringsField.t(labelId, { default: v2 });
+          return {
+            key: v2,
+            value: label,
+            title: stringsField.t("options.".concat(v2, ".description"), { default: isLocalizable ? v2 : d2.title !== label ? d2.title : "" }),
+            display: addComboboxIcons(stringsField.t.append(labelId, { default: v2 }), v2),
+            klass: isLocalizable ? "" : "raw-option"
+          };
+        });
+        _comboData = _comboData.filter(queryFilter);
+        _comboData = objectDifference(_comboData, _multiData);
+        if (callback) callback(_comboData, hasStaticValues());
+      });
+    }
+    function addComboboxIcons(disp, value) {
+      const iconsField = field.resolveReference("iconsCrossReference");
+      if (iconsField.icons) {
+        return function(selection2) {
+          var span = selection2.insert("span", ":first-child").attr("class", "tag-value-icon");
+          if (iconsField.icons[value]) {
+            span.call(svgIcon("#".concat(iconsField.icons[value])));
+          }
+          disp.call(this, selection2);
+        };
       }
+      return disp;
     }
-    function doubleUp(selection2) {
-      if ("PointerEvent" in window) {
-        selection2.on("pointerdown.doubleUp", pointerdown).on("pointerup.doubleUp", pointerup);
+    function setPlaceholder(values) {
+      if (_isMulti || _isSemi) {
+        _staticPlaceholder = field.placeholder() || _t("inspector.add");
       } else {
-        selection2.on("dblclick.doubleUp", function(d3_event) {
-          dispatch14.call("doubleUp", this, d3_event, utilFastMouse(this)(d3_event));
+        var vals = values.map(function(d2) {
+          return d2.value;
+        }).filter(function(s2) {
+          return s2.length < 20;
+        });
+        var placeholders = vals.length > 1 ? vals : values.map(function(d2) {
+          return d2.key;
         });
+        _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(", ");
+      }
+      if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
+        _staticPlaceholder += "\u2026";
+      }
+      var ph;
+      if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
+        ph = _t("inspector.multiple_values");
+      } else {
+        ph = _staticPlaceholder;
       }
+      _container.selectAll("input").attr("placeholder", ph);
+      var hideAdd = !_allowCustomValues && !values.length;
+      _container.selectAll(".chiplist .input-wrap").style("display", hideAdd ? "none" : null);
     }
-    doubleUp.off = function(selection2) {
-      selection2.on("pointerdown.doubleUp", null).on("pointerup.doubleUp", null).on("dblclick.doubleUp", null);
-    };
-    return utilRebind(doubleUp, dispatch14, "on");
-  }
-
-  // modules/renderer/map.js
-  var TILESIZE = 256;
-  var minZoom2 = 2;
-  var maxZoom = 24;
-  var kMin = geoZoomToScale(minZoom2, TILESIZE);
-  var kMax = geoZoomToScale(maxZoom, TILESIZE);
-  function clamp2(num, min3, max3) {
-    return Math.max(min3, Math.min(num, max3));
-  }
-  function rendererMap(context) {
-    var dispatch14 = dispatch_default(
-      "move",
-      "drawn",
-      "crossEditableZoom",
-      "hitMinZoom",
-      "changeHighlighting",
-      "changeAreaFill"
-    );
-    var projection2 = context.projection;
-    var curtainProjection = context.curtainProjection;
-    var drawLayers;
-    var drawPoints;
-    var drawVertices;
-    var drawLines;
-    var drawAreas;
-    var drawMidpoints;
-    var drawLabels;
-    var _selection = select_default2(null);
-    var supersurface = select_default2(null);
-    var wrapper = select_default2(null);
-    var surface = select_default2(null);
-    var _dimensions = [1, 1];
-    var _dblClickZoomEnabled = true;
-    var _redrawEnabled = true;
-    var _gestureTransformStart;
-    var _transformStart = projection2.transform();
-    var _transformLast;
-    var _isTransformed = false;
-    var _minzoom = 0;
-    var _getMouseCoords;
-    var _lastPointerEvent;
-    var _lastWithinEditableZoom;
-    var _pointerDown = false;
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    var _zoomerPannerFunction = "PointerEvent" in window ? utilZoomPan : zoom_default2;
-    var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(value_default).filter(zoomEventFilter).on("zoom.map", zoomPan2).on("start.map", function(d3_event) {
-      _pointerDown = d3_event && (d3_event.type === "pointerdown" || d3_event.sourceEvent && d3_event.sourceEvent.type === "pointerdown");
-    }).on("end.map", function() {
-      _pointerDown = false;
-    });
-    var _doubleUpHandler = utilDoubleUp();
-    var scheduleRedraw = throttle_default(redraw, 750);
-    function cancelPendingRedraw() {
-      scheduleRedraw.cancel();
+    function change() {
+      var t2 = {};
+      var val;
+      if (_isMulti || _isSemi) {
+        var vals;
+        if (_isMulti) {
+          vals = [tagValue(utilGetSetValue(_input))];
+        } else if (_isSemi) {
+          val = tagValue(utilGetSetValue(_input)) || "";
+          val = val.replace(/,/g, ";");
+          vals = val.split(";");
+        }
+        vals = vals.filter(Boolean);
+        if (!vals.length) return;
+        _container.classed("active", false);
+        utilGetSetValue(_input, "");
+        if (_isMulti) {
+          utilArrayUniq(vals).forEach(function(v2) {
+            var key = (field.key || "") + v2;
+            if (_tags) {
+              var old = _tags[key];
+              if (typeof old === "string" && old.toLowerCase() !== "no") return;
+            }
+            key = context.cleanTagKey(key);
+            field.keys.push(key);
+            t2[key] = "yes";
+          });
+        } else if (_isSemi) {
+          var arr = _multiData.map(function(d2) {
+            return d2.key;
+          });
+          arr = arr.concat(vals);
+          t2[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(";"));
+        }
+        window.setTimeout(function() {
+          _input.node().focus();
+        }, 10);
+      } else {
+        var rawValue = utilGetSetValue(_input);
+        if (!rawValue && Array.isArray(_tags[field.key])) return;
+        val = context.cleanTagValue(tagValue(rawValue));
+        t2[field.key] = val || void 0;
+      }
+      dispatch14.call("change", this, t2);
     }
-    function map2(selection2) {
-      _selection = selection2;
-      context.on("change.map", immediateRedraw);
-      var osm = context.connection();
-      if (osm) {
-        osm.on("change.map", immediateRedraw);
+    function removeMultikey(d3_event, d2) {
+      d3_event.preventDefault();
+      d3_event.stopPropagation();
+      var t2 = {};
+      if (_isMulti) {
+        t2[d2.key] = void 0;
+      } else if (_isSemi) {
+        var arr = _multiData.map(function(md) {
+          return md.key === d2.key ? null : md.key;
+        }).filter(Boolean);
+        arr = utilArrayUniq(arr);
+        t2[field.key] = arr.length ? arr.join(";") : void 0;
+        _lengthIndicator.update(t2[field.key]);
       }
-      function didUndoOrRedo(targetTransform) {
-        var mode = context.mode().id;
-        if (mode !== "browse" && mode !== "select")
-          return;
-        if (targetTransform) {
-          map2.transformEase(targetTransform);
-        }
+      dispatch14.call("change", this, t2);
+    }
+    function invertMultikey(d3_event, d2) {
+      d3_event.preventDefault();
+      d3_event.stopPropagation();
+      var t2 = {};
+      if (_isMulti) {
+        t2[d2.key] = _tags[d2.key] === "yes" ? "no" : "yes";
       }
-      context.history().on("merge.map", function() {
-        scheduleRedraw();
-      }).on("change.map", immediateRedraw).on("undone.map", function(stack, fromStack) {
-        didUndoOrRedo(fromStack.transform);
-      }).on("redone.map", function(stack) {
-        didUndoOrRedo(stack.transform);
-      });
-      context.background().on("change.map", immediateRedraw);
-      context.features().on("redraw.map", immediateRedraw);
-      drawLayers.on("change.map", function() {
-        context.background().updateImagery();
-        immediateRedraw();
-      });
-      selection2.on("wheel.map mousewheel.map", function(d3_event) {
-        d3_event.preventDefault();
-      }).call(_zoomerPanner).call(_zoomerPanner.transform, projection2.transform()).on("dblclick.zoom", null);
-      map2.supersurface = supersurface = selection2.append("div").attr("class", "supersurface").call(utilSetTransform, 0, 0);
-      wrapper = supersurface.append("div").attr("class", "layer layer-data");
-      map2.surface = surface = wrapper.call(drawLayers).selectAll(".surface");
-      surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + "down.zoom", function(d3_event) {
-        _lastPointerEvent = d3_event;
-        if (d3_event.button === 2) {
-          d3_event.stopPropagation();
-        }
-      }, true).on(_pointerPrefix + "up.zoom", function(d3_event) {
-        _lastPointerEvent = d3_event;
-        if (resetTransform()) {
-          immediateRedraw();
-        }
-      }).on(_pointerPrefix + "move.map", function(d3_event) {
-        _lastPointerEvent = d3_event;
-      }).on(_pointerPrefix + "over.vertices", function(d3_event) {
-        if (map2.editableDataEnabled() && !_isTransformed) {
-          var hover = d3_event.target.__data__;
-          surface.call(drawVertices.drawHover, context.graph(), hover, map2.extent());
-          dispatch14.call("drawn", this, { full: false });
+      dispatch14.call("change", this, t2);
+    }
+    function combo(selection2) {
+      _container = selection2.selectAll(".form-field-input-wrap").data([0]);
+      var type2 = _isMulti || _isSemi ? "multicombo" : "combo";
+      _container = _container.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + type2).merge(_container);
+      if (_isMulti || _isSemi) {
+        _container = _container.selectAll(".chiplist").data([0]);
+        var listClass = "chiplist";
+        if (field.key === "destination" || field.key === "via") {
+          listClass += " full-line-chips";
         }
-      }).on(_pointerPrefix + "out.vertices", function(d3_event) {
-        if (map2.editableDataEnabled() && !_isTransformed) {
-          var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
-          surface.call(drawVertices.drawHover, context.graph(), hover, map2.extent());
-          dispatch14.call("drawn", this, { full: false });
+        _container = _container.enter().append("ul").attr("class", listClass).on("click", function() {
+          window.setTimeout(function() {
+            _input.node().focus();
+          }, 10);
+        }).merge(_container);
+        _inputWrap = _container.selectAll(".input-wrap").data([0]);
+        _inputWrap = _inputWrap.enter().append("li").attr("class", "input-wrap").merge(_inputWrap);
+        var hideAdd = !_allowCustomValues && !_comboData.length;
+        _inputWrap.style("display", hideAdd ? "none" : null);
+        _input = _inputWrap.selectAll("input").data([0]);
+      } else {
+        _input = _container.selectAll("input").data([0]);
+      }
+      _input = _input.enter().append("input").attr("type", "text").attr("id", field.domId).call(utilNoAuto).call(initCombo, _container).merge(_input);
+      if (_isSemi) {
+        _inputWrap.call(_lengthIndicator);
+      } else if (!_isMulti) {
+        _container.call(_lengthIndicator);
+      }
+      if (_isNetwork) {
+        var extent = combinedEntityExtent();
+        var countryCode = extent && iso1A2Code(extent.center());
+        _countryCode = countryCode && countryCode.toLowerCase();
+      }
+      _input.on("change", change).on("blur", change).on("input", function() {
+        let val = utilGetSetValue(_input);
+        updateIcon(val);
+        if (_isSemi && _tags[field.key]) {
+          val += ";" + _tags[field.key];
         }
+        _lengthIndicator.update(val);
       });
-      var detected = utilDetect();
-      if ("GestureEvent" in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
-      // but we only need to do this on desktop Safari anyway. – #7694
-      !detected.isMobileWebKit) {
-        surface.on("gesturestart.surface", function(d3_event) {
-          d3_event.preventDefault();
-          _gestureTransformStart = projection2.transform();
-        }).on("gesturechange.surface", gestureChange);
-      }
-      updateAreaFill();
-      _doubleUpHandler.on("doubleUp.map", function(d3_event, p02) {
-        if (!_dblClickZoomEnabled)
-          return;
-        if (typeof d3_event.target.__data__ === "object" && // or area fills
-        !select_default2(d3_event.target).classed("fill"))
-          return;
-        var zoomOut2 = d3_event.shiftKey;
-        var t2 = projection2.transform();
-        var p1 = t2.invert(p02);
-        t2 = t2.scale(zoomOut2 ? 0.5 : 2);
-        t2.x = p02[0] - p1[0] * t2.k;
-        t2.y = p02[1] - p1[1] * t2.k;
-        map2.transformEase(t2);
+      _input.on("keydown.field", function(d3_event) {
+        switch (d3_event.keyCode) {
+          case 13:
+            _input.node().blur();
+            d3_event.stopPropagation();
+            break;
+        }
       });
-      context.on("enter.map", function() {
-        if (!map2.editableDataEnabled(
-          true
-          /* skip zoom check */
-        ))
-          return;
-        if (_isTransformed)
-          return;
-        var graph = context.graph();
-        var selectedAndParents = {};
-        context.selectedIDs().forEach(function(id2) {
-          var entity = graph.hasEntity(id2);
-          if (entity) {
-            selectedAndParents[entity.id] = entity;
-            if (entity.type === "node") {
-              graph.parentWays(entity).forEach(function(parent) {
-                selectedAndParents[parent.id] = parent;
-              });
-            }
-          }
+      if (_isMulti || _isSemi) {
+        _combobox.on("accept", function() {
+          _input.node().blur();
+          _input.node().focus();
         });
-        var data = Object.values(selectedAndParents);
-        var filter2 = function(d2) {
-          return d2.id in selectedAndParents;
-        };
-        data = context.features().filter(data, graph);
-        surface.call(drawVertices.drawSelected, graph, map2.extent()).call(drawLines, graph, data, filter2).call(drawAreas, graph, data, filter2).call(drawMidpoints, graph, data, filter2, map2.trimmedExtent());
-        dispatch14.call("drawn", this, { full: false });
-        scheduleRedraw();
+        _input.on("focus", function() {
+          _container.classed("active", true);
+        });
+      }
+      _combobox.on("cancel", function() {
+        _input.node().blur();
+      }).on("update", function() {
+        updateIcon(utilGetSetValue(_input));
       });
-      map2.dimensions(utilGetDimensions(selection2));
     }
-    function zoomEventFilter(d3_event) {
-      if (d3_event.type === "mousedown") {
-        var hasOrphan = false;
-        var listeners = window.__on;
-        for (var i3 = 0; i3 < listeners.length; i3++) {
-          var listener = listeners[i3];
-          if (listener.name === "zoom" && listener.type === "mouseup") {
-            hasOrphan = true;
-            break;
-          }
+    function updateIcon(value) {
+      value = tagValue(value);
+      let container = _container;
+      if (field.type === "multiCombo" || field.type === "semiCombo") {
+        container = _container.select(".input-wrap");
+      }
+      const iconsField = field.resolveReference("iconsCrossReference");
+      if (iconsField.icons) {
+        container.selectAll(".tag-value-icon").remove();
+        if (iconsField.icons[value]) {
+          container.selectAll(".tag-value-icon").data([value]).enter().insert("div", "input").attr("class", "tag-value-icon").call(svgIcon("#".concat(iconsField.icons[value])));
         }
-        if (hasOrphan) {
-          var event = window.CustomEvent;
-          if (event) {
-            event = new event("mouseup");
+      }
+    }
+    combo.tags = function(tags) {
+      _tags = tags;
+      var stringsField = field.resolveReference("stringsCrossReference");
+      var isMixed = Array.isArray(tags[field.key]);
+      var showsValue = (value) => !isMixed && value && !(field.type === "typeCombo" && value === "yes");
+      var isRawValue = (value) => showsValue(value) && !stringsField.hasTextForStringId("options.".concat(value)) && !stringsField.hasTextForStringId("options.".concat(value, ".title"));
+      var isKnownValue = (value) => showsValue(value) && !isRawValue(value);
+      var isReadOnly = !_allowCustomValues;
+      if (_isMulti || _isSemi) {
+        _multiData = [];
+        var maxLength;
+        if (_isMulti) {
+          for (var k2 in tags) {
+            if (field.key && k2.indexOf(field.key) !== 0) continue;
+            if (!field.key && field.keys.indexOf(k2) === -1) continue;
+            var v2 = tags[k2];
+            var suffix = field.key ? k2.slice(field.key.length) : k2;
+            _multiData.push({
+              key: k2,
+              value: displayValue(suffix),
+              display: addComboboxIcons(renderValue(suffix), suffix),
+              state: typeof v2 === "string" ? v2.toLowerCase() : "",
+              isMixed: Array.isArray(v2)
+            });
+          }
+          if (field.key) {
+            field.keys = _multiData.map(function(d2) {
+              return d2.key;
+            });
+            maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
           } else {
-            event = window.document.createEvent("Event");
-            event.initEvent("mouseup", false, false);
+            maxLength = context.maxCharsForTagKey();
+          }
+        } else if (_isSemi) {
+          var allValues = [];
+          var commonValues;
+          if (Array.isArray(tags[field.key])) {
+            tags[field.key].forEach(function(tagVal) {
+              var thisVals = utilArrayUniq((tagVal || "").split(";")).filter(Boolean);
+              allValues = allValues.concat(thisVals);
+              if (!commonValues) {
+                commonValues = thisVals;
+              } else {
+                commonValues = commonValues.filter((value) => thisVals.includes(value));
+              }
+            });
+            allValues = utilArrayUniq(allValues).filter(Boolean);
+          } else {
+            allValues = utilArrayUniq((tags[field.key] || "").split(";")).filter(Boolean);
+            commonValues = allValues;
+          }
+          _multiData = allValues.map(function(v3) {
+            return {
+              key: v3,
+              value: displayValue(v3),
+              display: addComboboxIcons(renderValue(v3), v3),
+              isMixed: !commonValues.includes(v3)
+            };
+          });
+          var currLength = utilUnicodeCharsCount(commonValues.join(";"));
+          maxLength = context.maxCharsForTagValue() - currLength;
+          if (currLength > 0) {
+            maxLength -= 1;
           }
-          event.view = window;
-          window.dispatchEvent(event);
         }
-      }
-      return d3_event.button !== 2;
-    }
-    function pxCenter() {
-      return [_dimensions[0] / 2, _dimensions[1] / 2];
-    }
-    function drawEditable(difference2, extent) {
-      var mode = context.mode();
-      var graph = context.graph();
-      var features = context.features();
-      var all = context.history().intersects(map2.extent());
-      var fullRedraw = false;
-      var data;
-      var set4;
-      var filter2;
-      var applyFeatureLayerFilters = true;
-      if (map2.isInWideSelection()) {
-        data = [];
-        utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function(id2) {
-          var entity = context.hasEntity(id2);
-          if (entity)
-            data.push(entity);
+        maxLength = Math.max(0, maxLength);
+        var hideAdd = maxLength <= 0 || !_allowCustomValues && !_comboData.length;
+        _container.selectAll(".chiplist .input-wrap").style("display", hideAdd ? "none" : null);
+        var allowDragAndDrop = _isSemi && !Array.isArray(tags[field.key]);
+        var chips = _container.selectAll(".chip").data(_multiData);
+        chips.exit().remove();
+        var enter = chips.enter().insert("li", ".input-wrap").attr("class", "chip");
+        enter.append("span");
+        const field_buttons = enter.append("div").attr("class", "field_buttons");
+        field_buttons.append("a").attr("class", "remove");
+        chips = chips.merge(enter).order().classed("raw-value", function(d2) {
+          var k3 = d2.key;
+          if (_isMulti) k3 = k3.replace(field.key, "");
+          return !stringsField.hasTextForStringId("options." + k3);
+        }).classed("draggable", allowDragAndDrop).classed("mixed", function(d2) {
+          return d2.isMixed;
+        }).attr("title", function(d2) {
+          if (d2.isMixed) {
+            return _t("inspector.unshared_value_tooltip");
+          }
+          if (!["yes", "no"].includes(d2.state)) {
+            return d2.state;
+          }
+          return null;
+        }).classed("negated", (d2) => d2.state === "no");
+        if (!_isSemi) {
+          chips.selectAll("input[type=checkbox]").remove();
+          chips.insert("input", "span").attr("type", "checkbox").property("checked", (d2) => d2.state === "yes").property("indeterminate", (d2) => d2.isMixed || !["yes", "no"].includes(d2.state)).on("click", invertMultikey);
+        }
+        if (allowDragAndDrop) {
+          registerDragAndDrop(chips);
+        }
+        chips.each(function(d2) {
+          const selection2 = select_default2(this);
+          const text_span = selection2.select("span");
+          const field_buttons2 = selection2.select(".field_buttons");
+          const clean_value = d2.value.trim();
+          text_span.text("");
+          if (!field_buttons2.select("button").empty()) {
+            field_buttons2.select("button").remove();
+          }
+          if (clean_value.startsWith("https://")) {
+            text_span.text(clean_value);
+            field_buttons2.append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", () => _t("icons.visit_website")).attr("aria-label", () => _t("icons.visit_website")).on("click", function(d3_event) {
+              d3_event.preventDefault();
+              window.open(clean_value, "_blank");
+            });
+            return;
+          }
+          if (d2.display) {
+            d2.display(text_span);
+            return;
+          }
+          text_span.text(d2.value);
         });
-        fullRedraw = true;
-        filter2 = utilFunctor(true);
-        applyFeatureLayerFilters = false;
-      } else if (difference2) {
-        var complete = difference2.complete(map2.extent());
-        data = Object.values(complete).filter(Boolean);
-        set4 = new Set(Object.keys(complete));
-        filter2 = function(d2) {
-          return set4.has(d2.id);
-        };
-        features.clear(data);
+        chips.select("a.remove").attr("href", "#").on("click", removeMultikey).attr("class", "remove").text("\xD7");
+        updateIcon("");
       } else {
-        if (features.gatherStats(all, graph, _dimensions)) {
-          extent = void 0;
+        var mixedValues = isMixed && tags[field.key].map(function(val) {
+          return displayValue(val);
+        }).filter(Boolean);
+        utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : "").data([tags[field.key]]).classed("raw-value", isRawValue).classed("known-value", isKnownValue).attr("readonly", isReadOnly ? "readonly" : void 0).attr("title", isMixed ? mixedValues.join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : _staticPlaceholder || "").classed("mixed", isMixed).on("keydown.deleteCapture", function(d3_event) {
+          if (isReadOnly && isKnownValue(tags[field.key]) && (d3_event.keyCode === utilKeybinding.keyCodes["\u232B"] || d3_event.keyCode === utilKeybinding.keyCodes["\u2326"])) {
+            d3_event.preventDefault();
+            d3_event.stopPropagation();
+            var t2 = {};
+            t2[field.key] = void 0;
+            dispatch14.call("change", this, t2);
+          }
+        });
+        if (!Array.isArray(tags[field.key])) {
+          updateIcon(tags[field.key]);
         }
-        if (extent) {
-          data = context.history().intersects(map2.extent().intersection(extent));
-          set4 = new Set(data.map(function(entity) {
-            return entity.id;
-          }));
-          filter2 = function(d2) {
-            return set4.has(d2.id);
-          };
-        } else {
-          data = all;
-          fullRedraw = true;
-          filter2 = utilFunctor(true);
+        if (!isMixed) {
+          _lengthIndicator.update(tags[field.key]);
         }
       }
-      if (applyFeatureLayerFilters) {
-        data = features.filter(data, graph);
-      } else {
-        context.features().resetStats();
-      }
-      if (mode && mode.id === "select") {
-        surface.call(drawVertices.drawSelected, graph, map2.extent());
-      }
-      surface.call(drawVertices, graph, data, filter2, map2.extent(), fullRedraw).call(drawLines, graph, data, filter2).call(drawAreas, graph, data, filter2).call(drawMidpoints, graph, data, filter2, map2.trimmedExtent()).call(drawLabels, graph, data, filter2, _dimensions, fullRedraw).call(drawPoints, graph, data, filter2);
-      dispatch14.call("drawn", this, { full: true });
-    }
-    map2.init = function() {
-      drawLayers = svgLayers(projection2, context);
-      drawPoints = svgPoints(projection2, context);
-      drawVertices = svgVertices(projection2, context);
-      drawLines = svgLines(projection2, context);
-      drawAreas = svgAreas(projection2, context);
-      drawMidpoints = svgMidpoints(projection2, context);
-      drawLabels = svgLabels(projection2, context);
+      const refreshStyles = () => {
+        _input.data([tagValue(utilGetSetValue(_input))]).classed("raw-value", isRawValue).classed("known-value", isKnownValue);
+      };
+      _input.on("input.refreshStyles", refreshStyles);
+      _combobox.on("update.refreshStyles", refreshStyles);
+      refreshStyles();
     };
-    function editOff() {
-      context.features().resetStats();
-      surface.selectAll(".layer-osm *").remove();
-      surface.selectAll(".layer-touch:not(.markers) *").remove();
-      var allowed = {
-        "browse": true,
-        "save": true,
-        "select-note": true,
-        "select-data": true,
-        "select-error": true
-      };
-      var mode = context.mode();
-      if (mode && !allowed[mode.id]) {
-        context.enter(modeBrowse(context));
-      }
-      dispatch14.call("drawn", this, { full: true });
-    }
-    function gestureChange(d3_event) {
-      var e3 = d3_event;
-      e3.preventDefault();
-      var props = {
-        deltaMode: 0,
-        // dummy values to ignore in zoomPan
-        deltaY: 1,
-        // dummy values to ignore in zoomPan
-        clientX: e3.clientX,
-        clientY: e3.clientY,
-        screenX: e3.screenX,
-        screenY: e3.screenY,
-        x: e3.x,
-        y: e3.y
-      };
-      var e22 = new WheelEvent("wheel", props);
-      e22._scale = e3.scale;
-      e22._rotation = e3.rotation;
-      _selection.node().dispatchEvent(e22);
-    }
-    function zoomPan2(event, key, transform2) {
-      var source = event && event.sourceEvent || event;
-      var eventTransform = transform2 || event && event.transform;
-      var x2 = eventTransform.x;
-      var y2 = eventTransform.y;
-      var k2 = eventTransform.k;
-      if (source && source.type === "wheel") {
-        if (_pointerDown)
-          return;
-        var detected = utilDetect();
-        var dX = source.deltaX;
-        var dY = source.deltaY;
-        var x22 = x2;
-        var y22 = y2;
-        var k22 = k2;
-        var t0, p02, p1;
-        if (source.deltaMode === 1) {
-          var lines = Math.abs(source.deltaY);
-          var sign2 = source.deltaY > 0 ? 1 : -1;
-          dY = sign2 * clamp2(
-            Math.exp((lines - 1) * 0.75) * 4.000244140625,
-            4.000244140625,
-            // min
-            350.000244140625
-            // max
-          );
-          if (detected.os !== "mac") {
-            dY *= 5;
-          }
-          t0 = _isTransformed ? _transformLast : _transformStart;
-          p02 = _getMouseCoords(source);
-          p1 = t0.invert(p02);
-          k22 = t0.k * Math.pow(2, -dY / 500);
-          k22 = clamp2(k22, kMin, kMax);
-          x22 = p02[0] - p1[0] * k22;
-          y22 = p02[1] - p1[1] * k22;
-        } else if (source._scale) {
-          t0 = _gestureTransformStart;
-          p02 = _getMouseCoords(source);
-          p1 = t0.invert(p02);
-          k22 = t0.k * source._scale;
-          k22 = clamp2(k22, kMin, kMax);
-          x22 = p02[0] - p1[0] * k22;
-          y22 = p02[1] - p1[1] * k22;
-        } else if (source.ctrlKey && !isInteger(dY)) {
-          dY *= 6;
-          t0 = _isTransformed ? _transformLast : _transformStart;
-          p02 = _getMouseCoords(source);
-          p1 = t0.invert(p02);
-          k22 = t0.k * Math.pow(2, -dY / 500);
-          k22 = clamp2(k22, kMin, kMax);
-          x22 = p02[0] - p1[0] * k22;
-          y22 = p02[1] - p1[1] * k22;
-        } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
-          t0 = _isTransformed ? _transformLast : _transformStart;
-          p02 = _getMouseCoords(source);
-          p1 = t0.invert(p02);
-          k22 = t0.k * Math.pow(2, -dY / 500);
-          k22 = clamp2(k22, kMin, kMax);
-          x22 = p02[0] - p1[0] * k22;
-          y22 = p02[1] - p1[1] * k22;
-        } else if (detected.os === "mac" && detected.browser !== "Firefox" && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
-          p1 = projection2.translate();
-          x22 = p1[0] - dX;
-          y22 = p1[1] - dY;
-          k22 = projection2.scale();
-          k22 = clamp2(k22, kMin, kMax);
-        }
-        if (x22 !== x2 || y22 !== y2 || k22 !== k2) {
-          x2 = x22;
-          y2 = y22;
-          k2 = k22;
-          eventTransform = identity2.translate(x22, y22).scale(k22);
-          if (_zoomerPanner._transform) {
-            _zoomerPanner._transform(eventTransform);
+    function registerDragAndDrop(selection2) {
+      var dragOrigin, targetIndex;
+      selection2.call(
+        drag_default().on("start", function(d3_event) {
+          dragOrigin = {
+            x: d3_event.x,
+            y: d3_event.y
+          };
+          targetIndex = null;
+        }).on("drag", function(d3_event) {
+          var x2 = d3_event.x - dragOrigin.x, y2 = d3_event.y - dragOrigin.y;
+          if (!select_default2(this).classed("dragging") && // don't display drag until dragging beyond a distance threshold
+          Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2)) <= 5) return;
+          var index = selection2.nodes().indexOf(this);
+          select_default2(this).classed("dragging", true);
+          targetIndex = null;
+          var targetIndexOffsetTop = null;
+          var draggedTagWidth = select_default2(this).node().offsetWidth;
+          if (field.key === "destination" || field.key === "via") {
+            _container.selectAll(".chip").style("transform", function(d2, index2) {
+              var node = select_default2(this).node();
+              if (index === index2) {
+                return "translate(" + x2 + "px, " + y2 + "px)";
+              } else if (index2 > index && d3_event.y > node.offsetTop) {
+                if (targetIndex === null || index2 > targetIndex) {
+                  targetIndex = index2;
+                }
+                return "translateY(-100%)";
+              } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
+                if (targetIndex === null || index2 < targetIndex) {
+                  targetIndex = index2;
+                }
+                return "translateY(100%)";
+              }
+              return null;
+            });
           } else {
-            _selection.node().__zoom = eventTransform;
+            _container.selectAll(".chip").each(function(d2, index2) {
+              var node = select_default2(this).node();
+              if (index !== index2 && d3_event.x < node.offsetLeft + node.offsetWidth + 5 && d3_event.x > node.offsetLeft && d3_event.y < node.offsetTop + node.offsetHeight && d3_event.y > node.offsetTop) {
+                targetIndex = index2;
+                targetIndexOffsetTop = node.offsetTop;
+              }
+            }).style("transform", function(d2, index2) {
+              var node = select_default2(this).node();
+              if (index === index2) {
+                return "translate(" + x2 + "px, " + y2 + "px)";
+              }
+              if (node.offsetTop === targetIndexOffsetTop) {
+                if (index2 < index && index2 >= targetIndex) {
+                  return "translateX(" + draggedTagWidth + "px)";
+                } else if (index2 > index && index2 <= targetIndex) {
+                  return "translateX(-" + draggedTagWidth + "px)";
+                }
+              }
+              return null;
+            });
           }
-        }
-      }
-      if (_transformStart.x === x2 && _transformStart.y === y2 && _transformStart.k === k2) {
-        return;
-      }
-      if (geoScaleToZoom(k2, TILESIZE) < _minzoom) {
-        surface.interrupt();
-        dispatch14.call("hitMinZoom", this, map2);
-        setCenterZoom(map2.center(), context.minEditableZoom(), 0, true);
-        scheduleRedraw();
-        dispatch14.call("move", this, map2);
-        return;
-      }
-      projection2.transform(eventTransform);
-      var withinEditableZoom = map2.withinEditableZoom();
-      if (_lastWithinEditableZoom !== withinEditableZoom) {
-        if (_lastWithinEditableZoom !== void 0) {
-          dispatch14.call("crossEditableZoom", this, withinEditableZoom);
-        }
-        _lastWithinEditableZoom = withinEditableZoom;
-      }
-      var scale = k2 / _transformStart.k;
-      var tX = (x2 / scale - _transformStart.x) * scale;
-      var tY = (y2 / scale - _transformStart.y) * scale;
-      if (context.inIntro()) {
-        curtainProjection.transform({
-          x: x2 - tX,
-          y: y2 - tY,
-          k: k2
-        });
-      }
-      if (source) {
-        _lastPointerEvent = event;
-      }
-      _isTransformed = true;
-      _transformLast = eventTransform;
-      utilSetTransform(supersurface, tX, tY, scale);
-      scheduleRedraw();
-      dispatch14.call("move", this, map2);
-      function isInteger(val) {
-        return typeof val === "number" && isFinite(val) && Math.floor(val) === val;
-      }
+        }).on("end", function() {
+          if (!select_default2(this).classed("dragging")) {
+            return;
+          }
+          var index = selection2.nodes().indexOf(this);
+          select_default2(this).classed("dragging", false);
+          _container.selectAll(".chip").style("transform", null);
+          if (typeof targetIndex === "number") {
+            var element = _multiData[index];
+            _multiData.splice(index, 1);
+            _multiData.splice(targetIndex, 0, element);
+            var t2 = {};
+            if (_multiData.length) {
+              t2[field.key] = _multiData.map(function(element2) {
+                return element2.key;
+              }).join(";");
+            } else {
+              t2[field.key] = void 0;
+            }
+            dispatch14.call("change", this, t2);
+          }
+          dragOrigin = void 0;
+          targetIndex = void 0;
+        })
+      );
     }
-    function resetTransform() {
-      if (!_isTransformed)
-        return false;
-      utilSetTransform(supersurface, 0, 0);
-      _isTransformed = false;
-      if (context.inIntro()) {
-        curtainProjection.transform(projection2.transform());
-      }
-      return true;
+    combo.focus = function() {
+      _input.node().focus();
+    };
+    combo.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return combo;
+    };
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
     }
-    function redraw(difference2, extent) {
-      if (surface.empty() || !_redrawEnabled)
-        return;
-      if (resetTransform()) {
-        difference2 = extent = void 0;
-      }
-      var zoom = map2.zoom();
-      var z2 = String(~~zoom);
-      if (surface.attr("data-zoom") !== z2) {
-        surface.attr("data-zoom", z2);
-      }
-      var lat = map2.center()[1];
-      var lowzoom = linear3().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
-      surface.classed("low-zoom", zoom <= lowzoom(lat));
-      if (!difference2) {
-        supersurface.call(context.background());
-        wrapper.call(drawLayers);
-      }
-      if (map2.editableDataEnabled() || map2.isInWideSelection()) {
-        context.loadTiles(projection2);
-        drawEditable(difference2, extent);
+    return utilRebind(combo, dispatch14, "on");
+  }
+
+  // modules/ui/account.js
+  function uiAccount(context) {
+    const osm = context.connection();
+    function updateUserDetails(selection2) {
+      if (!osm) return;
+      if (!osm.authenticated()) {
+        render(selection2, null);
       } else {
-        editOff();
+        osm.userDetails((err, user) => render(selection2, user));
       }
-      _transformStart = projection2.transform();
-      return map2;
     }
-    var immediateRedraw = function(difference2, extent) {
-      if (!difference2 && !extent)
-        cancelPendingRedraw();
-      redraw(difference2, extent);
-    };
-    map2.lastPointerEvent = function() {
-      return _lastPointerEvent;
-    };
-    map2.mouse = function(d3_event) {
-      var event = d3_event || _lastPointerEvent;
-      if (event) {
-        var s2;
-        while (s2 = event.sourceEvent) {
-          event = s2;
+    function render(selection2, user) {
+      let userInfo = selection2.select(".userInfo");
+      let loginLogout = selection2.select(".loginLogout");
+      if (user) {
+        userInfo.html("").classed("hide", false);
+        let userLink = userInfo.append("a").attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
+        if (user.image_url) {
+          userLink.append("img").attr("class", "icon pre-text user-icon").attr("src", user.image_url);
+        } else {
+          userLink.call(svgIcon("#iD-icon-avatar", "pre-text light"));
         }
-        return _getMouseCoords(event);
-      }
-      return null;
-    };
-    map2.mouseCoordinates = function() {
-      var coord2 = map2.mouse() || pxCenter();
-      return projection2.invert(coord2);
-    };
-    map2.dblclickZoomEnable = function(val) {
-      if (!arguments.length)
-        return _dblClickZoomEnabled;
-      _dblClickZoomEnabled = val;
-      return map2;
-    };
-    map2.redrawEnable = function(val) {
-      if (!arguments.length)
-        return _redrawEnabled;
-      _redrawEnabled = val;
-      return map2;
-    };
-    map2.isTransformed = function() {
-      return _isTransformed;
-    };
-    function setTransform(t2, duration, force) {
-      var t3 = projection2.transform();
-      if (!force && t2.k === t3.k && t2.x === t3.x && t2.y === t3.y)
-        return false;
-      if (duration) {
-        _selection.transition().duration(duration).on("start", function() {
-          map2.startEase();
-        }).call(_zoomerPanner.transform, identity2.translate(t2.x, t2.y).scale(t2.k));
+        userLink.append("span").attr("class", "label").text(user.display_name);
+        loginLogout.classed("hide", false).select("a").text(_t("logout")).on("click", (e3) => {
+          e3.preventDefault();
+          osm.logout();
+          tryLogout();
+        });
       } else {
-        projection2.transform(t2);
-        _transformStart = t2;
-        _selection.call(_zoomerPanner.transform, _transformStart);
+        userInfo.html("").classed("hide", true);
+        loginLogout.classed("hide", false).select("a").text(_t("login")).on("click", (e3) => {
+          e3.preventDefault();
+          osm.authenticate();
+        });
       }
-      return true;
     }
-    function setCenterZoom(loc2, z2, duration, force) {
-      var c2 = map2.center();
-      var z3 = map2.zoom();
-      if (loc2[0] === c2[0] && loc2[1] === c2[1] && z2 === z3 && !force)
-        return false;
-      var proj = geoRawMercator().transform(projection2.transform());
-      var k2 = clamp2(geoZoomToScale(z2, TILESIZE), kMin, kMax);
-      proj.scale(k2);
-      var t2 = proj.translate();
-      var point2 = proj(loc2);
-      var center = pxCenter();
-      t2[0] += center[0] - point2[0];
-      t2[1] += center[1] - point2[1];
-      return setTransform(identity2.translate(t2[0], t2[1]).scale(k2), duration, force);
+    function tryLogout() {
+      if (!osm) return;
+      const url = osm.getUrlRoot() + "/logout?referer=%2Flogin";
+      const w2 = 600;
+      const h2 = 550;
+      const settings = [
+        ["width", w2],
+        ["height", h2],
+        ["left", window.screen.width / 2 - w2 / 2],
+        ["top", window.screen.height / 2 - h2 / 2]
+      ].map((x2) => x2.join("=")).join(",");
+      window.open(url, "_blank", settings);
     }
-    map2.pan = function(delta, duration) {
-      var t2 = projection2.translate();
-      var k2 = projection2.scale();
-      t2[0] += delta[0];
-      t2[1] += delta[1];
-      if (duration) {
-        _selection.transition().duration(duration).on("start", function() {
-          map2.startEase();
-        }).call(_zoomerPanner.transform, identity2.translate(t2[0], t2[1]).scale(k2));
-      } else {
-        projection2.translate(t2);
-        _transformStart = projection2.transform();
-        _selection.call(_zoomerPanner.transform, _transformStart);
-        dispatch14.call("move", this, map2);
-        immediateRedraw();
-      }
-      return map2;
-    };
-    map2.dimensions = function(val) {
-      if (!arguments.length)
-        return _dimensions;
-      _dimensions = val;
-      drawLayers.dimensions(_dimensions);
-      context.background().dimensions(_dimensions);
-      projection2.clipExtent([[0, 0], _dimensions]);
-      _getMouseCoords = utilFastMouse(supersurface.node());
-      scheduleRedraw();
-      return map2;
+    return function(selection2) {
+      if (!osm) return;
+      selection2.append("li").attr("class", "userInfo").classed("hide", true);
+      selection2.append("li").attr("class", "loginLogout").classed("hide", true).append("a").attr("href", "#");
+      osm.on("change.account", () => updateUserDetails(selection2));
+      updateUserDetails(selection2);
     };
-    function zoomIn(delta) {
-      setCenterZoom(map2.center(), ~~map2.zoom() + delta, 250, true);
+  }
+
+  // modules/ui/attribution.js
+  function uiAttribution(context) {
+    let _selection = select_default2(null);
+    function render(selection2, data, klass) {
+      let div = selection2.selectAll(".".concat(klass)).data([0]);
+      div = div.enter().append("div").attr("class", klass).merge(div);
+      let attributions = div.selectAll(".attribution").data(data, (d2) => d2.id);
+      attributions.exit().remove();
+      attributions = attributions.enter().append("span").attr("class", "attribution").each((d2, i3, nodes) => {
+        let attribution = select_default2(nodes[i3]);
+        if (d2.terms_html) {
+          attribution.html(d2.terms_html);
+          return;
+        }
+        if (d2.terms_url) {
+          attribution = attribution.append("a").attr("href", d2.terms_url).attr("target", "_blank");
+        }
+        const sourceID = d2.id.replace(/\./g, "<TX_DOT>");
+        const terms_text = _t(
+          "imagery.".concat(sourceID, ".attribution.text"),
+          { default: d2.terms_text || d2.id || d2.name() }
+        );
+        if (d2.icon && !d2.overlay) {
+          attribution.append("img").attr("class", "source-image").attr("src", d2.icon);
+        }
+        attribution.append("span").attr("class", "attribution-text").text(terms_text);
+      }).merge(attributions);
+      let copyright = attributions.selectAll(".copyright-notice").data((d2) => {
+        let notice = d2.copyrightNotices(context.map().zoom(), context.map().extent());
+        return notice ? [notice] : [];
+      });
+      copyright.exit().remove();
+      copyright = copyright.enter().append("span").attr("class", "copyright-notice").merge(copyright);
+      copyright.text(String);
     }
-    function zoomOut(delta) {
-      setCenterZoom(map2.center(), ~~map2.zoom() - delta, 250, true);
+    function update() {
+      let baselayer = context.background().baseLayerSource();
+      _selection.call(render, baselayer ? [baselayer] : [], "base-layer-attribution");
+      const z2 = context.map().zoom();
+      let overlays = context.background().overlayLayerSources() || [];
+      _selection.call(render, overlays.filter((s2) => s2.validZoom(z2)), "overlay-layer-attribution");
     }
-    map2.zoomIn = function() {
-      zoomIn(1);
-    };
-    map2.zoomInFurther = function() {
-      zoomIn(4);
-    };
-    map2.canZoomIn = function() {
-      return map2.zoom() < maxZoom;
-    };
-    map2.zoomOut = function() {
-      zoomOut(1);
-    };
-    map2.zoomOutFurther = function() {
-      zoomOut(4);
-    };
-    map2.canZoomOut = function() {
-      return map2.zoom() > minZoom2;
+    return function(selection2) {
+      _selection = selection2;
+      context.background().on("change.attribution", update);
+      context.map().on("move.attribution", throttle_default(update, 400, { leading: false }));
+      update();
     };
-    map2.center = function(loc2) {
-      if (!arguments.length) {
-        return projection2.invert(pxCenter());
+  }
+
+  // modules/ui/contributors.js
+  function uiContributors(context) {
+    var osm = context.connection(), debouncedUpdate = debounce_default(function() {
+      update();
+    }, 1e3), limit = 4, hidden = false, wrap2 = select_default2(null);
+    function update() {
+      if (!osm) return;
+      var users = {}, entities = context.history().intersects(context.map().extent());
+      entities.forEach(function(entity) {
+        if (entity && entity.user) users[entity.user] = true;
+      });
+      var u2 = Object.keys(users), subset = u2.slice(0, u2.length > limit ? limit - 1 : limit);
+      wrap2.html("").call(svgIcon("#iD-icon-nearby", "pre-text light"));
+      var userList = select_default2(document.createElement("span"));
+      userList.selectAll().data(subset).enter().append("a").attr("class", "user-link").attr("href", function(d2) {
+        return osm.userURL(d2);
+      }).attr("target", "_blank").text(String);
+      if (u2.length > limit) {
+        var count = select_default2(document.createElement("span"));
+        var othersNum = u2.length - limit + 1;
+        count.append("a").attr("target", "_blank").attr("href", function() {
+          return osm.changesetsURL(context.map().center(), context.map().zoom());
+        }).text(othersNum);
+        wrap2.append("span").html(_t.html("contributors.truncated_list", { n: othersNum, users: { html: userList.html() }, count: { html: count.html() } }));
+      } else {
+        wrap2.append("span").html(_t.html("contributors.list", { users: { html: userList.html() } }));
       }
-      if (setCenterZoom(loc2, map2.zoom())) {
-        dispatch14.call("move", this, map2);
+      if (!u2.length) {
+        hidden = true;
+        wrap2.transition().style("opacity", 0);
+      } else if (hidden) {
+        wrap2.transition().style("opacity", 1);
       }
-      scheduleRedraw();
-      return map2;
+    }
+    return function(selection2) {
+      if (!osm) return;
+      wrap2 = selection2;
+      update();
+      osm.on("loaded.contributors", debouncedUpdate);
+      context.map().on("move.contributors", debouncedUpdate);
     };
-    map2.unobscuredCenterZoomEase = function(loc, zoom) {
-      var offset = map2.unobscuredOffsetPx();
-      var proj = geoRawMercator().transform(projection2.transform());
-      proj.scale(geoZoomToScale(zoom, TILESIZE));
-      var locPx = proj(loc);
-      var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
-      var offsetLoc = proj.invert(offsetLocPx);
-      map2.centerZoomEase(offsetLoc, zoom);
-    };
-    map2.unobscuredOffsetPx = function() {
-      var openPane = context.container().select(".map-panes .map-pane.shown");
-      if (!openPane.empty()) {
-        return [openPane.node().offsetWidth / 2, 0];
+  }
+
+  // modules/ui/edit_menu.js
+  function uiEditMenu(context) {
+    var dispatch14 = dispatch_default("toggled");
+    var _menu = select_default2(null);
+    var _operations = [];
+    var _anchorLoc = [0, 0];
+    var _anchorLocLonLat = [0, 0];
+    var _triggerType = "";
+    var _vpTopMargin = 85;
+    var _vpBottomMargin = 45;
+    var _vpSideMargin = 35;
+    var _menuTop = false;
+    var _menuHeight;
+    var _menuWidth;
+    var _verticalPadding = 4;
+    var _tooltipWidth = 210;
+    var _menuSideMargin = 10;
+    var _tooltips = [];
+    var editMenu = function(selection2) {
+      var isTouchMenu = _triggerType.includes("touch") || _triggerType.includes("pen");
+      var ops = _operations.filter(function(op) {
+        return !isTouchMenu || !op.mouseOnly;
+      });
+      if (!ops.length) return;
+      _tooltips = [];
+      _menuTop = isTouchMenu;
+      var showLabels = isTouchMenu;
+      var buttonHeight = showLabels ? 32 : 34;
+      if (showLabels) {
+        _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function(op) {
+          return op.title.length;
+        })));
+      } else {
+        _menuWidth = 44;
       }
-      return [0, 0];
-    };
-    map2.zoom = function(z2) {
-      if (!arguments.length) {
-        return Math.max(geoScaleToZoom(projection2.scale(), TILESIZE), 0);
+      _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
+      _menu = selection2.append("div").attr("class", "edit-menu").classed("touch-menu", isTouchMenu).style("padding", _verticalPadding + "px 0");
+      var buttons = _menu.selectAll(".edit-menu-item").data(ops);
+      var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
+        return "edit-menu-item edit-menu-item-" + d2.id;
+      }).style("height", buttonHeight + "px").on("click", click).on("pointerup", pointerup).on("pointerdown mousedown", function pointerdown(d3_event) {
+        d3_event.stopPropagation();
+      }).on("mouseenter.highlight", function(d3_event, d2) {
+        if (!d2.relatedEntityIds || select_default2(this).classed("disabled")) return;
+        utilHighlightEntities(d2.relatedEntityIds(), true, context);
+      }).on("mouseleave.highlight", function(d3_event, d2) {
+        if (!d2.relatedEntityIds) return;
+        utilHighlightEntities(d2.relatedEntityIds(), false, context);
+      });
+      buttonsEnter.each(function(d2) {
+        var tooltip = uiTooltip().heading(() => d2.title).title(d2.tooltip).keys([d2.keys[0]]);
+        _tooltips.push(tooltip);
+        select_default2(this).call(tooltip).append("div").attr("class", "icon-wrap").call(svgIcon(d2.icon && d2.icon() || "#iD-operation-" + d2.id, "operation"));
+      });
+      if (showLabels) {
+        buttonsEnter.append("span").attr("class", "label").each(function(d2) {
+          select_default2(this).call(d2.title);
+        });
       }
-      if (z2 < _minzoom) {
-        surface.interrupt();
-        dispatch14.call("hitMinZoom", this, map2);
-        z2 = context.minEditableZoom();
+      buttonsEnter.merge(buttons).classed("disabled", function(d2) {
+        return d2.disabled();
+      });
+      updatePosition();
+      var initialScale = context.projection.scale();
+      context.map().on("move.edit-menu", function() {
+        if (initialScale !== context.projection.scale()) {
+          editMenu.close();
+        }
+      }).on("drawn.edit-menu", function(info) {
+        if (info.full) updatePosition();
+      });
+      var lastPointerUpType;
+      function pointerup(d3_event) {
+        lastPointerUpType = d3_event.pointerType;
       }
-      if (setCenterZoom(map2.center(), z2)) {
-        dispatch14.call("move", this, map2);
+      function click(d3_event, operation2) {
+        d3_event.stopPropagation();
+        if (operation2.relatedEntityIds) {
+          utilHighlightEntities(operation2.relatedEntityIds(), false, context);
+        }
+        if (operation2.disabled()) {
+          if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
+            context.ui().flash.duration(4e3).iconName("#iD-operation-" + operation2.id).iconClass("operation disabled").label(operation2.tooltip())();
+          }
+        } else {
+          if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
+            context.ui().flash.duration(2e3).iconName("#iD-operation-" + operation2.id).iconClass("operation").label(operation2.annotation() || operation2.title)();
+          }
+          operation2();
+          editMenu.close();
+        }
+        lastPointerUpType = null;
       }
-      scheduleRedraw();
-      return map2;
+      dispatch14.call("toggled", this, true);
     };
-    map2.centerZoom = function(loc2, z2) {
-      if (setCenterZoom(loc2, z2)) {
-        dispatch14.call("move", this, map2);
+    function updatePosition() {
+      if (!_menu || _menu.empty()) return;
+      var anchorLoc = context.projection(_anchorLocLonLat);
+      var viewport = context.surfaceRect();
+      if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
+        editMenu.close();
+        return;
       }
-      scheduleRedraw();
-      return map2;
-    };
-    map2.zoomTo = function(entity) {
-      var extent = entity.extent(context.graph());
-      if (!isFinite(extent.area()))
-        return map2;
-      var z2 = clamp2(map2.trimmedExtentZoom(extent), 0, 20);
-      return map2.centerZoom(extent.center(), z2);
-    };
-    map2.centerEase = function(loc2, duration) {
-      duration = duration || 250;
-      setCenterZoom(loc2, map2.zoom(), duration);
-      return map2;
-    };
-    map2.zoomEase = function(z2, duration) {
-      duration = duration || 250;
-      setCenterZoom(map2.center(), z2, duration, false);
-      return map2;
-    };
-    map2.centerZoomEase = function(loc2, z2, duration) {
-      duration = duration || 250;
-      setCenterZoom(loc2, z2, duration, false);
-      return map2;
-    };
-    map2.transformEase = function(t2, duration) {
-      duration = duration || 250;
-      setTransform(
-        t2,
-        duration,
-        false
-        /* don't force */
-      );
-      return map2;
-    };
-    map2.zoomToEase = function(obj, duration) {
-      var extent;
-      if (Array.isArray(obj)) {
-        obj.forEach(function(entity) {
-          var entityExtent = entity.extent(context.graph());
-          if (!extent) {
-            extent = entityExtent;
-          } else {
-            extent = extent.extend(entityExtent);
-          }
-        });
+      var menuLeft = displayOnLeft(viewport);
+      var offset = [0, 0];
+      offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
+      if (_menuTop) {
+        if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
+          offset[1] = -anchorLoc[1] + _vpTopMargin;
+        } else {
+          offset[1] = -_menuHeight;
+        }
       } else {
-        extent = obj.extent(context.graph());
+        if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
+          offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
+        } else {
+          offset[1] = 0;
+        }
       }
-      if (!isFinite(extent.area()))
-        return map2;
-      var z2 = clamp2(map2.trimmedExtentZoom(extent), 0, 20);
-      return map2.centerZoomEase(extent.center(), z2, duration);
-    };
-    map2.startEase = function() {
-      utilBindOnce(surface, _pointerPrefix + "down.ease", function() {
-        map2.cancelEase();
+      var origin = geoVecAdd(anchorLoc, offset);
+      _menu.style("left", origin[0] + "px").style("top", origin[1] + "px");
+      var tooltipSide = tooltipPosition(viewport, menuLeft);
+      _tooltips.forEach(function(tooltip) {
+        tooltip.placement(tooltipSide);
       });
-      return map2;
-    };
-    map2.cancelEase = function() {
-      _selection.interrupt();
-      return map2;
-    };
-    map2.extent = function(val) {
-      if (!arguments.length) {
-        return new geoExtent(
-          projection2.invert([0, _dimensions[1]]),
-          projection2.invert([_dimensions[0], 0])
-        );
-      } else {
-        var extent = geoExtent(val);
-        map2.centerZoom(extent.center(), map2.extentZoom(extent));
+      function displayOnLeft(viewport2) {
+        if (_mainLocalizer.textDirection() === "ltr") {
+          if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport2.width - _vpSideMargin) {
+            return true;
+          }
+          return false;
+        } else {
+          if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
+            return false;
+          }
+          return true;
+        }
       }
-    };
-    map2.trimmedExtent = function(val) {
-      if (!arguments.length) {
-        var headerY = 71;
-        var footerY = 30;
-        var pad2 = 10;
-        return new geoExtent(
-          projection2.invert([pad2, _dimensions[1] - footerY - pad2]),
-          projection2.invert([_dimensions[0] - pad2, headerY + pad2])
-        );
-      } else {
-        var extent = geoExtent(val);
-        map2.centerZoom(extent.center(), map2.trimmedExtentZoom(extent));
+      function tooltipPosition(viewport2, menuLeft2) {
+        if (_mainLocalizer.textDirection() === "ltr") {
+          if (menuLeft2) {
+            return "left";
+          }
+          if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport2.width - _vpSideMargin) {
+            return "left";
+          }
+          return "right";
+        } else {
+          if (!menuLeft2) {
+            return "right";
+          }
+          if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
+            return "right";
+          }
+          return "left";
+        }
       }
-    };
-    function calcExtentZoom(extent, dim) {
-      var tl = projection2([extent[0][0], extent[1][1]]);
-      var br2 = projection2([extent[1][0], extent[0][1]]);
-      var hFactor = (br2[0] - tl[0]) / dim[0];
-      var vFactor = (br2[1] - tl[1]) / dim[1];
-      var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
-      var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
-      var newZoom = map2.zoom() - Math.max(hZoomDiff, vZoomDiff);
-      return newZoom;
     }
-    map2.extentZoom = function(val) {
-      return calcExtentZoom(geoExtent(val), _dimensions);
-    };
-    map2.trimmedExtentZoom = function(val) {
-      var trimY = 120;
-      var trimX = 40;
-      var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
-      return calcExtentZoom(geoExtent(val), trimmed);
-    };
-    map2.withinEditableZoom = function() {
-      return map2.zoom() >= context.minEditableZoom();
-    };
-    map2.isInWideSelection = function() {
-      return !map2.withinEditableZoom() && context.selectedIDs().length;
+    editMenu.close = function() {
+      context.map().on("move.edit-menu", null).on("drawn.edit-menu", null);
+      _menu.remove();
+      _tooltips = [];
+      dispatch14.call("toggled", this, false);
     };
-    map2.editableDataEnabled = function(skipZoomCheck) {
-      var layer = context.layers().layer("osm");
-      if (!layer || !layer.enabled())
-        return false;
-      return skipZoomCheck || map2.withinEditableZoom();
+    editMenu.anchorLoc = function(val) {
+      if (!arguments.length) return _anchorLoc;
+      _anchorLoc = val;
+      _anchorLocLonLat = context.projection.invert(_anchorLoc);
+      return editMenu;
     };
-    map2.notesEditable = function() {
-      var layer = context.layers().layer("notes");
-      if (!layer || !layer.enabled())
-        return false;
-      return map2.withinEditableZoom();
+    editMenu.triggerType = function(val) {
+      if (!arguments.length) return _triggerType;
+      _triggerType = val;
+      return editMenu;
     };
-    map2.minzoom = function(val) {
-      if (!arguments.length)
-        return _minzoom;
-      _minzoom = val;
-      return map2;
+    editMenu.operations = function(val) {
+      if (!arguments.length) return _operations;
+      _operations = val;
+      return editMenu;
     };
-    map2.toggleHighlightEdited = function() {
-      surface.classed("highlight-edited", !surface.classed("highlight-edited"));
-      map2.pan([0, 0]);
-      dispatch14.call("changeHighlighting", this);
+    return utilRebind(editMenu, dispatch14, "on");
+  }
+
+  // modules/ui/feature_info.js
+  function uiFeatureInfo(context) {
+    function update(selection2) {
+      var features = context.features();
+      var stats = features.stats();
+      var count = 0;
+      var hiddenList = features.hidden().map(function(k2) {
+        if (stats[k2]) {
+          count += stats[k2];
+          return _t.append("inspector.title_count", {
+            title: _t("feature." + k2 + ".description"),
+            count: stats[k2]
+          });
+        }
+        return null;
+      }).filter(Boolean);
+      selection2.text("");
+      if (hiddenList.length) {
+        var tooltipBehavior = uiTooltip().placement("top").title(function() {
+          return (selection3) => {
+            hiddenList.forEach((hiddenFeature) => {
+              selection3.append("div").call(hiddenFeature);
+            });
+          };
+        });
+        selection2.append("a").attr("class", "chip").attr("href", "#").call(_t.append("feature_info.hidden_warning", { count })).call(tooltipBehavior).on("click", function(d3_event) {
+          tooltipBehavior.hide();
+          d3_event.preventDefault();
+          context.ui().togglePanes(context.container().select(".map-panes .map-data-pane"));
+        });
+      }
+      selection2.classed("hide", !hiddenList.length);
+    }
+    return function(selection2) {
+      update(selection2);
+      context.features().on("change.feature_info", function() {
+        update(selection2);
+      });
     };
-    map2.areaFillOptions = ["wireframe", "partial", "full"];
-    map2.activeAreaFill = function(val) {
-      if (!arguments.length)
-        return corePreferences("area-fill") || "partial";
-      corePreferences("area-fill", val);
-      if (val !== "wireframe") {
-        corePreferences("area-fill-toggle", val);
+  }
+
+  // modules/ui/flash.js
+  function uiFlash(context) {
+    var _flashTimer;
+    var _duration = 2e3;
+    var _iconName = "#iD-icon-no";
+    var _iconClass = "disabled";
+    var _label = (s2) => s2.text("");
+    function flash() {
+      if (_flashTimer) {
+        _flashTimer.stop();
       }
-      updateAreaFill();
-      map2.pan([0, 0]);
-      dispatch14.call("changeAreaFill", this);
-      return map2;
+      context.container().select(".main-footer-wrap").classed("footer-hide", true).classed("footer-show", false);
+      context.container().select(".flash-wrap").classed("footer-hide", false).classed("footer-show", true);
+      var content = context.container().select(".flash-wrap").selectAll(".flash-content").data([0]);
+      var contentEnter = content.enter().append("div").attr("class", "flash-content");
+      var iconEnter = contentEnter.append("svg").attr("class", "flash-icon icon").append("g").attr("transform", "translate(10,10)");
+      iconEnter.append("circle").attr("r", 9);
+      iconEnter.append("use").attr("transform", "translate(-7,-7)").attr("width", "14").attr("height", "14");
+      contentEnter.append("div").attr("class", "flash-text");
+      content = content.merge(contentEnter);
+      content.selectAll(".flash-icon").attr("class", "icon flash-icon " + (_iconClass || ""));
+      content.selectAll(".flash-icon use").attr("xlink:href", _iconName);
+      content.selectAll(".flash-text").attr("class", "flash-text").call(_label);
+      _flashTimer = timeout_default(function() {
+        _flashTimer = null;
+        context.container().select(".main-footer-wrap").classed("footer-hide", false).classed("footer-show", true);
+        context.container().select(".flash-wrap").classed("footer-hide", true).classed("footer-show", false);
+      }, _duration);
+      return content;
+    }
+    flash.duration = function(_2) {
+      if (!arguments.length) return _duration;
+      _duration = _2;
+      return flash;
     };
-    map2.toggleWireframe = function() {
-      var activeFill = map2.activeAreaFill();
-      if (activeFill === "wireframe") {
-        activeFill = corePreferences("area-fill-toggle") || "partial";
+    flash.label = function(_2) {
+      if (!arguments.length) return _label;
+      if (typeof _2 !== "function") {
+        _label = (selection2) => selection2.text(_2);
       } else {
-        activeFill = "wireframe";
+        _label = (selection2) => selection2.text("").call(_2);
       }
-      map2.activeAreaFill(activeFill);
+      return flash;
     };
-    function updateAreaFill() {
-      var activeFill = map2.activeAreaFill();
-      map2.areaFillOptions.forEach(function(opt) {
-        surface.classed("fill-" + opt, Boolean(opt === activeFill));
-      });
-    }
-    map2.layers = () => drawLayers;
-    map2.doubleUpHandler = function() {
-      return _doubleUpHandler;
+    flash.iconName = function(_2) {
+      if (!arguments.length) return _iconName;
+      _iconName = _2;
+      return flash;
     };
-    return utilRebind(map2, dispatch14, "on");
+    flash.iconClass = function(_2) {
+      if (!arguments.length) return _iconClass;
+      _iconClass = _2;
+      return flash;
+    };
+    return flash;
   }
 
-  // modules/renderer/photos.js
-  function rendererPhotos(context) {
-    var dispatch14 = dispatch_default("change");
-    var _layerIDs = ["streetside", "mapillary", "mapillary-map-features", "mapillary-signs", "kartaview", "mapilio", "vegbilder"];
-    var _allPhotoTypes = ["flat", "panoramic"];
-    var _shownPhotoTypes = _allPhotoTypes.slice();
-    var _dateFilters = ["fromDate", "toDate"];
-    var _fromDate;
-    var _toDate;
-    var _usernames;
-    function photos() {
+  // modules/ui/full_screen.js
+  function uiFullScreen(context) {
+    var element = context.container().node();
+    function getFullScreenFn() {
+      if (element.requestFullscreen) {
+        return element.requestFullscreen;
+      } else if (element.msRequestFullscreen) {
+        return element.msRequestFullscreen;
+      } else if (element.mozRequestFullScreen) {
+        return element.mozRequestFullScreen;
+      } else if (element.webkitRequestFullscreen) {
+        return element.webkitRequestFullscreen;
+      }
     }
-    function updateStorage() {
-      if (window.mocha)
-        return;
-      var hash = utilStringQs(window.location.hash);
-      var enabled = context.layers().all().filter(function(d2) {
-        return _layerIDs.indexOf(d2.id) !== -1 && d2.layer && d2.layer.supported() && d2.layer.enabled();
-      }).map(function(d2) {
-        return d2.id;
-      });
-      if (enabled.length) {
-        hash.photo_overlay = enabled.join(",");
+    function getExitFullScreenFn() {
+      if (document.exitFullscreen) {
+        return document.exitFullscreen;
+      } else if (document.msExitFullscreen) {
+        return document.msExitFullscreen;
+      } else if (document.mozCancelFullScreen) {
+        return document.mozCancelFullScreen;
+      } else if (document.webkitExitFullscreen) {
+        return document.webkitExitFullscreen;
+      }
+    }
+    function isFullScreen() {
+      return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
+    }
+    function isSupported() {
+      return !!getFullScreenFn();
+    }
+    function fullScreen(d3_event) {
+      d3_event.preventDefault();
+      if (!isFullScreen()) {
+        getFullScreenFn().apply(element);
       } else {
-        delete hash.photo_overlay;
+        getExitFullScreenFn().apply(document);
       }
-      window.location.replace("#" + utilQsString(hash, true));
     }
-    photos.overlayLayerIDs = function() {
-      return _layerIDs;
-    };
-    photos.allPhotoTypes = function() {
-      return _allPhotoTypes;
-    };
-    photos.dateFilters = function() {
-      return _dateFilters;
+    return function() {
+      if (!isSupported()) return;
+      var detected = utilDetect();
+      var keys2 = detected.os === "mac" ? [uiCmd("\u2303\u2318F"), "f11"] : ["f11"];
+      context.keybinding().on(keys2, fullScreen);
     };
-    photos.dateFilterValue = function(val) {
-      return val === _dateFilters[0] ? _fromDate : _toDate;
+  }
+
+  // modules/ui/geolocate.js
+  function uiGeolocate(context) {
+    var _geolocationOptions = {
+      // prioritize speed and power usage over precision
+      enableHighAccuracy: false,
+      // don't hang indefinitely getting the location
+      timeout: 6e3
+      // 6sec
     };
-    photos.setDateFilter = function(type2, val, updateUrl) {
-      var date = val && new Date(val);
-      if (date && !isNaN(date)) {
-        val = date.toISOString().slice(0, 10);
+    var _locating = uiLoading(context).message(_t.html("geolocate.locating")).blocking(true);
+    var _layer = context.layers().layer("geolocate");
+    var _position;
+    var _extent;
+    var _timeoutID;
+    var _button = select_default2(null);
+    function click() {
+      if (context.inIntro()) return;
+      if (!_layer.enabled() && !_locating.isShown()) {
+        _timeoutID = setTimeout(
+          error,
+          1e4
+          /* 10sec */
+        );
+        context.container().call(_locating);
+        navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
       } else {
-        val = null;
-      }
-      if (type2 === _dateFilters[0]) {
-        _fromDate = val;
-        if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
-          _toDate = _fromDate;
-        }
-      }
-      if (type2 === _dateFilters[1]) {
-        _toDate = val;
-        if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
-          _fromDate = _toDate;
-        }
-      }
-      dispatch14.call("change", this);
-      if (updateUrl) {
-        var rangeString;
-        if (_fromDate || _toDate) {
-          rangeString = (_fromDate || "") + "_" + (_toDate || "");
-        }
-        setUrlFilterValue("photo_dates", rangeString);
-      }
-    };
-    photos.setUsernameFilter = function(val, updateUrl) {
-      if (val && typeof val === "string")
-        val = val.replace(/;/g, ",").split(",");
-      if (val) {
-        val = val.map((d2) => d2.trim()).filter(Boolean);
-        if (!val.length) {
-          val = null;
-        }
-      }
-      _usernames = val;
-      dispatch14.call("change", this);
-      if (updateUrl) {
-        var hashString;
-        if (_usernames) {
-          hashString = _usernames.join(",");
-        }
-        setUrlFilterValue("photo_username", hashString);
-      }
-    };
-    function setUrlFilterValue(property, val) {
-      if (!window.mocha) {
-        var hash = utilStringQs(window.location.hash);
-        if (val) {
-          if (hash[property] === val)
-            return;
-          hash[property] = val;
-        } else {
-          if (!(property in hash))
-            return;
-          delete hash[property];
-        }
-        window.location.replace("#" + utilQsString(hash, true));
+        _locating.close();
+        _layer.enabled(null, false);
+        updateButtonState();
       }
     }
-    function showsLayer(id2) {
-      var layer = context.layers().layer(id2);
-      return layer && layer.supported() && layer.enabled();
+    function zoomTo() {
+      context.enter(modeBrowse(context));
+      var map2 = context.map();
+      _layer.enabled(_position, true);
+      updateButtonState();
+      map2.centerZoomEase(_extent.center(), Math.min(20, map2.extentZoom(_extent)));
     }
-    photos.shouldFilterByDate = function() {
-      return showsLayer("mapillary") || showsLayer("kartaview") || showsLayer("streetside") || showsLayer("vegbilder");
-    };
-    photos.shouldFilterByPhotoType = function() {
-      return showsLayer("mapillary") || showsLayer("streetside") && showsLayer("kartaview") || showsLayer("vegbilder");
-    };
-    photos.shouldFilterByUsername = function() {
-      return !showsLayer("mapillary") && showsLayer("kartaview") && !showsLayer("streetside");
-    };
-    photos.showsPhotoType = function(val) {
-      if (!photos.shouldFilterByPhotoType())
-        return true;
-      return _shownPhotoTypes.indexOf(val) !== -1;
-    };
-    photos.showsFlat = function() {
-      return photos.showsPhotoType("flat");
-    };
-    photos.showsPanoramic = function() {
-      return photos.showsPhotoType("panoramic");
-    };
-    photos.fromDate = function() {
-      return _fromDate;
-    };
-    photos.toDate = function() {
-      return _toDate;
-    };
-    photos.togglePhotoType = function(val) {
-      var index = _shownPhotoTypes.indexOf(val);
-      if (index !== -1) {
-        _shownPhotoTypes.splice(index, 1);
-      } else {
-        _shownPhotoTypes.push(val);
-      }
-      dispatch14.call("change", this);
-      return photos;
-    };
-    photos.usernames = function() {
-      return _usernames;
-    };
-    photos.init = function() {
-      var hash = utilStringQs(window.location.hash);
-      if (hash.photo_dates) {
-        var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
-        this.setDateFilter("fromDate", parts && parts.length >= 2 && parts[1], false);
-        this.setDateFilter("toDate", parts && parts.length >= 3 && parts[2], false);
-      }
-      if (hash.photo_username) {
-        this.setUsernameFilter(hash.photo_username, false);
-      }
-      if (hash.photo_overlay) {
-        var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ",").split(",");
-        hashOverlayIDs.forEach(function(id2) {
-          if (id2 === "openstreetcam")
-            id2 = "kartaview";
-          var layer2 = _layerIDs.indexOf(id2) !== -1 && context.layers().layer(id2);
-          if (layer2 && !layer2.enabled())
-            layer2.enabled(true);
-        });
-      }
-      if (hash.photo) {
-        var photoIds = hash.photo.replace(/;/g, ",").split(",");
-        var photoId = photoIds.length && photoIds[0].trim();
-        var results = /(.*)\/(.*)/g.exec(photoId);
-        if (results && results.length >= 3) {
-          var serviceId = results[1];
-          if (serviceId === "openstreetcam")
-            serviceId = "kartaview";
-          var photoKey = results[2];
-          var service = services[serviceId];
-          if (service && service.ensureViewerLoaded) {
-            var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
-            if (layer && !layer.enabled())
-              layer.enabled(true);
-            var baselineTime = Date.now();
-            service.on("loadedImages.rendererPhotos", function() {
-              if (Date.now() - baselineTime > 45e3) {
-                service.on("loadedImages.rendererPhotos", null);
-                return;
-              }
-              if (!service.cachedImage(photoKey))
-                return;
-              service.on("loadedImages.rendererPhotos", null);
-              service.ensureViewerLoaded(context).then(function() {
-                service.selectImage(context, photoKey).showViewer(context);
-              });
-            });
-          }
-        }
-      }
-      context.layers().on("change.rendererPhotos", updateStorage);
-    };
-    return utilRebind(photos, dispatch14, "on");
-  }
-
-  // modules/ui/account.js
-  function uiAccount(context) {
-    const osm = context.connection();
-    function updateUserDetails(selection2) {
-      if (!osm)
-        return;
-      if (!osm.authenticated()) {
-        render(selection2, null);
+    function success(geolocation) {
+      _position = geolocation;
+      var coords = _position.coords;
+      _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
+      zoomTo();
+      finish();
+    }
+    function error() {
+      if (_position) {
+        zoomTo();
       } else {
-        osm.userDetails((err, user) => render(selection2, user));
+        context.ui().flash.label(_t.append("geolocate.location_unavailable")).iconName("#iD-icon-geolocate")();
       }
+      finish();
     }
-    function render(selection2, user) {
-      let userInfo = selection2.select(".userInfo");
-      let loginLogout = selection2.select(".loginLogout");
-      if (user) {
-        userInfo.html("").classed("hide", false);
-        let userLink = userInfo.append("a").attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
-        if (user.image_url) {
-          userLink.append("img").attr("class", "icon pre-text user-icon").attr("src", user.image_url);
-        } else {
-          userLink.call(svgIcon("#iD-icon-avatar", "pre-text light"));
-        }
-        userLink.append("span").attr("class", "label").text(user.display_name);
-        loginLogout.classed("hide", false).select("a").text(_t("logout")).on("click", (e3) => {
-          e3.preventDefault();
-          osm.logout();
-          tryLogout();
-        });
-      } else {
-        userInfo.html("").classed("hide", true);
-        loginLogout.classed("hide", false).select("a").text(_t("login")).on("click", (e3) => {
-          e3.preventDefault();
-          osm.authenticate();
-        });
+    function finish() {
+      _locating.close();
+      if (_timeoutID) {
+        clearTimeout(_timeoutID);
       }
+      _timeoutID = void 0;
     }
-    function tryLogout() {
-      if (!osm)
-        return;
-      const url = osm.getUrlRoot() + "/logout?referer=%2Flogin";
-      const w2 = 600;
-      const h2 = 550;
-      const settings = [
-        ["width", w2],
-        ["height", h2],
-        ["left", window.screen.width / 2 - w2 / 2],
-        ["top", window.screen.height / 2 - h2 / 2]
-      ].map((x2) => x2.join("=")).join(",");
-      window.open(url, "_blank", settings);
+    function updateButtonState() {
+      _button.classed("active", _layer.enabled());
+      _button.attr("aria-pressed", _layer.enabled());
     }
     return function(selection2) {
-      if (!osm)
-        return;
-      selection2.append("li").attr("class", "userInfo").classed("hide", true);
-      selection2.append("li").attr("class", "loginLogout").classed("hide", true).append("a").attr("href", "#");
-      osm.on("change.account", () => updateUserDetails(selection2));
-      updateUserDetails(selection2);
+      if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
+      _button = selection2.append("button").on("click", click).attr("aria-pressed", false).call(svgIcon("#iD-icon-geolocate", "light")).call(
+        uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(() => _t.append("geolocate.title")).keys([_t("geolocate.key")])
+      );
+      context.keybinding().on(_t("geolocate.key"), click);
     };
   }
 
-  // modules/ui/attribution.js
-  function uiAttribution(context) {
-    let _selection = select_default2(null);
-    function render(selection2, data, klass) {
-      let div = selection2.selectAll(".".concat(klass)).data([0]);
-      div = div.enter().append("div").attr("class", klass).merge(div);
-      let attributions = div.selectAll(".attribution").data(data, (d2) => d2.id);
-      attributions.exit().remove();
-      attributions = attributions.enter().append("span").attr("class", "attribution").each((d2, i3, nodes) => {
-        let attribution = select_default2(nodes[i3]);
-        if (d2.terms_html) {
-          attribution.html(d2.terms_html);
-          return;
-        }
-        if (d2.terms_url) {
-          attribution = attribution.append("a").attr("href", d2.terms_url).attr("target", "_blank");
-        }
-        const sourceID = d2.id.replace(/\./g, "<TX_DOT>");
-        const terms_text = _t(
-          "imagery.".concat(sourceID, ".attribution.text"),
-          { default: d2.terms_text || d2.id || d2.name() }
-        );
-        if (d2.icon && !d2.overlay) {
-          attribution.append("img").attr("class", "source-image").attr("src", d2.icon);
+  // modules/ui/panels/background.js
+  function uiPanelBackground(context) {
+    var background = context.background();
+    var _currSourceName = null;
+    var _metadata = {};
+    var _metadataKeys = [
+      "zoom",
+      "vintage",
+      "source",
+      "description",
+      "resolution",
+      "accuracy"
+    ];
+    var debouncedRedraw = debounce_default(redraw, 250);
+    function redraw(selection2) {
+      var source = background.baseLayerSource();
+      if (!source) return;
+      var isDG = source.id.match(/^DigitalGlobe/i) !== null;
+      var sourceLabel = source.label();
+      if (_currSourceName !== sourceLabel) {
+        _currSourceName = sourceLabel;
+        _metadata = {};
+      }
+      selection2.text("");
+      var list2 = selection2.append("ul").attr("class", "background-info");
+      list2.append("li").call(_currSourceName);
+      _metadataKeys.forEach(function(k2) {
+        if (isDG && k2 === "vintage") return;
+        list2.append("li").attr("class", "background-info-list-" + k2).classed("hide", !_metadata[k2]).call(_t.append("info_panels.background." + k2, { suffix: ":" })).append("span").attr("class", "background-info-span-" + k2).text(_metadata[k2]);
+      });
+      debouncedGetMetadata(selection2);
+      var toggleTiles = context.getDebug("tile") ? "hide_tiles" : "show_tiles";
+      selection2.append("a").call(_t.append("info_panels.background." + toggleTiles)).attr("href", "#").attr("class", "button button-toggle-tiles").on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.setDebug("tile", !context.getDebug("tile"));
+        selection2.call(redraw);
+      });
+      if (isDG) {
+        var key = source.id + "-vintage";
+        var sourceVintage = context.background().findSource(key);
+        var showsVintage = context.background().showsLayer(sourceVintage);
+        var toggleVintage = showsVintage ? "hide_vintage" : "show_vintage";
+        selection2.append("a").call(_t.append("info_panels.background." + toggleVintage)).attr("href", "#").attr("class", "button button-toggle-vintage").on("click", function(d3_event) {
+          d3_event.preventDefault();
+          context.background().toggleOverlayLayer(sourceVintage);
+          selection2.call(redraw);
+        });
+      }
+      ["DigitalGlobe-Premium", "DigitalGlobe-Standard"].forEach(function(layerId) {
+        if (source.id !== layerId) {
+          var key2 = layerId + "-vintage";
+          var sourceVintage2 = context.background().findSource(key2);
+          if (context.background().showsLayer(sourceVintage2)) {
+            context.background().toggleOverlayLayer(sourceVintage2);
+          }
         }
-        attribution.append("span").attr("class", "attribution-text").text(terms_text);
-      }).merge(attributions);
-      let copyright = attributions.selectAll(".copyright-notice").data((d2) => {
-        let notice = d2.copyrightNotices(context.map().zoom(), context.map().extent());
-        return notice ? [notice] : [];
       });
-      copyright.exit().remove();
-      copyright = copyright.enter().append("span").attr("class", "copyright-notice").merge(copyright);
-      copyright.text(String);
     }
-    function update() {
-      let baselayer = context.background().baseLayerSource();
-      _selection.call(render, baselayer ? [baselayer] : [], "base-layer-attribution");
-      const z2 = context.map().zoom();
-      let overlays = context.background().overlayLayerSources() || [];
-      _selection.call(render, overlays.filter((s2) => s2.validZoom(z2)), "overlay-layer-attribution");
+    var debouncedGetMetadata = debounce_default(getMetadata, 250);
+    function getMetadata(selection2) {
+      var tile = context.container().select(".layer-background img.tile-center");
+      if (tile.empty()) return;
+      var sourceName = _currSourceName;
+      var d2 = tile.datum();
+      var zoom = d2 && d2.length >= 3 && d2[2] || Math.floor(context.map().zoom());
+      var center = context.map().center();
+      _metadata.zoom = String(zoom);
+      selection2.selectAll(".background-info-list-zoom").classed("hide", false).selectAll(".background-info-span-zoom").text(_metadata.zoom);
+      if (!d2 || !d2.length >= 3) return;
+      background.baseLayerSource().getMetadata(center, d2, function(err, result) {
+        if (err || _currSourceName !== sourceName) return;
+        var vintage = result.vintage;
+        _metadata.vintage = vintage && vintage.range || _t("info_panels.background.unknown");
+        selection2.selectAll(".background-info-list-vintage").classed("hide", false).selectAll(".background-info-span-vintage").text(_metadata.vintage);
+        _metadataKeys.forEach(function(k2) {
+          if (k2 === "zoom" || k2 === "vintage") return;
+          var val = result[k2];
+          _metadata[k2] = val;
+          selection2.selectAll(".background-info-list-" + k2).classed("hide", !val).selectAll(".background-info-span-" + k2).text(val);
+        });
+      });
     }
-    return function(selection2) {
-      _selection = selection2;
-      context.background().on("change.attribution", update);
-      context.map().on("move.attribution", throttle_default(update, 400, { leading: false }));
-      update();
+    var panel = function(selection2) {
+      selection2.call(redraw);
+      context.map().on("drawn.info-background", function() {
+        selection2.call(debouncedRedraw);
+      }).on("move.info-background", function() {
+        selection2.call(debouncedGetMetadata);
+      });
+    };
+    panel.off = function() {
+      context.map().on("drawn.info-background", null).on("move.info-background", null);
     };
+    panel.id = "background";
+    panel.label = _t.append("info_panels.background.title");
+    panel.key = _t("info_panels.background.key");
+    return panel;
   }
 
-  // modules/ui/contributors.js
-  function uiContributors(context) {
-    var osm = context.connection(), debouncedUpdate = debounce_default(function() {
-      update();
-    }, 1e3), limit = 4, hidden = false, wrap2 = select_default2(null);
-    function update() {
-      if (!osm)
+  // modules/ui/panels/history.js
+  function uiPanelHistory(context) {
+    var osm;
+    function displayTimestamp(timestamp) {
+      if (!timestamp) return _t("info_panels.history.unknown");
+      var options2 = {
+        day: "numeric",
+        month: "short",
+        year: "numeric",
+        hour: "numeric",
+        minute: "numeric",
+        second: "numeric"
+      };
+      var d2 = new Date(timestamp);
+      if (isNaN(d2.getTime())) return _t("info_panels.history.unknown");
+      return d2.toLocaleString(_mainLocalizer.localeCode(), options2);
+    }
+    function displayUser(selection2, userName) {
+      if (!userName) {
+        selection2.append("span").call(_t.append("info_panels.history.unknown"));
         return;
-      var users = {}, entities = context.history().intersects(context.map().extent());
-      entities.forEach(function(entity) {
-        if (entity && entity.user)
-          users[entity.user] = true;
-      });
-      var u2 = Object.keys(users), subset = u2.slice(0, u2.length > limit ? limit - 1 : limit);
-      wrap2.html("").call(svgIcon("#iD-icon-nearby", "pre-text light"));
-      var userList = select_default2(document.createElement("span"));
-      userList.selectAll().data(subset).enter().append("a").attr("class", "user-link").attr("href", function(d2) {
-        return osm.userURL(d2);
-      }).attr("target", "_blank").text(String);
-      if (u2.length > limit) {
-        var count = select_default2(document.createElement("span"));
-        var othersNum = u2.length - limit + 1;
-        count.append("a").attr("target", "_blank").attr("href", function() {
-          return osm.changesetsURL(context.map().center(), context.map().zoom());
-        }).text(othersNum);
-        wrap2.append("span").html(_t.html("contributors.truncated_list", { n: othersNum, users: { html: userList.html() }, count: { html: count.html() } }));
-      } else {
-        wrap2.append("span").html(_t.html("contributors.list", { users: { html: userList.html() } }));
       }
-      if (!u2.length) {
-        hidden = true;
-        wrap2.transition().style("opacity", 0);
-      } else if (hidden) {
-        wrap2.transition().style("opacity", 1);
+      selection2.append("span").attr("class", "user-name").text(userName);
+      var links = selection2.append("div").attr("class", "links");
+      if (osm) {
+        links.append("a").attr("class", "user-osm-link").attr("href", osm.userURL(userName)).attr("target", "_blank").call(_t.append("info_panels.history.profile_link"));
       }
+      links.append("a").attr("class", "user-hdyc-link").attr("href", "https://hdyc.neis-one.org/?" + userName).attr("target", "_blank").attr("tabindex", -1).text("HDYC");
     }
-    return function(selection2) {
-      if (!osm)
+    function displayChangeset(selection2, changeset) {
+      if (!changeset) {
+        selection2.append("span").call(_t.append("info_panels.history.unknown"));
         return;
-      wrap2 = selection2;
-      update();
-      osm.on("loaded.contributors", debouncedUpdate);
-      context.map().on("move.contributors", debouncedUpdate);
-    };
-  }
-
-  // modules/ui/popover.js
-  var _popoverID = 0;
-  function uiPopover(klass) {
-    var _id = _popoverID++;
-    var _anchorSelection = select_default2(null);
-    var popover = function(selection2) {
-      _anchorSelection = selection2;
-      selection2.each(setup);
-    };
-    var _animation = utilFunctor(false);
-    var _placement = utilFunctor("top");
-    var _alignment = utilFunctor("center");
-    var _scrollContainer = utilFunctor(select_default2(null));
-    var _content;
-    var _displayType = utilFunctor("");
-    var _hasArrow = utilFunctor(true);
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    popover.displayType = function(val) {
-      if (arguments.length) {
-        _displayType = utilFunctor(val);
-        return popover;
-      } else {
-        return _displayType;
       }
-    };
-    popover.hasArrow = function(val) {
-      if (arguments.length) {
-        _hasArrow = utilFunctor(val);
-        return popover;
-      } else {
-        return _hasArrow;
+      selection2.append("span").attr("class", "changeset-id").text(changeset);
+      var links = selection2.append("div").attr("class", "links");
+      if (osm) {
+        links.append("a").attr("class", "changeset-osm-link").attr("href", osm.changesetURL(changeset)).attr("target", "_blank").call(_t.append("info_panels.history.changeset_link"));
       }
-    };
-    popover.placement = function(val) {
-      if (arguments.length) {
-        _placement = utilFunctor(val);
-        return popover;
+      links.append("a").attr("class", "changeset-osmcha-link").attr("href", "https://osmcha.org/changesets/" + changeset).attr("target", "_blank").text("OSMCha");
+      links.append("a").attr("class", "changeset-achavi-link").attr("href", "https://overpass-api.de/achavi/?changeset=" + changeset).attr("target", "_blank").text("Achavi");
+    }
+    function redraw(selection2) {
+      var selectedNoteID = context.selectedNoteID();
+      osm = context.connection();
+      var selected, note, entity;
+      if (selectedNoteID && osm) {
+        selected = [_t.html("note.note") + " " + selectedNoteID];
+        note = osm.getNote(selectedNoteID);
       } else {
-        return _placement;
+        selected = context.selectedIDs().filter(function(e3) {
+          return context.hasEntity(e3);
+        });
+        if (selected.length) {
+          entity = context.entity(selected[0]);
+        }
       }
-    };
-    popover.alignment = function(val) {
-      if (arguments.length) {
-        _alignment = utilFunctor(val);
-        return popover;
+      var singular = selected.length === 1 ? selected[0] : null;
+      selection2.html("");
+      if (singular) {
+        selection2.append("h4").attr("class", "history-heading").html(singular);
       } else {
-        return _alignment;
+        selection2.append("h4").attr("class", "history-heading").call(_t.append("info_panels.selected", { n: selected.length }));
       }
-    };
-    popover.scrollContainer = function(val) {
-      if (arguments.length) {
-        _scrollContainer = utilFunctor(val);
-        return popover;
-      } else {
-        return _scrollContainer;
+      if (!singular) return;
+      if (entity) {
+        selection2.call(redrawEntity, entity);
+      } else if (note) {
+        selection2.call(redrawNote, note);
       }
-    };
-    popover.content = function(val) {
-      if (arguments.length) {
-        _content = val;
-        return popover;
-      } else {
-        return _content;
+    }
+    function redrawNote(selection2, note) {
+      if (!note || note.isNew()) {
+        selection2.append("div").call(_t.append("info_panels.history.note_no_history"));
+        return;
       }
-    };
-    popover.isShown = function() {
-      var popoverSelection = _anchorSelection.select(".popover-" + _id);
-      return !popoverSelection.empty() && popoverSelection.classed("in");
-    };
-    popover.show = function() {
-      _anchorSelection.each(show);
-    };
-    popover.updateContent = function() {
-      _anchorSelection.each(updateContent);
-    };
-    popover.hide = function() {
-      _anchorSelection.each(hide);
-    };
-    popover.toggle = function() {
-      _anchorSelection.each(toggle);
-    };
-    popover.destroy = function(selection2, selector) {
-      selector = selector || ".popover-" + _id;
-      selection2.on(_pointerPrefix + "enter.popover", null).on(_pointerPrefix + "leave.popover", null).on(_pointerPrefix + "up.popover", null).on(_pointerPrefix + "down.popover", null).on("click.popover", null).attr("title", function() {
-        return this.getAttribute("data-original-title") || this.getAttribute("title");
-      }).attr("data-original-title", null).selectAll(selector).remove();
-    };
-    popover.destroyAny = function(selection2) {
-      selection2.call(popover.destroy, ".popover");
-    };
-    function setup() {
-      var anchor = select_default2(this);
-      var animate = _animation.apply(this, arguments);
-      var popoverSelection = anchor.selectAll(".popover-" + _id).data([0]);
-      var enter = popoverSelection.enter().append("div").attr("class", "popover popover-" + _id + " " + (klass ? klass : "")).classed("arrowed", _hasArrow.apply(this, arguments));
-      enter.append("div").attr("class", "popover-arrow");
-      enter.append("div").attr("class", "popover-inner");
-      popoverSelection = enter.merge(popoverSelection);
-      if (animate) {
-        popoverSelection.classed("fade", true);
-      }
-      var display = _displayType.apply(this, arguments);
-      if (display === "hover") {
-        var _lastNonMouseEnterTime;
-        anchor.on(_pointerPrefix + "enter.popover", function(d3_event) {
-          if (d3_event.pointerType) {
-            if (d3_event.pointerType !== "mouse") {
-              _lastNonMouseEnterTime = d3_event.timeStamp;
-              return;
-            } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
-              return;
-            }
-          }
-          if (d3_event.buttons !== 0)
-            return;
-          show.apply(this, arguments);
-        }).on(_pointerPrefix + "leave.popover", function() {
-          hide.apply(this, arguments);
-        }).on("focus.popover", function() {
-          show.apply(this, arguments);
-        }).on("blur.popover", function() {
-          hide.apply(this, arguments);
-        });
-      } else if (display === "clickFocus") {
-        anchor.on(_pointerPrefix + "down.popover", function(d3_event) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-        }).on(_pointerPrefix + "up.popover", function(d3_event) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-        }).on("click.popover", toggle);
-        popoverSelection.attr("tabindex", 0).on("blur.popover", function() {
-          anchor.each(function() {
-            hide.apply(this, arguments);
-          });
-        });
-      }
-    }
-    function show() {
-      var anchor = select_default2(this);
-      var popoverSelection = anchor.selectAll(".popover-" + _id);
-      if (popoverSelection.empty()) {
-        anchor.call(popover.destroy);
-        anchor.each(setup);
-        popoverSelection = anchor.selectAll(".popover-" + _id);
-      }
-      popoverSelection.classed("in", true);
-      var displayType = _displayType.apply(this, arguments);
-      if (displayType === "clickFocus") {
-        anchor.classed("active", true);
-        popoverSelection.node().focus();
-      }
-      anchor.each(updateContent);
-    }
-    function updateContent() {
-      var anchor = select_default2(this);
-      if (_content) {
-        anchor.selectAll(".popover-" + _id + " > .popover-inner").call(_content.apply(this, arguments));
-      }
-      updatePosition.apply(this, arguments);
-      updatePosition.apply(this, arguments);
-      updatePosition.apply(this, arguments);
-    }
-    function updatePosition() {
-      var anchor = select_default2(this);
-      var popoverSelection = anchor.selectAll(".popover-" + _id);
-      var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
-      var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
-      var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
-      var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
-      var placement = _placement.apply(this, arguments);
-      popoverSelection.classed("left", false).classed("right", false).classed("top", false).classed("bottom", false).classed(placement, true);
-      var alignment = _alignment.apply(this, arguments);
-      var alignFactor = 0.5;
-      if (alignment === "leading") {
-        alignFactor = 0;
-      } else if (alignment === "trailing") {
-        alignFactor = 1;
-      }
-      var anchorFrame = getFrame(anchor.node());
-      var popoverFrame = getFrame(popoverSelection.node());
-      var position;
-      switch (placement) {
-        case "top":
-          position = {
-            x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
-            y: anchorFrame.y - popoverFrame.h
-          };
-          break;
-        case "bottom":
-          position = {
-            x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
-            y: anchorFrame.y + anchorFrame.h
-          };
-          break;
-        case "left":
-          position = {
-            x: anchorFrame.x - popoverFrame.w,
-            y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
-          };
-          break;
-        case "right":
-          position = {
-            x: anchorFrame.x + anchorFrame.w,
-            y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
-          };
-          break;
-      }
-      if (position) {
-        if (scrollNode && (placement === "top" || placement === "bottom")) {
-          var initialPosX = position.x;
-          if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
-            position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
-          } else if (position.x < 10) {
-            position.x = 10;
-          }
-          var arrow = anchor.selectAll(".popover-" + _id + " > .popover-arrow");
-          var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
-          arrow.style("left", ~~arrowPosX + "px");
-        }
-        popoverSelection.style("left", ~~position.x + "px").style("top", ~~position.y + "px");
-      } else {
-        popoverSelection.style("left", null).style("top", null);
+      var list2 = selection2.append("ul");
+      list2.append("li").call(_t.append("info_panels.history.note_comments", { suffix: ":" })).append("span").text(note.comments.length);
+      if (note.comments.length) {
+        list2.append("li").call(_t.append("info_panels.history.note_created_date", { suffix: ":" })).append("span").text(displayTimestamp(note.comments[0].date));
+        list2.append("li").call(_t.append("info_panels.history.note_created_user", { suffix: ":" })).call(displayUser, note.comments[0].user);
       }
-      function getFrame(node) {
-        var positionStyle = select_default2(node).style("position");
-        if (positionStyle === "absolute" || positionStyle === "static") {
-          return {
-            x: node.offsetLeft - scrollLeft,
-            y: node.offsetTop - scrollTop,
-            w: node.offsetWidth,
-            h: node.offsetHeight
-          };
-        } else {
-          return {
-            x: 0,
-            y: 0,
-            w: node.offsetWidth,
-            h: node.offsetHeight
-          };
-        }
+      if (osm) {
+        selection2.append("a").attr("class", "view-history-on-osm").attr("target", "_blank").attr("href", osm.noteURL(note)).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("info_panels.history.note_link_text"));
       }
     }
-    function hide() {
-      var anchor = select_default2(this);
-      if (_displayType.apply(this, arguments) === "clickFocus") {
-        anchor.classed("active", false);
+    function redrawEntity(selection2, entity) {
+      if (!entity || entity.isNew()) {
+        selection2.append("div").call(_t.append("info_panels.history.no_history"));
+        return;
       }
-      anchor.selectAll(".popover-" + _id).classed("in", false);
-    }
-    function toggle() {
-      if (select_default2(this).select(".popover-" + _id).classed("in")) {
-        hide.apply(this, arguments);
-      } else {
-        show.apply(this, arguments);
+      var links = selection2.append("div").attr("class", "links");
+      if (osm) {
+        links.append("a").attr("class", "view-history-on-osm").attr("href", osm.historyURL(entity)).attr("target", "_blank").call(_t.append("info_panels.history.history_link"));
       }
+      links.append("a").attr("class", "pewu-history-viewer-link").attr("href", "https://pewu.github.io/osm-history/#/" + entity.type + "/" + entity.osmId()).attr("target", "_blank").attr("tabindex", -1).text("PeWu");
+      var list2 = selection2.append("ul");
+      list2.append("li").call(_t.append("info_panels.history.version", { suffix: ":" })).append("span").text(entity.version);
+      list2.append("li").call(_t.append("info_panels.history.last_edit", { suffix: ":" })).append("span").text(displayTimestamp(entity.timestamp));
+      list2.append("li").call(_t.append("info_panels.history.edited_by", { suffix: ":" })).call(displayUser, entity.user);
+      list2.append("li").call(_t.append("info_panels.history.changeset", { suffix: ":" })).call(displayChangeset, entity.changeset);
     }
-    return popover;
-  }
-
-  // modules/ui/tooltip.js
-  function uiTooltip(klass) {
-    var tooltip = uiPopover((klass || "") + " tooltip").displayType("hover");
-    var _title = function() {
-      var title = this.getAttribute("data-original-title");
-      if (title) {
-        return title;
-      } else {
-        title = this.getAttribute("title");
-        this.removeAttribute("title");
-        this.setAttribute("data-original-title", title);
-      }
-      return title;
-    };
-    var _heading = utilFunctor(null);
-    var _keys = utilFunctor(null);
-    tooltip.title = function(val) {
-      if (!arguments.length)
-        return _title;
-      _title = utilFunctor(val);
-      return tooltip;
-    };
-    tooltip.heading = function(val) {
-      if (!arguments.length)
-        return _heading;
-      _heading = utilFunctor(val);
-      return tooltip;
+    var panel = function(selection2) {
+      selection2.call(redraw);
+      context.map().on("drawn.info-history", function() {
+        selection2.call(redraw);
+      });
+      context.on("enter.info-history", function() {
+        selection2.call(redraw);
+      });
     };
-    tooltip.keys = function(val) {
-      if (!arguments.length)
-        return _keys;
-      _keys = utilFunctor(val);
-      return tooltip;
+    panel.off = function() {
+      context.map().on("drawn.info-history", null);
+      context.on("enter.info-history", null);
     };
-    tooltip.content(function() {
-      var heading2 = _heading.apply(this, arguments);
-      var text = _title.apply(this, arguments);
-      var keys2 = _keys.apply(this, arguments);
-      var headingCallback = typeof heading2 === "function" ? heading2 : (s2) => s2.text(heading2);
-      var textCallback = typeof text === "function" ? text : (s2) => s2.text(text);
-      return function(selection2) {
-        var headingSelect = selection2.selectAll(".tooltip-heading").data(heading2 ? [heading2] : []);
-        headingSelect.exit().remove();
-        headingSelect.enter().append("div").attr("class", "tooltip-heading").merge(headingSelect).text("").call(headingCallback);
-        var textSelect = selection2.selectAll(".tooltip-text").data(text ? [text] : []);
-        textSelect.exit().remove();
-        textSelect.enter().append("div").attr("class", "tooltip-text").merge(textSelect).text("").call(textCallback);
-        var keyhintWrap = selection2.selectAll(".keyhint-wrap").data(keys2 && keys2.length ? [0] : []);
-        keyhintWrap.exit().remove();
-        var keyhintWrapEnter = keyhintWrap.enter().append("div").attr("class", "keyhint-wrap");
-        keyhintWrapEnter.append("span").call(_t.append("tooltip_keyhint"));
-        keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
-        keyhintWrap.selectAll("kbd.shortcut").data(keys2 && keys2.length ? keys2 : []).enter().append("kbd").attr("class", "shortcut").text(function(d2) {
-          return d2;
-        });
-      };
-    });
-    return tooltip;
+    panel.id = "history";
+    panel.label = _t.append("info_panels.history.title");
+    panel.key = _t("info_panels.history.key");
+    return panel;
   }
 
-  // modules/ui/edit_menu.js
-  function uiEditMenu(context) {
-    var dispatch14 = dispatch_default("toggled");
-    var _menu = select_default2(null);
-    var _operations = [];
-    var _anchorLoc = [0, 0];
-    var _anchorLocLonLat = [0, 0];
-    var _triggerType = "";
-    var _vpTopMargin = 85;
-    var _vpBottomMargin = 45;
-    var _vpSideMargin = 35;
-    var _menuTop = false;
-    var _menuHeight;
-    var _menuWidth;
-    var _verticalPadding = 4;
-    var _tooltipWidth = 210;
-    var _menuSideMargin = 10;
-    var _tooltips = [];
-    var editMenu = function(selection2) {
-      var isTouchMenu = _triggerType.includes("touch") || _triggerType.includes("pen");
-      var ops = _operations.filter(function(op) {
-        return !isTouchMenu || !op.mouseOnly;
-      });
-      if (!ops.length)
-        return;
-      _tooltips = [];
-      _menuTop = isTouchMenu;
-      var showLabels = isTouchMenu;
-      var buttonHeight = showLabels ? 32 : 34;
-      if (showLabels) {
-        _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function(op) {
-          return op.title.length;
-        })));
-      } else {
-        _menuWidth = 44;
+  // modules/ui/panels/location.js
+  function uiPanelLocation(context) {
+    var currLocation = "";
+    function redraw(selection2) {
+      selection2.html("");
+      var list2 = selection2.append("ul");
+      var coord2 = context.map().mouseCoordinates();
+      if (coord2.some(isNaN)) {
+        coord2 = context.map().center();
       }
-      _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
-      _menu = selection2.append("div").attr("class", "edit-menu").classed("touch-menu", isTouchMenu).style("padding", _verticalPadding + "px 0");
-      var buttons = _menu.selectAll(".edit-menu-item").data(ops);
-      var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
-        return "edit-menu-item edit-menu-item-" + d2.id;
-      }).style("height", buttonHeight + "px").on("click", click).on("pointerup", pointerup).on("pointerdown mousedown", function pointerdown(d3_event) {
-        d3_event.stopPropagation();
-      }).on("mouseenter.highlight", function(d3_event, d2) {
-        if (!d2.relatedEntityIds || select_default2(this).classed("disabled"))
-          return;
-        utilHighlightEntities(d2.relatedEntityIds(), true, context);
-      }).on("mouseleave.highlight", function(d3_event, d2) {
-        if (!d2.relatedEntityIds)
-          return;
-        utilHighlightEntities(d2.relatedEntityIds(), false, context);
-      });
-      buttonsEnter.each(function(d2) {
-        var tooltip = uiTooltip().heading(() => d2.title).title(d2.tooltip).keys([d2.keys[0]]);
-        _tooltips.push(tooltip);
-        select_default2(this).call(tooltip).append("div").attr("class", "icon-wrap").call(svgIcon(d2.icon && d2.icon() || "#iD-operation-" + d2.id, "operation"));
-      });
-      if (showLabels) {
-        buttonsEnter.append("span").attr("class", "label").each(function(d2) {
-          select_default2(this).call(d2.title);
+      list2.append("li").text(dmsCoordinatePair(coord2)).append("li").text(decimalCoordinatePair(coord2));
+      selection2.append("div").attr("class", "location-info").text(currLocation || " ");
+      debouncedGetLocation(selection2, coord2);
+    }
+    var debouncedGetLocation = debounce_default(getLocation, 250);
+    function getLocation(selection2, coord2) {
+      if (!services.geocoder) {
+        currLocation = _t("info_panels.location.unknown_location");
+        selection2.selectAll(".location-info").text(currLocation);
+      } else {
+        services.geocoder.reverse(coord2, function(err, result) {
+          currLocation = result ? result.display_name : _t("info_panels.location.unknown_location");
+          selection2.selectAll(".location-info").text(currLocation);
         });
       }
-      buttonsEnter.merge(buttons).classed("disabled", function(d2) {
-        return d2.disabled();
-      });
-      updatePosition();
-      var initialScale = context.projection.scale();
-      context.map().on("move.edit-menu", function() {
-        if (initialScale !== context.projection.scale()) {
-          editMenu.close();
-        }
-      }).on("drawn.edit-menu", function(info) {
-        if (info.full)
-          updatePosition();
+    }
+    var panel = function(selection2) {
+      selection2.call(redraw);
+      context.surface().on(("PointerEvent" in window ? "pointer" : "mouse") + "move.info-location", function() {
+        selection2.call(redraw);
       });
-      var lastPointerUpType;
-      function pointerup(d3_event) {
-        lastPointerUpType = d3_event.pointerType;
-      }
-      function click(d3_event, operation2) {
-        d3_event.stopPropagation();
-        if (operation2.relatedEntityIds) {
-          utilHighlightEntities(operation2.relatedEntityIds(), false, context);
-        }
-        if (operation2.disabled()) {
-          if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
-            context.ui().flash.duration(4e3).iconName("#iD-operation-" + operation2.id).iconClass("operation disabled").label(operation2.tooltip())();
-          }
-        } else {
-          if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
-            context.ui().flash.duration(2e3).iconName("#iD-operation-" + operation2.id).iconClass("operation").label(operation2.annotation() || operation2.title)();
-          }
-          operation2();
-          editMenu.close();
-        }
-        lastPointerUpType = null;
-      }
-      dispatch14.call("toggled", this, true);
     };
-    function updatePosition() {
-      if (!_menu || _menu.empty())
-        return;
-      var anchorLoc = context.projection(_anchorLocLonLat);
-      var viewport = context.surfaceRect();
-      if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
-        editMenu.close();
-        return;
+    panel.off = function() {
+      context.surface().on(".info-location", null);
+    };
+    panel.id = "location";
+    panel.label = _t.append("info_panels.location.title");
+    panel.key = _t("info_panels.location.key");
+    return panel;
+  }
+
+  // modules/ui/panels/measurement.js
+  function uiPanelMeasurement(context) {
+    function radiansToMeters(r2) {
+      return r2 * 63710071809e-4;
+    }
+    function steradiansToSqmeters(r2) {
+      return r2 / (4 * Math.PI) * 510065621724e3;
+    }
+    function toLineString(feature3) {
+      if (feature3.type === "LineString") return feature3;
+      var result = { type: "LineString", coordinates: [] };
+      if (feature3.type === "Polygon") {
+        result.coordinates = feature3.coordinates[0];
+      } else if (feature3.type === "MultiPolygon") {
+        result.coordinates = feature3.coordinates[0][0];
       }
-      var menuLeft = displayOnLeft(viewport);
-      var offset = [0, 0];
-      offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
-      if (_menuTop) {
-        if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
-          offset[1] = -anchorLoc[1] + _vpTopMargin;
-        } else {
-          offset[1] = -_menuHeight;
-        }
+      return result;
+    }
+    var _isImperial = !_mainLocalizer.usesMetric();
+    function redraw(selection2) {
+      var graph = context.graph();
+      var selectedNoteID = context.selectedNoteID();
+      var osm = services.osm;
+      var localeCode = _mainLocalizer.localeCode();
+      var heading2;
+      var center, location, centroid;
+      var closed, geometry;
+      var totalNodeCount, length2 = 0, area = 0, distance;
+      if (selectedNoteID && osm) {
+        var note = osm.getNote(selectedNoteID);
+        heading2 = _t.html("note.note") + " " + selectedNoteID;
+        location = note.loc;
+        geometry = "note";
       } else {
-        if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
-          offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
-        } else {
-          offset[1] = 0;
-        }
-      }
-      var origin = geoVecAdd(anchorLoc, offset);
-      _menu.style("left", origin[0] + "px").style("top", origin[1] + "px");
-      var tooltipSide = tooltipPosition(viewport, menuLeft);
-      _tooltips.forEach(function(tooltip) {
-        tooltip.placement(tooltipSide);
-      });
-      function displayOnLeft(viewport2) {
-        if (_mainLocalizer.textDirection() === "ltr") {
-          if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport2.width - _vpSideMargin) {
-            return true;
-          }
-          return false;
-        } else {
-          if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
-            return false;
+        var selectedIDs = context.selectedIDs().filter(function(id2) {
+          return context.hasEntity(id2);
+        });
+        var selected = selectedIDs.map(function(id2) {
+          return context.entity(id2);
+        });
+        heading2 = selected.length === 1 ? selected[0].id : _t.html("info_panels.selected", { n: selected.length });
+        if (selected.length) {
+          var extent = geoExtent();
+          for (var i3 in selected) {
+            var entity = selected[i3];
+            extent._extend(entity.extent(graph));
+            geometry = entity.geometry(graph);
+            if (geometry === "line" || geometry === "area") {
+              closed = entity.type === "relation" || entity.isClosed() && !entity.isDegenerate();
+              var feature3 = entity.asGeoJSON(graph);
+              length2 += radiansToMeters(length_default(toLineString(feature3)));
+              centroid = path_default(context.projection).centroid(entity.asGeoJSON(graph));
+              centroid = centroid && context.projection.invert(centroid);
+              if (!centroid || !isFinite(centroid[0]) || !isFinite(centroid[1])) {
+                centroid = entity.extent(graph).center();
+              }
+              if (closed) {
+                area += steradiansToSqmeters(entity.area(graph));
+              }
+            }
           }
-          return true;
-        }
-      }
-      function tooltipPosition(viewport2, menuLeft2) {
-        if (_mainLocalizer.textDirection() === "ltr") {
-          if (menuLeft2) {
-            return "left";
+          if (selected.length > 1) {
+            geometry = null;
+            closed = null;
+            centroid = null;
           }
-          if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport2.width - _vpSideMargin) {
-            return "left";
+          if (selected.length === 2 && selected[0].type === "node" && selected[1].type === "node") {
+            distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
           }
-          return "right";
-        } else {
-          if (!menuLeft2) {
-            return "right";
+          if (selected.length === 1 && selected[0].type === "node") {
+            location = selected[0].loc;
+          } else {
+            totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
           }
-          if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
-            return "right";
+          if (!location && !centroid) {
+            center = extent.center();
           }
-          return "left";
         }
       }
-    }
-    editMenu.close = function() {
-      context.map().on("move.edit-menu", null).on("drawn.edit-menu", null);
-      _menu.remove();
-      _tooltips = [];
-      dispatch14.call("toggled", this, false);
-    };
-    editMenu.anchorLoc = function(val) {
-      if (!arguments.length)
-        return _anchorLoc;
-      _anchorLoc = val;
-      _anchorLocLonLat = context.projection.invert(_anchorLoc);
-      return editMenu;
-    };
-    editMenu.triggerType = function(val) {
-      if (!arguments.length)
-        return _triggerType;
-      _triggerType = val;
-      return editMenu;
-    };
-    editMenu.operations = function(val) {
-      if (!arguments.length)
-        return _operations;
-      _operations = val;
-      return editMenu;
-    };
-    return utilRebind(editMenu, dispatch14, "on");
-  }
-
-  // modules/ui/feature_info.js
-  function uiFeatureInfo(context) {
-    function update(selection2) {
-      var features = context.features();
-      var stats = features.stats();
-      var count = 0;
-      var hiddenList = features.hidden().map(function(k2) {
-        if (stats[k2]) {
-          count += stats[k2];
-          return _t.append("inspector.title_count", {
-            title: _t("feature." + k2 + ".description"),
-            count: stats[k2]
-          });
-        }
-        return null;
-      }).filter(Boolean);
-      selection2.text("");
-      if (hiddenList.length) {
-        var tooltipBehavior = uiTooltip().placement("top").title(function() {
-          return (selection3) => {
-            hiddenList.forEach((hiddenFeature) => {
-              selection3.append("div").call(hiddenFeature);
-            });
-          };
-        });
-        selection2.append("a").attr("class", "chip").attr("href", "#").call(_t.append("feature_info.hidden_warning", { count })).call(tooltipBehavior).on("click", function(d3_event) {
-          tooltipBehavior.hide();
-          d3_event.preventDefault();
-          context.ui().togglePanes(context.container().select(".map-panes .map-data-pane"));
-        });
+      selection2.html("");
+      if (heading2) {
+        selection2.append("h4").attr("class", "measurement-heading").html(heading2);
       }
-      selection2.classed("hide", !hiddenList.length);
-    }
-    return function(selection2) {
-      update(selection2);
-      context.features().on("change.feature_info", function() {
-        update(selection2);
-      });
-    };
-  }
-
-  // modules/ui/flash.js
-  function uiFlash(context) {
-    var _flashTimer;
-    var _duration = 2e3;
-    var _iconName = "#iD-icon-no";
-    var _iconClass = "disabled";
-    var _label = (s2) => s2.text("");
-    function flash() {
-      if (_flashTimer) {
-        _flashTimer.stop();
+      var list2 = selection2.append("ul");
+      var coordItem;
+      if (geometry) {
+        list2.append("li").call(_t.append("info_panels.measurement.geometry", { suffix: ":" })).append("span").html(
+          closed ? _t.html("info_panels.measurement.closed_" + geometry) : _t.html("geometry." + geometry)
+        );
       }
-      context.container().select(".main-footer-wrap").classed("footer-hide", true).classed("footer-show", false);
-      context.container().select(".flash-wrap").classed("footer-hide", false).classed("footer-show", true);
-      var content = context.container().select(".flash-wrap").selectAll(".flash-content").data([0]);
-      var contentEnter = content.enter().append("div").attr("class", "flash-content");
-      var iconEnter = contentEnter.append("svg").attr("class", "flash-icon icon").append("g").attr("transform", "translate(10,10)");
-      iconEnter.append("circle").attr("r", 9);
-      iconEnter.append("use").attr("transform", "translate(-7,-7)").attr("width", "14").attr("height", "14");
-      contentEnter.append("div").attr("class", "flash-text");
-      content = content.merge(contentEnter);
-      content.selectAll(".flash-icon").attr("class", "icon flash-icon " + (_iconClass || ""));
-      content.selectAll(".flash-icon use").attr("xlink:href", _iconName);
-      content.selectAll(".flash-text").attr("class", "flash-text").call(_label);
-      _flashTimer = timeout_default(function() {
-        _flashTimer = null;
-        context.container().select(".main-footer-wrap").classed("footer-hide", false).classed("footer-show", true);
-        context.container().select(".flash-wrap").classed("footer-hide", true).classed("footer-show", false);
-      }, _duration);
-      return content;
-    }
-    flash.duration = function(_2) {
-      if (!arguments.length)
-        return _duration;
-      _duration = _2;
-      return flash;
-    };
-    flash.label = function(_2) {
-      if (!arguments.length)
-        return _label;
-      if (typeof _2 !== "function") {
-        _label = (selection2) => selection2.text(_2);
-      } else {
-        _label = (selection2) => selection2.text("").call(_2);
+      if (totalNodeCount) {
+        list2.append("li").call(_t.append("info_panels.measurement.node_count", { suffix: ":" })).append("span").text(totalNodeCount.toLocaleString(localeCode));
       }
-      return flash;
-    };
-    flash.iconName = function(_2) {
-      if (!arguments.length)
-        return _iconName;
-      _iconName = _2;
-      return flash;
-    };
-    flash.iconClass = function(_2) {
-      if (!arguments.length)
-        return _iconClass;
-      _iconClass = _2;
-      return flash;
-    };
-    return flash;
-  }
-
-  // modules/ui/full_screen.js
-  function uiFullScreen(context) {
-    var element = context.container().node();
-    function getFullScreenFn() {
-      if (element.requestFullscreen) {
-        return element.requestFullscreen;
-      } else if (element.msRequestFullscreen) {
-        return element.msRequestFullscreen;
-      } else if (element.mozRequestFullScreen) {
-        return element.mozRequestFullScreen;
-      } else if (element.webkitRequestFullscreen) {
-        return element.webkitRequestFullscreen;
+      if (area) {
+        list2.append("li").call(_t.append("info_panels.measurement.area", { suffix: ":" })).append("span").text(displayArea(area, _isImperial));
       }
-    }
-    function getExitFullScreenFn() {
-      if (document.exitFullscreen) {
-        return document.exitFullscreen;
-      } else if (document.msExitFullscreen) {
-        return document.msExitFullscreen;
-      } else if (document.mozCancelFullScreen) {
-        return document.mozCancelFullScreen;
-      } else if (document.webkitExitFullscreen) {
-        return document.webkitExitFullscreen;
+      if (length2) {
+        list2.append("li").call(_t.append("info_panels.measurement." + (closed ? "perimeter" : "length"), { suffix: ":" })).append("span").text(displayLength(length2, _isImperial));
       }
-    }
-    function isFullScreen() {
-      return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
-    }
-    function isSupported() {
-      return !!getFullScreenFn();
-    }
-    function fullScreen(d3_event) {
-      d3_event.preventDefault();
-      if (!isFullScreen()) {
-        getFullScreenFn().apply(element);
-      } else {
-        getExitFullScreenFn().apply(document);
+      if (typeof distance === "number") {
+        list2.append("li").call(_t.append("info_panels.measurement.distance", { suffix: ":" })).append("span").text(displayLength(distance, _isImperial));
       }
-    }
-    return function() {
-      if (!isSupported())
-        return;
-      var detected = utilDetect();
-      var keys2 = detected.os === "mac" ? [uiCmd("\u2303\u2318F"), "f11"] : ["f11"];
-      context.keybinding().on(keys2, fullScreen);
-    };
-  }
-
-  // modules/ui/geolocate.js
-  function uiGeolocate(context) {
-    var _geolocationOptions = {
-      // prioritize speed and power usage over precision
-      enableHighAccuracy: false,
-      // don't hang indefinitely getting the location
-      timeout: 6e3
-      // 6sec
-    };
-    var _locating = uiLoading(context).message(_t.html("geolocate.locating")).blocking(true);
-    var _layer = context.layers().layer("geolocate");
-    var _position;
-    var _extent;
-    var _timeoutID;
-    var _button = select_default2(null);
-    function click() {
-      if (context.inIntro())
-        return;
-      if (!_layer.enabled() && !_locating.isShown()) {
-        _timeoutID = setTimeout(
-          error,
-          1e4
-          /* 10sec */
-        );
-        context.container().call(_locating);
-        navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
-      } else {
-        _locating.close();
-        _layer.enabled(null, false);
-        updateButtonState();
+      if (location) {
+        coordItem = list2.append("li").call(_t.append("info_panels.measurement.location", { suffix: ":" }));
+        coordItem.append("span").text(dmsCoordinatePair(location));
+        coordItem.append("span").text(decimalCoordinatePair(location));
       }
-    }
-    function zoomTo() {
-      context.enter(modeBrowse(context));
-      var map2 = context.map();
-      _layer.enabled(_position, true);
-      updateButtonState();
-      map2.centerZoomEase(_extent.center(), Math.min(20, map2.extentZoom(_extent)));
-    }
-    function success(geolocation) {
-      _position = geolocation;
-      var coords = _position.coords;
-      _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
-      zoomTo();
-      finish();
-    }
-    function error() {
-      if (_position) {
-        zoomTo();
-      } else {
-        context.ui().flash.label(_t.append("geolocate.location_unavailable")).iconName("#iD-icon-geolocate")();
+      if (centroid) {
+        coordItem = list2.append("li").call(_t.append("info_panels.measurement.centroid", { suffix: ":" }));
+        coordItem.append("span").text(dmsCoordinatePair(centroid));
+        coordItem.append("span").text(decimalCoordinatePair(centroid));
       }
-      finish();
-    }
-    function finish() {
-      _locating.close();
-      if (_timeoutID) {
-        clearTimeout(_timeoutID);
+      if (center) {
+        coordItem = list2.append("li").call(_t.append("info_panels.measurement.center", { suffix: ":" }));
+        coordItem.append("span").text(dmsCoordinatePair(center));
+        coordItem.append("span").text(decimalCoordinatePair(center));
+      }
+      if (length2 || area || typeof distance === "number") {
+        var toggle = _isImperial ? "imperial" : "metric";
+        selection2.append("a").call(_t.append("info_panels.measurement." + toggle)).attr("href", "#").attr("class", "button button-toggle-units").on("click", function(d3_event) {
+          d3_event.preventDefault();
+          _isImperial = !_isImperial;
+          selection2.call(redraw);
+        });
       }
-      _timeoutID = void 0;
-    }
-    function updateButtonState() {
-      _button.classed("active", _layer.enabled());
-      _button.attr("aria-pressed", _layer.enabled());
     }
-    return function(selection2) {
-      if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition)
-        return;
-      _button = selection2.append("button").on("click", click).attr("aria-pressed", false).call(svgIcon("#iD-icon-geolocate", "light")).call(
-        uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(() => _t.append("geolocate.title")).keys([_t("geolocate.key")])
-      );
-      context.keybinding().on(_t("geolocate.key"), click);
+    var panel = function(selection2) {
+      selection2.call(redraw);
+      context.map().on("drawn.info-measurement", function() {
+        selection2.call(redraw);
+      });
+      context.on("enter.info-measurement", function() {
+        selection2.call(redraw);
+      });
     };
+    panel.off = function() {
+      context.map().on("drawn.info-measurement", null);
+      context.on("enter.info-measurement", null);
+    };
+    panel.id = "measurement";
+    panel.label = _t.append("info_panels.measurement.title");
+    panel.key = _t("info_panels.measurement.key");
+    return panel;
   }
 
-  // modules/ui/panels/background.js
-  function uiPanelBackground(context) {
-    var background = context.background();
-    var _currSourceName = null;
-    var _metadata = {};
-    var _metadataKeys = [
-      "zoom",
-      "vintage",
-      "source",
-      "description",
-      "resolution",
-      "accuracy"
-    ];
-    var debouncedRedraw = debounce_default(redraw, 250);
-    function redraw(selection2) {
-      var source = background.baseLayerSource();
-      if (!source)
-        return;
-      var isDG = source.id.match(/^DigitalGlobe/i) !== null;
-      var sourceLabel = source.label();
-      if (_currSourceName !== sourceLabel) {
-        _currSourceName = sourceLabel;
-        _metadata = {};
+  // modules/ui/panels/index.js
+  var uiInfoPanels = {
+    background: uiPanelBackground,
+    history: uiPanelHistory,
+    location: uiPanelLocation,
+    measurement: uiPanelMeasurement
+  };
+
+  // modules/ui/info.js
+  function uiInfo(context) {
+    var ids = Object.keys(uiInfoPanels);
+    var wasActive = ["measurement"];
+    var panels = {};
+    var active = {};
+    ids.forEach(function(k2) {
+      if (!panels[k2]) {
+        panels[k2] = uiInfoPanels[k2](context);
+        active[k2] = false;
       }
-      selection2.text("");
-      var list2 = selection2.append("ul").attr("class", "background-info");
-      list2.append("li").call(_currSourceName);
-      _metadataKeys.forEach(function(k2) {
-        if (isDG && k2 === "vintage")
-          return;
-        list2.append("li").attr("class", "background-info-list-" + k2).classed("hide", !_metadata[k2]).call(_t.append("info_panels.background." + k2, { suffix: ":" })).append("span").attr("class", "background-info-span-" + k2).text(_metadata[k2]);
-      });
-      debouncedGetMetadata(selection2);
-      var toggleTiles = context.getDebug("tile") ? "hide_tiles" : "show_tiles";
-      selection2.append("a").call(_t.append("info_panels.background." + toggleTiles)).attr("href", "#").attr("class", "button button-toggle-tiles").on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.setDebug("tile", !context.getDebug("tile"));
-        selection2.call(redraw);
-      });
-      if (isDG) {
-        var key = source.id + "-vintage";
-        var sourceVintage = context.background().findSource(key);
-        var showsVintage = context.background().showsLayer(sourceVintage);
-        var toggleVintage = showsVintage ? "hide_vintage" : "show_vintage";
-        selection2.append("a").call(_t.append("info_panels.background." + toggleVintage)).attr("href", "#").attr("class", "button button-toggle-vintage").on("click", function(d3_event) {
+    });
+    function info(selection2) {
+      function redraw() {
+        var activeids = ids.filter(function(k2) {
+          return active[k2];
+        }).sort();
+        var containers = infoPanels.selectAll(".panel-container").data(activeids, function(k2) {
+          return k2;
+        });
+        containers.exit().style("opacity", 1).transition().duration(200).style("opacity", 0).on("end", function(d2) {
+          select_default2(this).call(panels[d2].off).remove();
+        });
+        var enter = containers.enter().append("div").attr("class", function(d2) {
+          return "fillD2 panel-container panel-container-" + d2;
+        });
+        enter.style("opacity", 0).transition().duration(200).style("opacity", 1);
+        var title = enter.append("div").attr("class", "panel-title fillD2");
+        title.append("h3").each(function(d2) {
+          return panels[d2].label(select_default2(this));
+        });
+        title.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function(d3_event, d2) {
+          d3_event.stopImmediatePropagation();
           d3_event.preventDefault();
-          context.background().toggleOverlayLayer(sourceVintage);
-          selection2.call(redraw);
+          info.toggle(d2);
+        }).call(svgIcon("#iD-icon-close"));
+        enter.append("div").attr("class", function(d2) {
+          return "panel-content panel-content-" + d2;
+        });
+        infoPanels.selectAll(".panel-content").each(function(d2) {
+          select_default2(this).call(panels[d2]);
         });
       }
-      ["DigitalGlobe-Premium", "DigitalGlobe-Standard"].forEach(function(layerId) {
-        if (source.id !== layerId) {
-          var key2 = layerId + "-vintage";
-          var sourceVintage2 = context.background().findSource(key2);
-          if (context.background().showsLayer(sourceVintage2)) {
-            context.background().toggleOverlayLayer(sourceVintage2);
+      info.toggle = function(which) {
+        var activeids = ids.filter(function(k2) {
+          return active[k2];
+        });
+        if (which) {
+          active[which] = !active[which];
+          if (activeids.length === 1 && activeids[0] === which) {
+            wasActive = [which];
+          }
+          context.container().select("." + which + "-panel-toggle-item").classed("active", active[which]).select("input").property("checked", active[which]);
+        } else {
+          if (activeids.length) {
+            wasActive = activeids;
+            activeids.forEach(function(k2) {
+              active[k2] = false;
+            });
+          } else {
+            wasActive.forEach(function(k2) {
+              active[k2] = true;
+            });
           }
         }
+        redraw();
+      };
+      var infoPanels = selection2.selectAll(".info-panels").data([0]);
+      infoPanels = infoPanels.enter().append("div").attr("class", "info-panels").merge(infoPanels);
+      redraw();
+      context.keybinding().on(uiCmd("\u2318" + _t("info_panels.key")), function(d3_event) {
+        d3_event.stopImmediatePropagation();
+        d3_event.preventDefault();
+        info.toggle();
       });
-    }
-    var debouncedGetMetadata = debounce_default(getMetadata, 250);
-    function getMetadata(selection2) {
-      var tile = context.container().select(".layer-background img.tile-center");
-      if (tile.empty())
-        return;
-      var sourceName = _currSourceName;
-      var d2 = tile.datum();
-      var zoom = d2 && d2.length >= 3 && d2[2] || Math.floor(context.map().zoom());
-      var center = context.map().center();
-      _metadata.zoom = String(zoom);
-      selection2.selectAll(".background-info-list-zoom").classed("hide", false).selectAll(".background-info-span-zoom").text(_metadata.zoom);
-      if (!d2 || !d2.length >= 3)
-        return;
-      background.baseLayerSource().getMetadata(center, d2, function(err, result) {
-        if (err || _currSourceName !== sourceName)
-          return;
-        var vintage = result.vintage;
-        _metadata.vintage = vintage && vintage.range || _t("info_panels.background.unknown");
-        selection2.selectAll(".background-info-list-vintage").classed("hide", false).selectAll(".background-info-span-vintage").text(_metadata.vintage);
-        _metadataKeys.forEach(function(k2) {
-          if (k2 === "zoom" || k2 === "vintage")
-            return;
-          var val = result[k2];
-          _metadata[k2] = val;
-          selection2.selectAll(".background-info-list-" + k2).classed("hide", !val).selectAll(".background-info-span-" + k2).text(val);
+      ids.forEach(function(k2) {
+        var key = _t("info_panels." + k2 + ".key", { default: null });
+        if (!key) return;
+        context.keybinding().on(uiCmd("\u2318\u21E7" + key), function(d3_event) {
+          d3_event.stopImmediatePropagation();
+          d3_event.preventDefault();
+          info.toggle(k2);
         });
       });
     }
-    var panel = function(selection2) {
-      selection2.call(redraw);
-      context.map().on("drawn.info-background", function() {
-        selection2.call(debouncedRedraw);
-      }).on("move.info-background", function() {
-        selection2.call(debouncedGetMetadata);
+    return info;
+  }
+
+  // modules/ui/toggle.js
+  function uiToggle(show, callback) {
+    return function(selection2) {
+      selection2.style("opacity", show ? 0 : 1).classed("hide", false).transition().style("opacity", show ? 1 : 0).on("end", function() {
+        select_default2(this).classed("hide", !show).style("opacity", null);
+        if (callback) callback.apply(this);
       });
     };
-    panel.off = function() {
-      context.map().on("drawn.info-background", null).on("move.info-background", null);
-    };
-    panel.id = "background";
-    panel.label = _t.append("info_panels.background.title");
-    panel.key = _t("info_panels.background.key");
-    return panel;
   }
 
-  // modules/ui/panels/history.js
-  function uiPanelHistory(context) {
-    var osm;
-    function displayTimestamp(timestamp) {
-      if (!timestamp)
-        return _t("info_panels.history.unknown");
-      var options2 = {
-        day: "numeric",
-        month: "short",
-        year: "numeric",
-        hour: "numeric",
-        minute: "numeric",
-        second: "numeric"
-      };
-      var d2 = new Date(timestamp);
-      if (isNaN(d2.getTime()))
-        return _t("info_panels.history.unknown");
-      return d2.toLocaleString(_mainLocalizer.localeCode(), options2);
-    }
-    function displayUser(selection2, userName) {
-      if (!userName) {
-        selection2.append("span").call(_t.append("info_panels.history.unknown"));
-        return;
-      }
-      selection2.append("span").attr("class", "user-name").text(userName);
-      var links = selection2.append("div").attr("class", "links");
-      if (osm) {
-        links.append("a").attr("class", "user-osm-link").attr("href", osm.userURL(userName)).attr("target", "_blank").call(_t.append("info_panels.history.profile_link"));
+  // modules/ui/curtain.js
+  function uiCurtain(containerNode) {
+    var surface = select_default2(null), tooltip = select_default2(null), darkness = select_default2(null);
+    function curtain(selection2) {
+      surface = selection2.append("svg").attr("class", "curtain").style("top", 0).style("left", 0);
+      darkness = surface.append("path").attr("x", 0).attr("y", 0).attr("class", "curtain-darkness");
+      select_default2(window).on("resize.curtain", resize);
+      tooltip = selection2.append("div").attr("class", "tooltip");
+      tooltip.append("div").attr("class", "popover-arrow");
+      tooltip.append("div").attr("class", "popover-inner");
+      resize();
+      function resize() {
+        surface.attr("width", containerNode.clientWidth).attr("height", containerNode.clientHeight);
+        curtain.cut(darkness.datum());
       }
-      links.append("a").attr("class", "user-hdyc-link").attr("href", "https://hdyc.neis-one.org/?" + userName).attr("target", "_blank").attr("tabindex", -1).text("HDYC");
     }
-    function displayChangeset(selection2, changeset) {
-      if (!changeset) {
-        selection2.append("span").call(_t.append("info_panels.history.unknown"));
-        return;
+    curtain.reveal = function(box, html3, options2) {
+      options2 = options2 || {};
+      if (typeof box === "string") {
+        box = select_default2(box).node();
       }
-      selection2.append("span").attr("class", "changeset-id").text(changeset);
-      var links = selection2.append("div").attr("class", "links");
-      if (osm) {
-        links.append("a").attr("class", "changeset-osm-link").attr("href", osm.changesetURL(changeset)).attr("target", "_blank").call(_t.append("info_panels.history.changeset_link"));
+      if (box && box.getBoundingClientRect) {
+        box = copyBox(box.getBoundingClientRect());
+        var containerRect = containerNode.getBoundingClientRect();
+        box.top -= containerRect.top;
+        box.left -= containerRect.left;
       }
-      links.append("a").attr("class", "changeset-osmcha-link").attr("href", "https://osmcha.org/changesets/" + changeset).attr("target", "_blank").text("OSMCha");
-      links.append("a").attr("class", "changeset-achavi-link").attr("href", "https://overpass-api.de/achavi/?changeset=" + changeset).attr("target", "_blank").text("Achavi");
-    }
-    function redraw(selection2) {
-      var selectedNoteID = context.selectedNoteID();
-      osm = context.connection();
-      var selected, note, entity;
-      if (selectedNoteID && osm) {
-        selected = [_t.html("note.note") + " " + selectedNoteID];
-        note = osm.getNote(selectedNoteID);
-      } else {
-        selected = context.selectedIDs().filter(function(e3) {
-          return context.hasEntity(e3);
-        });
-        if (selected.length) {
-          entity = context.entity(selected[0]);
-        }
+      if (box && options2.padding) {
+        box.top -= options2.padding;
+        box.left -= options2.padding;
+        box.bottom += options2.padding;
+        box.right += options2.padding;
+        box.height += options2.padding * 2;
+        box.width += options2.padding * 2;
       }
-      var singular = selected.length === 1 ? selected[0] : null;
-      selection2.html("");
-      if (singular) {
-        selection2.append("h4").attr("class", "history-heading").html(singular);
+      var tooltipBox;
+      if (options2.tooltipBox) {
+        tooltipBox = options2.tooltipBox;
+        if (typeof tooltipBox === "string") {
+          tooltipBox = select_default2(tooltipBox).node();
+        }
+        if (tooltipBox && tooltipBox.getBoundingClientRect) {
+          tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
+        }
       } else {
-        selection2.append("h4").attr("class", "history-heading").call(_t.append("info_panels.selected", { n: selected.length }));
-      }
-      if (!singular)
-        return;
-      if (entity) {
-        selection2.call(redrawEntity, entity);
-      } else if (note) {
-        selection2.call(redrawNote, note);
-      }
-    }
-    function redrawNote(selection2, note) {
-      if (!note || note.isNew()) {
-        selection2.append("div").call(_t.append("info_panels.history.note_no_history"));
-        return;
-      }
-      var list2 = selection2.append("ul");
-      list2.append("li").call(_t.append("info_panels.history.note_comments", { suffix: ":" })).append("span").text(note.comments.length);
-      if (note.comments.length) {
-        list2.append("li").call(_t.append("info_panels.history.note_created_date", { suffix: ":" })).append("span").text(displayTimestamp(note.comments[0].date));
-        list2.append("li").call(_t.append("info_panels.history.note_created_user", { suffix: ":" })).call(displayUser, note.comments[0].user);
-      }
-      if (osm) {
-        selection2.append("a").attr("class", "view-history-on-osm").attr("target", "_blank").attr("href", osm.noteURL(note)).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("info_panels.history.note_link_text"));
+        tooltipBox = box;
       }
-    }
-    function redrawEntity(selection2, entity) {
-      if (!entity || entity.isNew()) {
-        selection2.append("div").call(_t.append("info_panels.history.no_history"));
-        return;
+      if (tooltipBox && html3) {
+        if (html3.indexOf("**") !== -1) {
+          if (html3.indexOf("<span") === 0) {
+            html3 = html3.replace(/^(<span.*?>)(.+?)(\*\*)/, "$1<span>$2</span>$3");
+          } else {
+            html3 = html3.replace(/^(.+?)(\*\*)/, "<span>$1</span>$2");
+          }
+          html3 = html3.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
+        }
+        html3 = html3.replace(/\*(.*?)\*/g, "<em>$1</em>");
+        html3 = html3.replace(/\{br\}/g, "<br/><br/>");
+        if (options2.buttonText && options2.buttonCallback) {
+          html3 += '<div class="button-section"><button href="#" class="button action">' + options2.buttonText + "</button></div>";
+        }
+        var classes = "curtain-tooltip popover tooltip arrowed in " + (options2.tooltipClass || "");
+        tooltip.classed(classes, true).selectAll(".popover-inner").html(html3);
+        if (options2.buttonText && options2.buttonCallback) {
+          var button = tooltip.selectAll(".button-section .button.action");
+          button.on("click", function(d3_event) {
+            d3_event.preventDefault();
+            options2.buttonCallback();
+          });
+        }
+        var tip = copyBox(tooltip.node().getBoundingClientRect()), w2 = containerNode.clientWidth, h2 = containerNode.clientHeight, tooltipWidth = 200, tooltipArrow = 5, side, pos;
+        if (options2.tooltipClass === "intro-mouse") {
+          tip.height += 80;
+        }
+        if (tooltipBox.top + tooltipBox.height > h2) {
+          tooltipBox.height -= tooltipBox.top + tooltipBox.height - h2;
+        }
+        if (tooltipBox.left + tooltipBox.width > w2) {
+          tooltipBox.width -= tooltipBox.left + tooltipBox.width - w2;
+        }
+        if (tooltipBox.top + tooltipBox.height < 100) {
+          side = "bottom";
+          pos = [
+            tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
+            tooltipBox.top + tooltipBox.height
+          ];
+        } else if (tooltipBox.top > h2 - 140) {
+          side = "top";
+          pos = [
+            tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
+            tooltipBox.top - tip.height
+          ];
+        } else {
+          var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
+          if (_mainLocalizer.textDirection() === "rtl") {
+            if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
+              side = "right";
+              pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
+            } else {
+              side = "left";
+              pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
+            }
+          } else {
+            if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w2 - 70) {
+              side = "left";
+              pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
+            } else {
+              side = "right";
+              pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
+            }
+          }
+        }
+        if (options2.duration !== 0 || !tooltip.classed(side)) {
+          tooltip.call(uiToggle(true));
+        }
+        tooltip.style("top", pos[1] + "px").style("left", pos[0] + "px").attr("class", classes + " " + side);
+        var shiftY = 0;
+        if (side === "left" || side === "right") {
+          if (pos[1] < 60) {
+            shiftY = 60 - pos[1];
+          } else if (pos[1] + tip.height > h2 - 100) {
+            shiftY = h2 - pos[1] - tip.height - 100;
+          }
+        }
+        tooltip.selectAll(".popover-inner").style("top", shiftY + "px");
+      } else {
+        tooltip.classed("in", false).call(uiToggle(false));
       }
-      var links = selection2.append("div").attr("class", "links");
-      if (osm) {
-        links.append("a").attr("class", "view-history-on-osm").attr("href", osm.historyURL(entity)).attr("target", "_blank").call(_t.append("info_panels.history.history_link"));
+      curtain.cut(box, options2.duration);
+      return tooltip;
+    };
+    curtain.cut = function(datum2, duration) {
+      darkness.datum(datum2).interrupt();
+      var selection2;
+      if (duration === 0) {
+        selection2 = darkness;
+      } else {
+        selection2 = darkness.transition().duration(duration || 600).ease(linear2);
       }
-      links.append("a").attr("class", "pewu-history-viewer-link").attr("href", "https://pewu.github.io/osm-history/#/" + entity.type + "/" + entity.osmId()).attr("target", "_blank").attr("tabindex", -1).text("PeWu");
-      var list2 = selection2.append("ul");
-      list2.append("li").call(_t.append("info_panels.history.version", { suffix: ":" })).append("span").text(entity.version);
-      list2.append("li").call(_t.append("info_panels.history.last_edit", { suffix: ":" })).append("span").text(displayTimestamp(entity.timestamp));
-      list2.append("li").call(_t.append("info_panels.history.edited_by", { suffix: ":" })).call(displayUser, entity.user);
-      list2.append("li").call(_t.append("info_panels.history.changeset", { suffix: ":" })).call(displayChangeset, entity.changeset);
-    }
-    var panel = function(selection2) {
-      selection2.call(redraw);
-      context.map().on("drawn.info-history", function() {
-        selection2.call(redraw);
-      });
-      context.on("enter.info-history", function() {
-        selection2.call(redraw);
+      selection2.attr("d", function(d2) {
+        var containerWidth = containerNode.clientWidth;
+        var containerHeight = containerNode.clientHeight;
+        var string = "M 0,0 L 0," + containerHeight + " L " + containerWidth + "," + containerHeight + "L" + containerWidth + ",0 Z";
+        if (!d2) return string;
+        return string + "M" + d2.left + "," + d2.top + "L" + d2.left + "," + (d2.top + d2.height) + "L" + (d2.left + d2.width) + "," + (d2.top + d2.height) + "L" + (d2.left + d2.width) + "," + d2.top + "Z";
       });
     };
-    panel.off = function() {
-      context.map().on("drawn.info-history", null);
-      context.on("enter.info-history", null);
+    curtain.remove = function() {
+      surface.remove();
+      tooltip.remove();
+      select_default2(window).on("resize.curtain", null);
     };
-    panel.id = "history";
-    panel.label = _t.append("info_panels.history.title");
-    panel.key = _t("info_panels.history.key");
-    return panel;
+    function copyBox(src) {
+      return {
+        top: src.top,
+        right: src.right,
+        bottom: src.bottom,
+        left: src.left,
+        width: src.width,
+        height: src.height
+      };
+    }
+    return curtain;
   }
 
-  // modules/ui/panels/location.js
-  function uiPanelLocation(context) {
-    var currLocation = "";
-    function redraw(selection2) {
-      selection2.html("");
-      var list2 = selection2.append("ul");
-      var coord2 = context.map().mouseCoordinates();
-      if (coord2.some(isNaN)) {
-        coord2 = context.map().center();
-      }
-      list2.append("li").text(dmsCoordinatePair(coord2)).append("li").text(decimalCoordinatePair(coord2));
-      selection2.append("div").attr("class", "location-info").text(currLocation || " ");
-      debouncedGetLocation(selection2, coord2);
+  // modules/ui/intro/welcome.js
+  function uiIntroWelcome(context, reveal) {
+    var dispatch14 = dispatch_default("done");
+    var chapter = {
+      title: "intro.welcome.title"
+    };
+    function welcome() {
+      context.map().centerZoom([-85.63591, 41.94285], 19);
+      reveal(
+        ".intro-nav-wrap .chapter-welcome",
+        helpHtml("intro.welcome.welcome"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: practice }
+      );
     }
-    var debouncedGetLocation = debounce_default(getLocation, 250);
-    function getLocation(selection2, coord2) {
-      if (!services.geocoder) {
-        currLocation = _t("info_panels.location.unknown_location");
-        selection2.selectAll(".location-info").text(currLocation);
-      } else {
-        services.geocoder.reverse(coord2, function(err, result) {
-          currLocation = result ? result.display_name : _t("info_panels.location.unknown_location");
-          selection2.selectAll(".location-info").text(currLocation);
-        });
-      }
+    function practice() {
+      reveal(
+        ".intro-nav-wrap .chapter-welcome",
+        helpHtml("intro.welcome.practice"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: words }
+      );
     }
-    var panel = function(selection2) {
-      selection2.call(redraw);
-      context.surface().on(("PointerEvent" in window ? "pointer" : "mouse") + "move.info-location", function() {
-        selection2.call(redraw);
-      });
+    function words() {
+      reveal(
+        ".intro-nav-wrap .chapter-welcome",
+        helpHtml("intro.welcome.words"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: chapters }
+      );
+    }
+    function chapters() {
+      dispatch14.call("done");
+      reveal(
+        ".intro-nav-wrap .chapter-navigation",
+        helpHtml("intro.welcome.chapters", { next: _t("intro.navigation.title") })
+      );
+    }
+    chapter.enter = function() {
+      welcome();
     };
-    panel.off = function() {
-      context.surface().on(".info-location", null);
+    chapter.exit = function() {
+      context.container().select(".curtain-tooltip.intro-mouse").selectAll(".counter").remove();
     };
-    panel.id = "location";
-    panel.label = _t.append("info_panels.location.title");
-    panel.key = _t("info_panels.location.key");
-    return panel;
+    chapter.restart = function() {
+      chapter.exit();
+      chapter.enter();
+    };
+    return utilRebind(chapter, dispatch14, "on");
   }
 
-  // modules/ui/panels/measurement.js
-  function uiPanelMeasurement(context) {
-    function radiansToMeters(r2) {
-      return r2 * 63710071809e-4;
+  // modules/ui/intro/navigation.js
+  function uiIntroNavigation(context, reveal) {
+    var dispatch14 = dispatch_default("done");
+    var timeouts = [];
+    var hallId = "n2061";
+    var townHall = [-85.63591, 41.94285];
+    var springStreetId = "w397";
+    var springStreetEndId = "n1834";
+    var springStreet = [-85.63582, 41.94255];
+    var onewayField = _mainPresetIndex.field("oneway");
+    var maxspeedField = _mainPresetIndex.field("maxspeed");
+    var chapter = {
+      title: "intro.navigation.title"
+    };
+    function timeout2(f2, t2) {
+      timeouts.push(window.setTimeout(f2, t2));
     }
-    function steradiansToSqmeters(r2) {
-      return r2 / (4 * Math.PI) * 510065621724e3;
+    function eventCancel(d3_event) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
     }
-    function toLineString(feature3) {
-      if (feature3.type === "LineString")
-        return feature3;
-      var result = { type: "LineString", coordinates: [] };
-      if (feature3.type === "Polygon") {
-        result.coordinates = feature3.coordinates[0];
-      } else if (feature3.type === "MultiPolygon") {
-        result.coordinates = feature3.coordinates[0][0];
-      }
-      return result;
+    function isTownHallSelected() {
+      var ids = context.selectedIDs();
+      return ids.length === 1 && ids[0] === hallId;
     }
-    var _isImperial = !_mainLocalizer.usesMetric();
-    function redraw(selection2) {
-      var graph = context.graph();
-      var selectedNoteID = context.selectedNoteID();
-      var osm = services.osm;
-      var localeCode = _mainLocalizer.localeCode();
-      var heading2;
-      var center, location, centroid;
-      var closed, geometry;
-      var totalNodeCount, length2 = 0, area = 0, distance;
-      if (selectedNoteID && osm) {
-        var note = osm.getNote(selectedNoteID);
-        heading2 = _t.html("note.note") + " " + selectedNoteID;
-        location = note.loc;
-        geometry = "note";
-      } else {
-        var selectedIDs = context.selectedIDs().filter(function(id2) {
-          return context.hasEntity(id2);
-        });
-        var selected = selectedIDs.map(function(id2) {
-          return context.entity(id2);
+    function dragMap() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      var msec = transitionTime(townHall, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
+      }
+      context.map().centerZoomEase(townHall, 19, msec);
+      timeout2(function() {
+        var centerStart = context.map().center();
+        var textId = context.lastPointerType() === "mouse" ? "drag" : "drag_touch";
+        var dragString = helpHtml("intro.navigation.map_info") + "{br}" + helpHtml("intro.navigation." + textId);
+        reveal(".surface", dragString);
+        context.map().on("drawn.intro", function() {
+          reveal(".surface", dragString, { duration: 0 });
         });
-        heading2 = selected.length === 1 ? selected[0].id : _t.html("info_panels.selected", { n: selected.length });
-        if (selected.length) {
-          var extent = geoExtent();
-          for (var i3 in selected) {
-            var entity = selected[i3];
-            extent._extend(entity.extent(graph));
-            geometry = entity.geometry(graph);
-            if (geometry === "line" || geometry === "area") {
-              closed = entity.type === "relation" || entity.isClosed() && !entity.isDegenerate();
-              var feature3 = entity.asGeoJSON(graph);
-              length2 += radiansToMeters(length_default(toLineString(feature3)));
-              centroid = path_default(context.projection).centroid(entity.asGeoJSON(graph));
-              centroid = centroid && context.projection.invert(centroid);
-              if (!centroid || !isFinite(centroid[0]) || !isFinite(centroid[1])) {
-                centroid = entity.extent(graph).center();
-              }
-              if (closed) {
-                area += steradiansToSqmeters(entity.area(graph));
-              }
-            }
-          }
-          if (selected.length > 1) {
-            geometry = null;
-            closed = null;
-            centroid = null;
-          }
-          if (selected.length === 2 && selected[0].type === "node" && selected[1].type === "node") {
-            distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
-          }
-          if (selected.length === 1 && selected[0].type === "node") {
-            location = selected[0].loc;
-          } else {
-            totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
-          }
-          if (!location && !centroid) {
-            center = extent.center();
+        context.map().on("move.intro", function() {
+          var centerNow = context.map().center();
+          if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
+            context.map().on("move.intro", null);
+            timeout2(function() {
+              continueTo(zoomMap);
+            }, 3e3);
           }
-        }
+        });
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
       }
-      selection2.html("");
-      if (heading2) {
-        selection2.append("h4").attr("class", "measurement-heading").html(heading2);
+    }
+    function zoomMap() {
+      var zoomStart = context.map().zoom();
+      var textId = context.lastPointerType() === "mouse" ? "zoom" : "zoom_touch";
+      var zoomString = helpHtml("intro.navigation." + textId);
+      reveal(".surface", zoomString);
+      context.map().on("drawn.intro", function() {
+        reveal(".surface", zoomString, { duration: 0 });
+      });
+      context.map().on("move.intro", function() {
+        if (context.map().zoom() !== zoomStart) {
+          context.map().on("move.intro", null);
+          timeout2(function() {
+            continueTo(features);
+          }, 3e3);
+        }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
       }
-      var list2 = selection2.append("ul");
-      var coordItem;
-      if (geometry) {
-        list2.append("li").call(_t.append("info_panels.measurement.geometry", { suffix: ":" })).append("span").html(
-          closed ? _t.html("info_panels.measurement.closed_" + geometry) : _t.html("geometry." + geometry)
+    }
+    function features() {
+      var onClick = function() {
+        continueTo(pointsLinesAreas);
+      };
+      reveal(
+        ".surface",
+        helpHtml("intro.navigation.features"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("drawn.intro", function() {
+        reveal(
+          ".surface",
+          helpHtml("intro.navigation.features"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
         );
-      }
-      if (totalNodeCount) {
-        list2.append("li").call(_t.append("info_panels.measurement.node_count", { suffix: ":" })).append("span").text(totalNodeCount.toLocaleString(localeCode));
-      }
-      if (area) {
-        list2.append("li").call(_t.append("info_panels.measurement.area", { suffix: ":" })).append("span").text(displayArea(area, _isImperial));
-      }
-      if (length2) {
-        list2.append("li").call(_t.append("info_panels.measurement." + (closed ? "perimeter" : "length"), { suffix: ":" })).append("span").text(displayLength(length2, _isImperial));
-      }
-      if (typeof distance === "number") {
-        list2.append("li").call(_t.append("info_panels.measurement.distance", { suffix: ":" })).append("span").text(displayLength(distance, _isImperial));
-      }
-      if (location) {
-        coordItem = list2.append("li").call(_t.append("info_panels.measurement.location", { suffix: ":" }));
-        coordItem.append("span").text(dmsCoordinatePair(location));
-        coordItem.append("span").text(decimalCoordinatePair(location));
-      }
-      if (centroid) {
-        coordItem = list2.append("li").call(_t.append("info_panels.measurement.centroid", { suffix: ":" }));
-        coordItem.append("span").text(dmsCoordinatePair(centroid));
-        coordItem.append("span").text(decimalCoordinatePair(centroid));
-      }
-      if (center) {
-        coordItem = list2.append("li").call(_t.append("info_panels.measurement.center", { suffix: ":" }));
-        coordItem.append("span").text(dmsCoordinatePair(center));
-        coordItem.append("span").text(decimalCoordinatePair(center));
-      }
-      if (length2 || area || typeof distance === "number") {
-        var toggle = _isImperial ? "imperial" : "metric";
-        selection2.append("a").call(_t.append("info_panels.measurement." + toggle)).attr("href", "#").attr("class", "button button-toggle-units").on("click", function(d3_event) {
-          d3_event.preventDefault();
-          _isImperial = !_isImperial;
-          selection2.call(redraw);
-        });
+      });
+      function continueTo(nextStep) {
+        context.map().on("drawn.intro", null);
+        nextStep();
       }
     }
-    var panel = function(selection2) {
-      selection2.call(redraw);
-      context.map().on("drawn.info-measurement", function() {
-        selection2.call(redraw);
+    function pointsLinesAreas() {
+      var onClick = function() {
+        continueTo(nodesWays);
+      };
+      reveal(
+        ".surface",
+        helpHtml("intro.navigation.points_lines_areas"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("drawn.intro", function() {
+        reveal(
+          ".surface",
+          helpHtml("intro.navigation.points_lines_areas"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+        );
       });
-      context.on("enter.info-measurement", function() {
-        selection2.call(redraw);
+      function continueTo(nextStep) {
+        context.map().on("drawn.intro", null);
+        nextStep();
+      }
+    }
+    function nodesWays() {
+      var onClick = function() {
+        continueTo(clickTownHall);
+      };
+      reveal(
+        ".surface",
+        helpHtml("intro.navigation.nodes_ways"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("drawn.intro", function() {
+        reveal(
+          ".surface",
+          helpHtml("intro.navigation.nodes_ways"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+        );
       });
-    };
-    panel.off = function() {
-      context.map().on("drawn.info-measurement", null);
-      context.on("enter.info-measurement", null);
-    };
-    panel.id = "measurement";
-    panel.label = _t.append("info_panels.measurement.title");
-    panel.key = _t("info_panels.measurement.key");
-    return panel;
-  }
-
-  // modules/ui/panels/index.js
-  var uiInfoPanels = {
-    background: uiPanelBackground,
-    history: uiPanelHistory,
-    location: uiPanelLocation,
-    measurement: uiPanelMeasurement
-  };
-
-  // modules/ui/info.js
-  function uiInfo(context) {
-    var ids = Object.keys(uiInfoPanels);
-    var wasActive = ["measurement"];
-    var panels = {};
-    var active = {};
-    ids.forEach(function(k2) {
-      if (!panels[k2]) {
-        panels[k2] = uiInfoPanels[k2](context);
-        active[k2] = false;
+      function continueTo(nextStep) {
+        context.map().on("drawn.intro", null);
+        nextStep();
       }
-    });
-    function info(selection2) {
-      function redraw() {
-        var activeids = ids.filter(function(k2) {
-          return active[k2];
-        }).sort();
-        var containers = infoPanels.selectAll(".panel-container").data(activeids, function(k2) {
-          return k2;
-        });
-        containers.exit().style("opacity", 1).transition().duration(200).style("opacity", 0).on("end", function(d2) {
-          select_default2(this).call(panels[d2].off).remove();
-        });
-        var enter = containers.enter().append("div").attr("class", function(d2) {
-          return "fillD2 panel-container panel-container-" + d2;
-        });
-        enter.style("opacity", 0).transition().duration(200).style("opacity", 1);
-        var title = enter.append("div").attr("class", "panel-title fillD2");
-        title.append("h3").each(function(d2) {
-          return panels[d2].label(select_default2(this));
-        });
-        title.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function(d3_event, d2) {
-          d3_event.stopImmediatePropagation();
-          d3_event.preventDefault();
-          info.toggle(d2);
-        }).call(svgIcon("#iD-icon-close"));
-        enter.append("div").attr("class", function(d2) {
-          return "panel-content panel-content-" + d2;
-        });
-        infoPanels.selectAll(".panel-content").each(function(d2) {
-          select_default2(this).call(panels[d2]);
+    }
+    function clickTownHall() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      var entity = context.hasEntity(hallId);
+      if (!entity) return;
+      reveal(null, null, { duration: 0 });
+      context.map().centerZoomEase(entity.loc, 19, 500);
+      timeout2(function() {
+        var entity2 = context.hasEntity(hallId);
+        if (!entity2) return;
+        var box = pointBox(entity2.loc, context);
+        var textId = context.lastPointerType() === "mouse" ? "click_townhall" : "tap_townhall";
+        reveal(box, helpHtml("intro.navigation." + textId));
+        context.map().on("move.intro drawn.intro", function() {
+          var entity3 = context.hasEntity(hallId);
+          if (!entity3) return;
+          var box2 = pointBox(entity3.loc, context);
+          reveal(box2, helpHtml("intro.navigation." + textId), { duration: 0 });
         });
-      }
-      info.toggle = function(which) {
-        var activeids = ids.filter(function(k2) {
-          return active[k2];
+        context.on("enter.intro", function() {
+          if (isTownHallSelected()) continueTo(selectedTownHall);
         });
-        if (which) {
-          active[which] = !active[which];
-          if (activeids.length === 1 && activeids[0] === which) {
-            wasActive = [which];
-          }
-          context.container().select("." + which + "-panel-toggle-item").classed("active", active[which]).select("input").property("checked", active[which]);
-        } else {
-          if (activeids.length) {
-            wasActive = activeids;
-            activeids.forEach(function(k2) {
-              active[k2] = false;
-            });
-          } else {
-            wasActive.forEach(function(k2) {
-              active[k2] = true;
-            });
-          }
+      }, 550);
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
         }
-        redraw();
+      });
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
+    }
+    function selectedTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      var entity = context.hasEntity(hallId);
+      if (!entity) return clickTownHall();
+      var box = pointBox(entity.loc, context);
+      var onClick = function() {
+        continueTo(editorTownHall);
       };
-      var infoPanels = selection2.selectAll(".info-panels").data([0]);
-      infoPanels = infoPanels.enter().append("div").attr("class", "info-panels").merge(infoPanels);
-      redraw();
-      context.keybinding().on(uiCmd("\u2318" + _t("info_panels.key")), function(d3_event) {
-        d3_event.stopImmediatePropagation();
-        d3_event.preventDefault();
-        info.toggle();
+      reveal(
+        box,
+        helpHtml("intro.navigation.selected_townhall"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("move.intro drawn.intro", function() {
+        var entity2 = context.hasEntity(hallId);
+        if (!entity2) return;
+        var box2 = pointBox(entity2.loc, context);
+        reveal(
+          box2,
+          helpHtml("intro.navigation.selected_townhall"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+        );
       });
-      ids.forEach(function(k2) {
-        var key = _t("info_panels." + k2 + ".key", { default: null });
-        if (!key)
-          return;
-        context.keybinding().on(uiCmd("\u2318\u21E7" + key), function(d3_event) {
-          d3_event.stopImmediatePropagation();
-          d3_event.preventDefault();
-          info.toggle(k2);
-        });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
+        }
       });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
     }
-    return info;
-  }
-
-  // modules/ui/intro/helper.js
-  function pointBox(loc, context) {
-    var rect = context.surfaceRect();
-    var point2 = context.curtainProjection(loc);
-    return {
-      left: point2[0] + rect.left - 40,
-      top: point2[1] + rect.top - 60,
-      width: 80,
-      height: 90
-    };
-  }
-  function pad(locOrBox, padding, context) {
-    var box;
-    if (locOrBox instanceof Array) {
-      var rect = context.surfaceRect();
-      var point2 = context.curtainProjection(locOrBox);
-      box = {
-        left: point2[0] + rect.left,
-        top: point2[1] + rect.top
+    function editorTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      var onClick = function() {
+        continueTo(presetTownHall);
       };
-    } else {
-      box = locOrBox;
+      reveal(
+        ".entity-editor-pane",
+        helpHtml("intro.navigation.editor_townhall"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.on("exit.intro", function() {
+        continueTo(clickTownHall);
+      });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
+        }
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        nextStep();
+      }
     }
-    return {
-      left: box.left - padding,
-      top: box.top - padding,
-      width: (box.width || 0) + 2 * padding,
-      height: (box.width || 0) + 2 * padding
-    };
-  }
-  function icon(name, svgklass, useklass) {
-    return '<svg class="icon ' + (svgklass || "") + '"><use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : "") + "></use></svg>";
-  }
-  var helpStringReplacements;
-  function helpHtml(id2, replacements) {
-    if (!helpStringReplacements) {
-      helpStringReplacements = {
-        // insert icons corresponding to various UI elements
-        point_icon: icon("#iD-icon-point", "inline"),
-        line_icon: icon("#iD-icon-line", "inline"),
-        area_icon: icon("#iD-icon-area", "inline"),
-        note_icon: icon("#iD-icon-note", "inline add-note"),
-        plus: icon("#iD-icon-plus", "inline"),
-        minus: icon("#iD-icon-minus", "inline"),
-        layers_icon: icon("#iD-icon-layers", "inline"),
-        data_icon: icon("#iD-icon-data", "inline"),
-        inspect: icon("#iD-icon-inspect", "inline"),
-        help_icon: icon("#iD-icon-help", "inline"),
-        undo_icon: icon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-redo" : "#iD-icon-undo", "inline"),
-        redo_icon: icon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-undo" : "#iD-icon-redo", "inline"),
-        save_icon: icon("#iD-icon-save", "inline"),
-        // operation icons
-        circularize_icon: icon("#iD-operation-circularize", "inline operation"),
-        continue_icon: icon("#iD-operation-continue", "inline operation"),
-        copy_icon: icon("#iD-operation-copy", "inline operation"),
-        delete_icon: icon("#iD-operation-delete", "inline operation"),
-        disconnect_icon: icon("#iD-operation-disconnect", "inline operation"),
-        downgrade_icon: icon("#iD-operation-downgrade", "inline operation"),
-        extract_icon: icon("#iD-operation-extract", "inline operation"),
-        merge_icon: icon("#iD-operation-merge", "inline operation"),
-        move_icon: icon("#iD-operation-move", "inline operation"),
-        orthogonalize_icon: icon("#iD-operation-orthogonalize", "inline operation"),
-        paste_icon: icon("#iD-operation-paste", "inline operation"),
-        reflect_long_icon: icon("#iD-operation-reflect-long", "inline operation"),
-        reflect_short_icon: icon("#iD-operation-reflect-short", "inline operation"),
-        reverse_icon: icon("#iD-operation-reverse", "inline operation"),
-        rotate_icon: icon("#iD-operation-rotate", "inline operation"),
-        split_icon: icon("#iD-operation-split", "inline operation"),
-        straighten_icon: icon("#iD-operation-straighten", "inline operation"),
-        // interaction icons
-        leftclick: icon("#iD-walkthrough-mouse-left", "inline operation"),
-        rightclick: icon("#iD-walkthrough-mouse-right", "inline operation"),
-        mousewheel_icon: icon("#iD-walkthrough-mousewheel", "inline operation"),
-        tap_icon: icon("#iD-walkthrough-tap", "inline operation"),
-        doubletap_icon: icon("#iD-walkthrough-doubletap", "inline operation"),
-        longpress_icon: icon("#iD-walkthrough-longpress", "inline operation"),
-        touchdrag_icon: icon("#iD-walkthrough-touchdrag", "inline operation"),
-        pinch_icon: icon("#iD-walkthrough-pinch-apart", "inline operation"),
-        // insert keys; may be localized and platform-dependent
-        shift: uiCmd.display("\u21E7"),
-        alt: uiCmd.display("\u2325"),
-        return: uiCmd.display("\u21B5"),
-        esc: _t.html("shortcuts.key.esc"),
-        space: _t.html("shortcuts.key.space"),
-        add_note_key: _t.html("modes.add_note.key"),
-        help_key: _t.html("help.key"),
-        shortcuts_key: _t.html("shortcuts.toggle.key"),
-        // reference localized UI labels directly so that they'll always match
-        save: _t.html("save.title"),
-        undo: _t.html("undo.title"),
-        redo: _t.html("redo.title"),
-        upload: _t.html("commit.save"),
-        point: _t.html("modes.add_point.title"),
-        line: _t.html("modes.add_line.title"),
-        area: _t.html("modes.add_area.title"),
-        note: _t.html("modes.add_note.label"),
-        circularize: _t.html("operations.circularize.title"),
-        continue: _t.html("operations.continue.title"),
-        copy: _t.html("operations.copy.title"),
-        delete: _t.html("operations.delete.title"),
-        disconnect: _t.html("operations.disconnect.title"),
-        downgrade: _t.html("operations.downgrade.title"),
-        extract: _t.html("operations.extract.title"),
-        merge: _t.html("operations.merge.title"),
-        move: _t.html("operations.move.title"),
-        orthogonalize: _t.html("operations.orthogonalize.title"),
-        paste: _t.html("operations.paste.title"),
-        reflect_long: _t.html("operations.reflect.title.long"),
-        reflect_short: _t.html("operations.reflect.title.short"),
-        reverse: _t.html("operations.reverse.title"),
-        rotate: _t.html("operations.rotate.title"),
-        split: _t.html("operations.split.title"),
-        straighten: _t.html("operations.straighten.title"),
-        map_data: _t.html("map_data.title"),
-        osm_notes: _t.html("map_data.layers.notes.title"),
-        fields: _t.html("inspector.fields"),
-        tags: _t.html("inspector.tags"),
-        relations: _t.html("inspector.relations"),
-        new_relation: _t.html("inspector.new_relation"),
-        turn_restrictions: _t.html("_tagging.presets.fields.restrictions.label"),
-        background_settings: _t.html("background.description"),
-        imagery_offset: _t.html("background.fix_misalignment"),
-        start_the_walkthrough: _t.html("splash.walkthrough"),
-        help: _t.html("help.title"),
-        ok: _t.html("intro.ok")
+    function presetTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      var entity = context.entity(context.selectedIDs()[0]);
+      var preset = _mainPresetIndex.match(entity, context.graph());
+      var onClick = function() {
+        continueTo(fieldsTownHall);
       };
-      for (var key in helpStringReplacements) {
-        helpStringReplacements[key] = { html: helpStringReplacements[key] };
+      reveal(
+        ".entity-editor-pane .section-feature-type",
+        helpHtml("intro.navigation.preset_townhall", { preset: preset.name() }),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.on("exit.intro", function() {
+        continueTo(clickTownHall);
+      });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
+        }
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        nextStep();
       }
     }
-    var reps;
-    if (replacements) {
-      reps = Object.assign(replacements, helpStringReplacements);
-    } else {
-      reps = helpStringReplacements;
-    }
-    return _t.html(id2, reps).replace(/\`(.*?)\`/g, "<kbd>$1</kbd>");
-  }
-  function slugify(text) {
-    return text.toString().toLowerCase().replace(/\s+/g, "-").replace(/[^\w\-]+/g, "").replace(/\-\-+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
-  }
-  var missingStrings = {};
-  function checkKey(key, text) {
-    if (_t(key, { default: void 0 }) === void 0) {
-      if (missingStrings.hasOwnProperty(key))
-        return;
-      missingStrings[key] = text;
-      var missing = key + ": " + text;
-      if (typeof console !== "undefined")
-        console.log(missing);
-    }
-  }
-  function localize(obj) {
-    var key;
-    var name = obj.tags && obj.tags.name;
-    if (name) {
-      key = "intro.graph.name." + slugify(name);
-      obj.tags.name = _t(key, { default: name });
-      checkKey(key, name);
-    }
-    var street = obj.tags && obj.tags["addr:street"];
-    if (street) {
-      key = "intro.graph.name." + slugify(street);
-      obj.tags["addr:street"] = _t(key, { default: street });
-      checkKey(key, street);
-      var addrTags = [
-        "block_number",
-        "city",
-        "county",
-        "district",
-        "hamlet",
-        "neighbourhood",
-        "postcode",
-        "province",
-        "quarter",
-        "state",
-        "subdistrict",
-        "suburb"
-      ];
-      addrTags.forEach(function(k2) {
-        var key2 = "intro.graph." + k2;
-        var tag2 = "addr:" + k2;
-        var val = obj.tags && obj.tags[tag2];
-        var str = _t(key2, { default: val });
-        if (str) {
-          if (str.match(/^<.*>$/) !== null) {
-            delete obj.tags[tag2];
-          } else {
-            obj.tags[tag2] = str;
-          }
+    function fieldsTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      var onClick = function() {
+        continueTo(closeTownHall);
+      };
+      reveal(
+        ".entity-editor-pane .section-preset-fields",
+        helpHtml("intro.navigation.fields_townhall"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.on("exit.intro", function() {
+        continueTo(clickTownHall);
+      });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
         }
       });
-    }
-    return obj;
-  }
-  function isMostlySquare(points) {
-    var threshold = 15;
-    var lowerBound = Math.cos((90 - threshold) * Math.PI / 180);
-    var upperBound = Math.cos(threshold * Math.PI / 180);
-    for (var i3 = 0; i3 < points.length; i3++) {
-      var a2 = points[(i3 - 1 + points.length) % points.length];
-      var origin = points[i3];
-      var b2 = points[(i3 + 1) % points.length];
-      var dotp = geoVecNormalizedDot(a2, b2, origin);
-      var mag = Math.abs(dotp);
-      if (mag > lowerBound && mag < upperBound) {
-        return false;
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        nextStep();
       }
     }
-    return true;
-  }
-  function selectMenuItem(context, operation2) {
-    return context.container().select(".edit-menu .edit-menu-item-" + operation2);
-  }
-  function transitionTime(point1, point2) {
-    var distance = geoSphericalDistance(point1, point2);
-    if (distance === 0) {
-      return 0;
-    } else if (distance < 80) {
-      return 500;
-    } else {
-      return 1e3;
-    }
-  }
-
-  // modules/ui/toggle.js
-  function uiToggle(show, callback) {
-    return function(selection2) {
-      selection2.style("opacity", show ? 0 : 1).classed("hide", false).transition().style("opacity", show ? 1 : 0).on("end", function() {
-        select_default2(this).classed("hide", !show).style("opacity", null);
-        if (callback)
-          callback.apply(this);
+    function closeTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      var selector = ".entity-editor-pane button.close svg use";
+      var href = select_default2(selector).attr("href") || "#iD-icon-close";
+      reveal(
+        ".entity-editor-pane",
+        helpHtml("intro.navigation.close_townhall", { button: { html: icon(href, "inline") } })
+      );
+      context.on("exit.intro", function() {
+        continueTo(searchStreet);
       });
-    };
-  }
-
-  // modules/ui/curtain.js
-  function uiCurtain(containerNode) {
-    var surface = select_default2(null), tooltip = select_default2(null), darkness = select_default2(null);
-    function curtain(selection2) {
-      surface = selection2.append("svg").attr("class", "curtain").style("top", 0).style("left", 0);
-      darkness = surface.append("path").attr("x", 0).attr("y", 0).attr("class", "curtain-darkness");
-      select_default2(window).on("resize.curtain", resize);
-      tooltip = selection2.append("div").attr("class", "tooltip");
-      tooltip.append("div").attr("class", "popover-arrow");
-      tooltip.append("div").attr("class", "popover-inner");
-      resize();
-      function resize() {
-        surface.attr("width", containerNode.clientWidth).attr("height", containerNode.clientHeight);
-        curtain.cut(darkness.datum());
+      context.history().on("change.intro", function() {
+        var selector2 = ".entity-editor-pane button.close svg use";
+        var href2 = select_default2(selector2).attr("href") || "#iD-icon-close";
+        reveal(
+          ".entity-editor-pane",
+          helpHtml("intro.navigation.close_townhall", { button: { html: icon(href2, "inline") } }),
+          { duration: 0 }
+        );
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
     }
-    curtain.reveal = function(box, html3, options2) {
-      options2 = options2 || {};
-      if (typeof box === "string") {
-        box = select_default2(box).node();
-      }
-      if (box && box.getBoundingClientRect) {
-        box = copyBox(box.getBoundingClientRect());
-        var containerRect = containerNode.getBoundingClientRect();
-        box.top -= containerRect.top;
-        box.left -= containerRect.left;
-      }
-      if (box && options2.padding) {
-        box.top -= options2.padding;
-        box.left -= options2.padding;
-        box.bottom += options2.padding;
-        box.right += options2.padding;
-        box.height += options2.padding * 2;
-        box.width += options2.padding * 2;
-      }
-      var tooltipBox;
-      if (options2.tooltipBox) {
-        tooltipBox = options2.tooltipBox;
-        if (typeof tooltipBox === "string") {
-          tooltipBox = select_default2(tooltipBox).node();
-        }
-        if (tooltipBox && tooltipBox.getBoundingClientRect) {
-          tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
-        }
-      } else {
-        tooltipBox = box;
-      }
-      if (tooltipBox && html3) {
-        if (html3.indexOf("**") !== -1) {
-          if (html3.indexOf("<span") === 0) {
-            html3 = html3.replace(/^(<span.*?>)(.+?)(\*\*)/, "$1<span>$2</span>$3");
-          } else {
-            html3 = html3.replace(/^(.+?)(\*\*)/, "<span>$1</span>$2");
-          }
-          html3 = html3.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
-        }
-        html3 = html3.replace(/\*(.*?)\*/g, "<em>$1</em>");
-        html3 = html3.replace(/\{br\}/g, "<br/><br/>");
-        if (options2.buttonText && options2.buttonCallback) {
-          html3 += '<div class="button-section"><button href="#" class="button action">' + options2.buttonText + "</button></div>";
-        }
-        var classes = "curtain-tooltip popover tooltip arrowed in " + (options2.tooltipClass || "");
-        tooltip.classed(classes, true).selectAll(".popover-inner").html(html3);
-        if (options2.buttonText && options2.buttonCallback) {
-          var button = tooltip.selectAll(".button-section .button.action");
-          button.on("click", function(d3_event) {
-            d3_event.preventDefault();
-            options2.buttonCallback();
-          });
-        }
-        var tip = copyBox(tooltip.node().getBoundingClientRect()), w2 = containerNode.clientWidth, h2 = containerNode.clientHeight, tooltipWidth = 200, tooltipArrow = 5, side, pos;
-        if (options2.tooltipClass === "intro-mouse") {
-          tip.height += 80;
-        }
-        if (tooltipBox.top + tooltipBox.height > h2) {
-          tooltipBox.height -= tooltipBox.top + tooltipBox.height - h2;
-        }
-        if (tooltipBox.left + tooltipBox.width > w2) {
-          tooltipBox.width -= tooltipBox.left + tooltipBox.width - w2;
-        }
-        if (tooltipBox.top + tooltipBox.height < 100) {
-          side = "bottom";
-          pos = [
-            tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
-            tooltipBox.top + tooltipBox.height
-          ];
-        } else if (tooltipBox.top > h2 - 140) {
-          side = "top";
-          pos = [
-            tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
-            tooltipBox.top - tip.height
-          ];
-        } else {
-          var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
-          if (_mainLocalizer.textDirection() === "rtl") {
-            if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
-              side = "right";
-              pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
-            } else {
-              side = "left";
-              pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
-            }
-          } else {
-            if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w2 - 70) {
-              side = "left";
-              pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
-            } else {
-              side = "right";
-              pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
-            }
-          }
-        }
-        if (options2.duration !== 0 || !tooltip.classed(side)) {
-          tooltip.call(uiToggle(true));
-        }
-        tooltip.style("top", pos[1] + "px").style("left", pos[0] + "px").attr("class", classes + " " + side);
-        var shiftY = 0;
-        if (side === "left" || side === "right") {
-          if (pos[1] < 60) {
-            shiftY = 60 - pos[1];
-          } else if (pos[1] + tip.height > h2 - 100) {
-            shiftY = h2 - pos[1] - tip.height - 100;
-          }
-        }
-        tooltip.selectAll(".popover-inner").style("top", shiftY + "px");
-      } else {
-        tooltip.classed("in", false).call(uiToggle(false));
-      }
-      curtain.cut(box, options2.duration);
-      return tooltip;
-    };
-    curtain.cut = function(datum2, duration) {
-      darkness.datum(datum2).interrupt();
-      var selection2;
-      if (duration === 0) {
-        selection2 = darkness;
-      } else {
-        selection2 = darkness.transition().duration(duration || 600).ease(linear2);
-      }
-      selection2.attr("d", function(d2) {
-        var containerWidth = containerNode.clientWidth;
-        var containerHeight = containerNode.clientHeight;
-        var string = "M 0,0 L 0," + containerHeight + " L " + containerWidth + "," + containerHeight + "L" + containerWidth + ",0 Z";
-        if (!d2)
-          return string;
-        return string + "M" + d2.left + "," + d2.top + "L" + d2.left + "," + (d2.top + d2.height) + "L" + (d2.left + d2.width) + "," + (d2.top + d2.height) + "L" + (d2.left + d2.width) + "," + d2.top + "Z";
-      });
-    };
-    curtain.remove = function() {
-      surface.remove();
-      tooltip.remove();
-      select_default2(window).on("resize.curtain", null);
-    };
-    function copyBox(src) {
-      return {
-        top: src.top,
-        right: src.right,
-        bottom: src.bottom,
-        left: src.left,
-        width: src.width,
-        height: src.height
-      };
-    }
-    return curtain;
-  }
-
-  // modules/ui/intro/welcome.js
-  function uiIntroWelcome(context, reveal) {
-    var dispatch14 = dispatch_default("done");
-    var chapter = {
-      title: "intro.welcome.title"
-    };
-    function welcome() {
-      context.map().centerZoom([-85.63591, 41.94285], 19);
-      reveal(
-        ".intro-nav-wrap .chapter-welcome",
-        helpHtml("intro.welcome.welcome"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: practice }
-      );
-    }
-    function practice() {
-      reveal(
-        ".intro-nav-wrap .chapter-welcome",
-        helpHtml("intro.welcome.practice"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: words }
-      );
-    }
-    function words() {
-      reveal(
-        ".intro-nav-wrap .chapter-welcome",
-        helpHtml("intro.welcome.words"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: chapters }
-      );
-    }
-    function chapters() {
-      dispatch14.call("done");
-      reveal(
-        ".intro-nav-wrap .chapter-navigation",
-        helpHtml("intro.welcome.chapters", { next: _t("intro.navigation.title") })
-      );
-    }
-    chapter.enter = function() {
-      welcome();
-    };
-    chapter.exit = function() {
-      context.container().select(".curtain-tooltip.intro-mouse").selectAll(".counter").remove();
-    };
-    chapter.restart = function() {
-      chapter.exit();
-      chapter.enter();
-    };
-    return utilRebind(chapter, dispatch14, "on");
-  }
-
-  // modules/ui/intro/navigation.js
-  function uiIntroNavigation(context, reveal) {
-    var dispatch14 = dispatch_default("done");
-    var timeouts = [];
-    var hallId = "n2061";
-    var townHall = [-85.63591, 41.94285];
-    var springStreetId = "w397";
-    var springStreetEndId = "n1834";
-    var springStreet = [-85.63582, 41.94255];
-    var onewayField = _mainPresetIndex.field("oneway");
-    var maxspeedField = _mainPresetIndex.field("maxspeed");
-    var chapter = {
-      title: "intro.navigation.title"
-    };
-    function timeout2(f2, t2) {
-      timeouts.push(window.setTimeout(f2, t2));
-    }
-    function eventCancel(d3_event) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
-    }
-    function isTownHallSelected() {
-      var ids = context.selectedIDs();
-      return ids.length === 1 && ids[0] === hallId;
-    }
-    function dragMap() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      var msec = transitionTime(townHall, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
-      }
-      context.map().centerZoomEase(townHall, 19, msec);
-      timeout2(function() {
-        var centerStart = context.map().center();
-        var textId = context.lastPointerType() === "mouse" ? "drag" : "drag_touch";
-        var dragString = helpHtml("intro.navigation.map_info") + "{br}" + helpHtml("intro.navigation." + textId);
-        reveal(".surface", dragString);
-        context.map().on("drawn.intro", function() {
-          reveal(".surface", dragString, { duration: 0 });
-        });
-        context.map().on("move.intro", function() {
-          var centerNow = context.map().center();
-          if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
-            context.map().on("move.intro", null);
-            timeout2(function() {
-              continueTo(zoomMap);
-            }, 3e3);
-          }
-        });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
-      }
-    }
-    function zoomMap() {
-      var zoomStart = context.map().zoom();
-      var textId = context.lastPointerType() === "mouse" ? "zoom" : "zoom_touch";
-      var zoomString = helpHtml("intro.navigation." + textId);
-      reveal(".surface", zoomString);
-      context.map().on("drawn.intro", function() {
-        reveal(".surface", zoomString, { duration: 0 });
-      });
-      context.map().on("move.intro", function() {
-        if (context.map().zoom() !== zoomStart) {
-          context.map().on("move.intro", null);
-          timeout2(function() {
-            continueTo(features);
-          }, 3e3);
-        }
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
-      }
-    }
-    function features() {
-      var onClick = function() {
-        continueTo(pointsLinesAreas);
-      };
-      reveal(
-        ".surface",
-        helpHtml("intro.navigation.features"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("drawn.intro", function() {
-        reveal(
-          ".surface",
-          helpHtml("intro.navigation.features"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      function continueTo(nextStep) {
-        context.map().on("drawn.intro", null);
-        nextStep();
-      }
-    }
-    function pointsLinesAreas() {
-      var onClick = function() {
-        continueTo(nodesWays);
-      };
-      reveal(
-        ".surface",
-        helpHtml("intro.navigation.points_lines_areas"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("drawn.intro", function() {
-        reveal(
-          ".surface",
-          helpHtml("intro.navigation.points_lines_areas"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      function continueTo(nextStep) {
-        context.map().on("drawn.intro", null);
-        nextStep();
-      }
-    }
-    function nodesWays() {
-      var onClick = function() {
-        continueTo(clickTownHall);
-      };
-      reveal(
-        ".surface",
-        helpHtml("intro.navigation.nodes_ways"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("drawn.intro", function() {
-        reveal(
-          ".surface",
-          helpHtml("intro.navigation.nodes_ways"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      function continueTo(nextStep) {
-        context.map().on("drawn.intro", null);
-        nextStep();
-      }
-    }
-    function clickTownHall() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      var entity = context.hasEntity(hallId);
-      if (!entity)
-        return;
-      reveal(null, null, { duration: 0 });
-      context.map().centerZoomEase(entity.loc, 19, 500);
-      timeout2(function() {
-        var entity2 = context.hasEntity(hallId);
-        if (!entity2)
-          return;
-        var box = pointBox(entity2.loc, context);
-        var textId = context.lastPointerType() === "mouse" ? "click_townhall" : "tap_townhall";
-        reveal(box, helpHtml("intro.navigation." + textId));
-        context.map().on("move.intro drawn.intro", function() {
-          var entity3 = context.hasEntity(hallId);
-          if (!entity3)
-            return;
-          var box2 = pointBox(entity3.loc, context);
-          reveal(box2, helpHtml("intro.navigation." + textId), { duration: 0 });
-        });
-        context.on("enter.intro", function() {
-          if (isTownHallSelected())
-            continueTo(selectedTownHall);
-        });
-      }, 550);
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
-    }
-    function selectedTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      var entity = context.hasEntity(hallId);
-      if (!entity)
-        return clickTownHall();
-      var box = pointBox(entity.loc, context);
-      var onClick = function() {
-        continueTo(editorTownHall);
-      };
-      reveal(
-        box,
-        helpHtml("intro.navigation.selected_townhall"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("move.intro drawn.intro", function() {
-        var entity2 = context.hasEntity(hallId);
-        if (!entity2)
-          return;
-        var box2 = pointBox(entity2.loc, context);
-        reveal(
-          box2,
-          helpHtml("intro.navigation.selected_townhall"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
-    }
-    function editorTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      var onClick = function() {
-        continueTo(presetTownHall);
-      };
-      reveal(
-        ".entity-editor-pane",
-        helpHtml("intro.navigation.editor_townhall"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.on("exit.intro", function() {
-        continueTo(clickTownHall);
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        nextStep();
-      }
-    }
-    function presetTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      var entity = context.entity(context.selectedIDs()[0]);
-      var preset = _mainPresetIndex.match(entity, context.graph());
-      var onClick = function() {
-        continueTo(fieldsTownHall);
-      };
-      reveal(
-        ".entity-editor-pane .section-feature-type",
-        helpHtml("intro.navigation.preset_townhall", { preset: preset.name() }),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.on("exit.intro", function() {
-        continueTo(clickTownHall);
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        nextStep();
-      }
-    }
-    function fieldsTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      var onClick = function() {
-        continueTo(closeTownHall);
-      };
-      reveal(
-        ".entity-editor-pane .section-preset-fields",
-        helpHtml("intro.navigation.fields_townhall"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.on("exit.intro", function() {
-        continueTo(clickTownHall);
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        nextStep();
-      }
-    }
-    function closeTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      var selector = ".entity-editor-pane button.close svg use";
-      var href = select_default2(selector).attr("href") || "#iD-icon-close";
-      reveal(
-        ".entity-editor-pane",
-        helpHtml("intro.navigation.close_townhall", { button: { html: icon(href, "inline") } })
-      );
-      context.on("exit.intro", function() {
-        continueTo(searchStreet);
-      });
-      context.history().on("change.intro", function() {
-        var selector2 = ".entity-editor-pane button.close svg use";
-        var href2 = select_default2(selector2).attr("href") || "#iD-icon-close";
-        reveal(
-          ".entity-editor-pane",
-          helpHtml("intro.navigation.close_townhall", { button: { html: icon(href2, "inline") } }),
-          { duration: 0 }
-        );
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
-    }
-    function searchStreet() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      var msec = transitionTime(springStreet, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
+    function searchStreet() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      var msec = transitionTime(springStreet, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
       }
       context.map().centerZoomEase(springStreet, 19, msec);
       timeout2(function() {
       timeout2(function() {
         context.map().on("move.intro drawn.intro", function() {
           var entity2 = context.hasEntity(springStreetEndId);
-          if (!entity2)
-            return;
+          if (!entity2) return;
           var box2 = pointBox(entity2.loc, context);
           box2.height = 500;
           reveal(
         _pointID = null;
         tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-points");
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-point")
-            return;
+          if (mode.id !== "add-point") return;
           continueTo(placePoint);
         });
       }, msec + 100);
         reveal(pointBox2, helpHtml("intro.points." + textId), { duration: 0 });
       });
       context.on("enter.intro", function(mode) {
-        if (mode.id !== "select")
-          return chapter.restart();
+        if (mode.id !== "select") return chapter.restart();
         _pointID = context.mode().selectedIDs()[0];
         if (context.graph().geometry(_pointID) === "vertex") {
           context.map().on("move.intro drawn.intro", null);
       }
     }
     function reselectPoint() {
-      if (!_pointID)
-        return chapter.restart();
+      if (!_pointID) return chapter.restart();
       var entity = context.hasEntity(_pointID);
-      if (!entity)
-        return chapter.restart();
+      if (!entity) return chapter.restart();
       var oldPreset = _mainPresetIndex.match(entity, context.graph());
       context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
       context.enter(modeBrowse(context));
         timeout2(function() {
           context.map().on("move.intro drawn.intro", function() {
             var entity2 = context.hasEntity(_pointID);
-            if (!entity2)
-              return chapter.restart();
+            if (!entity2) return chapter.restart();
             var box2 = pointBox(entity2.loc, context);
             reveal(box2, helpHtml("intro.points.reselect"), { duration: 0 });
           });
         }, 600);
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "select")
-            return;
+          if (mode.id !== "select") return;
           continueTo(updatePoint);
         });
       }, msec + 100);
       }
     }
     function rightClickPoint() {
-      if (!_pointID)
-        return chapter.restart();
+      if (!_pointID) return chapter.restart();
       var entity = context.hasEntity(_pointID);
-      if (!entity)
-        return chapter.restart();
+      if (!entity) return chapter.restart();
       context.enter(modeBrowse(context));
       var box = pointBox(entity.loc, context);
       var textId = context.lastPointerType() === "mouse" ? "rightclick" : "edit_menu_touch";
       timeout2(function() {
         context.map().on("move.intro", function() {
           var entity2 = context.hasEntity(_pointID);
-          if (!entity2)
-            return chapter.restart();
+          if (!entity2) return chapter.restart();
           var box2 = pointBox(entity2.loc, context);
           reveal(box2, helpHtml("intro.points." + textId), { duration: 0 });
         });
       }, 600);
       context.on("enter.intro", function(mode) {
-        if (mode.id !== "select")
-          return;
+        if (mode.id !== "select") return;
         var ids = context.selectedIDs();
-        if (ids.length !== 1 || ids[0] !== _pointID)
-          return;
+        if (ids.length !== 1 || ids[0] !== _pointID) return;
         timeout2(function() {
           var node = selectMenuItem(context, "delete").node();
-          if (!node)
-            return;
+          if (!node) return;
           continueTo(enterDelete);
         }, 50);
       });
       }
     }
     function enterDelete() {
-      if (!_pointID)
-        return chapter.restart();
+      if (!_pointID) return chapter.restart();
       var entity = context.hasEntity(_pointID);
-      if (!entity)
-        return chapter.restart();
+      if (!entity) return chapter.restart();
       var node = selectMenuItem(context, "delete").node();
       if (!node) {
         return continueTo(rightClickPoint);
         });
       }, 300);
       context.on("exit.intro", function() {
-        if (!_pointID)
-          return chapter.restart();
+        if (!_pointID) return chapter.restart();
         var entity2 = context.hasEntity(_pointID);
-        if (entity2)
-          return continueTo(rightClickPoint);
+        if (entity2) return continueTo(rightClickPoint);
       });
       context.history().on("change.intro", function(changed) {
         if (changed.deleted().length) {
         );
         tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-areas");
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-area")
-            return;
+          if (mode.id !== "add-area") return;
           continueTo(startPlayground);
         });
       }, msec + 100);
             );
           });
           context.on("enter.intro", function(mode) {
-            if (mode.id !== "draw-area")
-              return chapter.restart();
+            if (mode.id !== "draw-area") return chapter.restart();
             continueTo(continuePlayground);
           });
         }, 250);
         return continueTo(searchPresets);
       });
       function continueTo(nextStep) {
-        if (watcher)
-          window.clearInterval(watcher);
+        if (watcher) window.clearInterval(watcher);
         context.on("exit.intro", null);
         nextStep();
       }
         );
         tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-lines");
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-line")
-            return;
+          if (mode.id !== "add-line") return;
           continueTo(startLine);
         });
       }, msec + 100);
       }
     }
     function startLine() {
-      if (context.mode().id !== "add-line")
-        return chapter.restart();
+      if (context.mode().id !== "add-line") return chapter.restart();
       _tulipRoadID = null;
       var padding = 70 * Math.pow(2, context.map().zoom() - 18);
       var box = pad(tulipRoadStart, padding, context);
         reveal(box, startLineString, { duration: 0 });
       });
       context.on("enter.intro", function(mode) {
-        if (mode.id !== "draw-line")
-          return chapter.restart();
+        if (mode.id !== "draw-line") return chapter.restart();
         continueTo(drawLine);
       });
       function continueTo(nextStep) {
       }
     }
     function drawLine() {
-      if (context.mode().id !== "draw-line")
-        return chapter.restart();
+      if (context.mode().id !== "draw-line") return chapter.restart();
       _tulipRoadID = context.mode().selectedIDs()[0];
       context.map().centerEase(tulipRoadMidpoint, 500);
       timeout2(function() {
     }
     function isLineConnected() {
       var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
-      if (!entity)
-        return false;
+      if (!entity) return false;
       var drawNodes = context.graph().childNodes(entity);
       return drawNodes.some(function(node) {
         return context.graph().parentWays(node).some(function(parent) {
       timeout2(chapter.restart, 3e3);
     }
     function continueLine() {
-      if (context.mode().id !== "draw-line")
-        return chapter.restart();
+      if (context.mode().id !== "draw-line") return chapter.restart();
       var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
-      if (!entity)
-        return chapter.restart();
+      if (!entity) return chapter.restart();
       context.map().centerEase(tulipRoadIntersection, 500);
       var continueLineText = helpHtml("intro.lines.continue_line") + "{br}" + helpHtml("intro.lines.finish_line_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.lines.finish_road");
       reveal(".surface", continueLineText);
       }
     }
     function chooseCategoryRoad() {
-      if (context.mode().id !== "select")
-        return chapter.restart();
+      if (context.mode().id !== "select") return chapter.restart();
       context.on("exit.intro", function() {
         return chapter.restart();
       });
       var button = context.container().select(".preset-category-road_minor .preset-list-button");
-      if (button.empty())
-        return chapter.restart();
+      if (button.empty()) return chapter.restart();
       context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
       timeout2(function() {
         context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
       }
     }
     function choosePresetResidential() {
-      if (context.mode().id !== "select")
-        return chapter.restart();
+      if (context.mode().id !== "select") return chapter.restart();
       context.on("exit.intro", function() {
         return chapter.restart();
       });
       var subgrid = context.container().select(".preset-category-road_minor .subgrid");
-      if (subgrid.empty())
-        return chapter.restart();
+      if (subgrid.empty()) return chapter.restart();
       subgrid.selectAll(":not(.preset-highway-residential) .preset-list-button").on("click.intro", function() {
         continueTo(retryPresetResidential);
       });
       }
     }
     function retryPresetResidential() {
-      if (context.mode().id !== "select")
-        return chapter.restart();
+      if (context.mode().id !== "select") return chapter.restart();
       context.on("exit.intro", function() {
         return chapter.restart();
       });
           );
         });
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "select")
-            return;
+          if (mode.id !== "select") return;
           var ids = context.selectedIDs();
-          if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID)
-            return;
+          if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
           timeout2(function() {
             var node = selectMenuItem(context, "split").node();
-            if (!node)
-              return;
+            if (!node) return;
             continueTo(splitIntersection);
           }, 50);
         });
       context.on("enter.intro", function() {
         var ids2 = context.selectedIDs();
         if (ids2.length === 1 && ids2[0] === _washingtonSegmentID) {
-          continueTo(multiSelect);
+          continueTo(multiSelect2);
         }
       });
       context.history().on("change.intro", function() {
         nextStep();
       }
     }
-    function multiSelect() {
+    function multiSelect2() {
       if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
         return continueTo(rightClickIntersection);
       }
           );
         });
         context.on("enter.intro", function() {
-          continueTo(multiSelect);
+          continueTo(multiSelect2);
         });
         context.history().on("change.intro", function() {
           if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
         reveal(box2, rightClickString, { duration: 0 });
       });
       context.ui().editMenu().on("toggled.intro", function(open) {
-        if (!open)
-          return;
+        if (!open) return;
         timeout2(function() {
           var ids = context.selectedIDs();
           if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
             var node = selectMenuItem(context, "delete").node();
-            if (!node)
-              return;
+            if (!node) return;
             continueTo(multiDelete);
           } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
-            return continueTo(multiSelect);
+            return continueTo(multiSelect2);
           } else {
             return continueTo(didSplit);
           }
         return continueTo(rightClickIntersection);
       }
       var node = selectMenuItem(context, "delete").node();
-      if (!node)
-        return continueTo(multiRightClick);
+      if (!node) return continueTo(multiRightClick);
       reveal(
         ".edit-menu",
         helpHtml("intro.lines.multi_delete"),
       });
       context.on("exit.intro", function() {
         if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
-          return continueTo(multiSelect);
+          return continueTo(multiSelect2);
         }
       });
       context.history().on("change.intro", function() {
       reveal(box, helpHtml("intro.lines.retry_delete"), {
         buttonText: _t.html("intro.ok"),
         buttonCallback: function() {
-          continueTo(multiSelect);
+          continueTo(multiSelect2);
         }
       });
       function continueTo(nextStep) {
         );
         tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-buildings");
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-area")
-            return;
+          if (mode.id !== "add-area") return;
           continueTo(startHouse);
         });
       }, msec + 100);
           revealHouse(house, startString, { duration: 0 });
         });
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "draw-area")
-            return chapter.restart();
+          if (mode.id !== "draw-area") return chapter.restart();
           continueTo(continueHouse);
         });
       }, 550);
       }
     }
     function rightClickHouse() {
-      if (!_houseID)
-        return chapter.restart();
+      if (!_houseID) return chapter.restart();
       context.enter(modeBrowse(context));
       context.history().reset("hasHouse");
       var zoom = context.map().zoom();
       }
       context.map().centerZoomEase(house, zoom, 500);
       context.on("enter.intro", function(mode) {
-        if (mode.id !== "select")
-          return;
+        if (mode.id !== "select") return;
         var ids = context.selectedIDs();
-        if (ids.length !== 1 || ids[0] !== _houseID)
-          return;
+        if (ids.length !== 1 || ids[0] !== _houseID) return;
         timeout2(function() {
           var node = selectMenuItem(context, "orthogonalize").node();
-          if (!node)
-            return;
+          if (!node) return;
           continueTo(clickSquare);
         }, 50);
       });
       }
     }
     function clickSquare() {
-      if (!_houseID)
-        return chapter.restart();
+      if (!_houseID) return chapter.restart();
       var entity = context.hasEntity(_houseID);
-      if (!entity)
-        return continueTo(rightClickHouse);
+      if (!entity) return continueTo(rightClickHouse);
       var node = selectMenuItem(context, "orthogonalize").node();
       if (!node) {
         return continueTo(rightClickHouse);
           helpHtml("intro.buildings.add_tank")
         );
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-area")
-            return;
+          if (mode.id !== "add-area") return;
           continueTo(startTank);
         });
       }, msec + 100);
           revealTank(tank, startString, { duration: 0 });
         });
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "draw-area")
-            return chapter.restart();
+          if (mode.id !== "draw-area") return chapter.restart();
           continueTo(continueTank);
         });
       }, 550);
       }
     }
     function rightClickTank() {
-      if (!_tankID)
-        return continueTo(addTank);
+      if (!_tankID) return continueTo(addTank);
       context.enter(modeBrowse(context));
       context.history().reset("hasTank");
       context.map().centerEase(tank, 500);
       timeout2(function() {
         context.on("enter.intro", function(mode) {
-          if (mode.id !== "select")
-            return;
+          if (mode.id !== "select") return;
           var ids = context.selectedIDs();
-          if (ids.length !== 1 || ids[0] !== _tankID)
-            return;
+          if (ids.length !== 1 || ids[0] !== _tankID) return;
           timeout2(function() {
             var node = selectMenuItem(context, "circularize").node();
-            if (!node)
-              return;
+            if (!node) return;
             continueTo(clickCircle);
           }, 50);
         });
       }
     }
     function clickCircle() {
-      if (!_tankID)
-        return chapter.restart();
+      if (!_tankID) return chapter.restart();
       var entity = context.hasEntity(_tankID);
-      if (!entity)
-        return continueTo(rightClickTank);
+      if (!entity) return continueTo(rightClickTank);
       var node = selectMenuItem(context, "circularize").node();
       if (!node) {
         return continueTo(rightClickTank);
     };
   }
 
-  // modules/ui/map_in_map.js
-  function uiMapInMap(context) {
-    function mapInMap(selection2) {
-      var backgroundLayer = rendererTileLayer(context);
-      var overlayLayers = {};
-      var projection2 = geoRawMercator();
-      var dataLayer = svgData(projection2, context).showLabels(false);
-      var debugLayer = svgDebug(projection2, context);
-      var zoom = zoom_default2().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on("start", zoomStarted).on("zoom", zoomed).on("end", zoomEnded);
-      var wrap2 = select_default2(null);
-      var tiles = select_default2(null);
-      var viewport = select_default2(null);
-      var _isTransformed = false;
-      var _isHidden = true;
-      var _skipEvents = false;
-      var _gesture = null;
-      var _zDiff = 6;
-      var _dMini;
-      var _cMini;
-      var _tStart;
-      var _tCurr;
-      var _timeoutID;
-      function zoomStarted() {
-        if (_skipEvents)
-          return;
-        _tStart = _tCurr = projection2.transform();
-        _gesture = null;
-      }
-      function zoomed(d3_event) {
-        if (_skipEvents)
-          return;
-        var x2 = d3_event.transform.x;
-        var y2 = d3_event.transform.y;
-        var k2 = d3_event.transform.k;
-        var isZooming = k2 !== _tStart.k;
-        var isPanning = x2 !== _tStart.x || y2 !== _tStart.y;
-        if (!isZooming && !isPanning) {
-          return;
-        }
-        if (!_gesture) {
-          _gesture = isZooming ? "zoom" : "pan";
-        }
-        var tMini = projection2.transform();
-        var tX, tY, scale;
-        if (_gesture === "zoom") {
-          scale = k2 / tMini.k;
-          tX = (_cMini[0] / scale - _cMini[0]) * scale;
-          tY = (_cMini[1] / scale - _cMini[1]) * scale;
-        } else {
-          k2 = tMini.k;
-          scale = 1;
-          tX = x2 - tMini.x;
-          tY = y2 - tMini.y;
-        }
-        utilSetTransform(tiles, tX, tY, scale);
-        utilSetTransform(viewport, 0, 0, scale);
-        _isTransformed = true;
-        _tCurr = identity2.translate(x2, y2).scale(k2);
-        var zMain = geoScaleToZoom(context.projection.scale());
-        var zMini = geoScaleToZoom(k2);
-        _zDiff = zMain - zMini;
-        queueRedraw();
+  // modules/renderer/background_source.js
+  var import_lodash4 = __toESM(require_lodash());
+
+  // modules/util/IntervalTasksQueue.js
+  var IntervalTasksQueue = class {
+    /**
+     * Interval in milliseconds inside which only 1 task can execute.
+     * e.g. if interval is 200ms, and 5 async tasks are unqueued,
+     * they will complete in ~1s if not cleared
+     * @param {number} intervalInMs
+     */
+    constructor(intervalInMs) {
+      this.intervalInMs = intervalInMs;
+      this.pendingHandles = [];
+      this.time = 0;
+    }
+    enqueue(task) {
+      let taskTimeout = this.time;
+      this.time += this.intervalInMs;
+      this.pendingHandles.push(setTimeout(() => {
+        this.time -= this.intervalInMs;
+        task();
+      }, taskTimeout));
+    }
+    clear() {
+      this.pendingHandles.forEach((timeoutHandle) => {
+        clearTimeout(timeoutHandle);
+      });
+      this.pendingHandles = [];
+      this.time = 0;
+    }
+  };
+
+  // modules/renderer/background_source.js
+  var isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
+  window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function() {
+    isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
+  });
+  function localeDateString(s2) {
+    if (!s2) return null;
+    var options2 = { day: "numeric", month: "short", year: "numeric" };
+    var d2 = new Date(s2);
+    if (isNaN(d2.getTime())) return null;
+    return d2.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+  }
+  function vintageRange(vintage) {
+    var s2;
+    if (vintage.start || vintage.end) {
+      s2 = vintage.start || "?";
+      if (vintage.start !== vintage.end) {
+        s2 += " - " + (vintage.end || "?");
       }
-      function zoomEnded() {
-        if (_skipEvents)
-          return;
-        if (_gesture !== "pan")
-          return;
-        updateProjection();
-        _gesture = null;
-        context.map().center(projection2.invert(_cMini));
+    }
+    return s2;
+  }
+  function rendererBackgroundSource(data) {
+    var source = Object.assign({}, data);
+    var _offset = [0, 0];
+    var _name = source.name;
+    var _description = source.description;
+    var _best = !!source.best;
+    var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
+    source.tileSize = data.tileSize || 256;
+    source.zoomExtent = data.zoomExtent || [0, 22];
+    source.overzoom = data.overzoom !== false;
+    source.offset = function(val) {
+      if (!arguments.length) return _offset;
+      _offset = val;
+      return source;
+    };
+    source.nudge = function(val, zoomlevel) {
+      _offset[0] += val[0] / Math.pow(2, zoomlevel);
+      _offset[1] += val[1] / Math.pow(2, zoomlevel);
+      return source;
+    };
+    source.name = function() {
+      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
+      return _t("imagery." + id_safe + ".name", { default: (0, import_lodash4.escape)(_name) });
+    };
+    source.label = function() {
+      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
+      return _t.append("imagery." + id_safe + ".name", { default: (0, import_lodash4.escape)(_name) });
+    };
+    source.hasDescription = function() {
+      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
+      var descriptionText = _mainLocalizer.tInfo("imagery." + id_safe + ".description", { default: (0, import_lodash4.escape)(_description) }).text;
+      return descriptionText !== "";
+    };
+    source.description = function() {
+      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
+      return _t.append("imagery." + id_safe + ".description", { default: (0, import_lodash4.escape)(_description) });
+    };
+    source.best = function() {
+      return _best;
+    };
+    source.area = function() {
+      if (!data.polygon) return Number.MAX_VALUE;
+      var area = area_default({ type: "MultiPolygon", coordinates: [data.polygon] });
+      return isNaN(area) ? 0 : area;
+    };
+    source.imageryUsed = function() {
+      return _name || source.id;
+    };
+    source.template = function(val) {
+      if (!arguments.length) return _template;
+      if (source.id === "custom" || source.id === "Bing") {
+        _template = val;
       }
-      function updateProjection() {
-        var loc = context.map().center();
-        var tMain = context.projection.transform();
-        var zMain = geoScaleToZoom(tMain.k);
-        var zMini = Math.max(zMain - _zDiff, 0.5);
-        var kMini = geoZoomToScale(zMini);
-        projection2.translate([tMain.x, tMain.y]).scale(kMini);
-        var point2 = projection2(loc);
-        var mouse = _gesture === "pan" ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
-        var xMini = _cMini[0] - point2[0] + tMain.x + mouse[0];
-        var yMini = _cMini[1] - point2[1] + tMain.y + mouse[1];
-        projection2.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
-        _tCurr = projection2.transform();
-        if (_isTransformed) {
-          utilSetTransform(tiles, 0, 0);
-          utilSetTransform(viewport, 0, 0);
-          _isTransformed = false;
+      return source;
+    };
+    source.url = function(coord2) {
+      var result = _template.replace(/#[\s\S]*/u, "");
+      if (result === "") return result;
+      if (!source.type || source.id === "custom") {
+        if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(result)) {
+          source.type = "wms";
+          source.projection = "EPSG:3857";
+        } else if (/\{(x|y)\}/.test(result)) {
+          source.type = "tms";
+        } else if (/\{u\}/.test(result)) {
+          source.type = "bing";
         }
-        zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
-        _skipEvents = true;
-        wrap2.call(zoom.transform, _tCurr);
-        _skipEvents = false;
       }
-      function redraw() {
-        clearTimeout(_timeoutID);
-        if (_isHidden)
-          return;
-        updateProjection();
-        var zMini = geoScaleToZoom(projection2.scale());
-        tiles = wrap2.selectAll(".map-in-map-tiles").data([0]);
-        tiles = tiles.enter().append("div").attr("class", "map-in-map-tiles").merge(tiles);
-        backgroundLayer.source(context.background().baseLayerSource()).projection(projection2).dimensions(_dMini);
-        var background = tiles.selectAll(".map-in-map-background").data([0]);
-        background.enter().append("div").attr("class", "map-in-map-background").merge(background).call(backgroundLayer);
-        var overlaySources = context.background().overlayLayerSources();
-        var activeOverlayLayers = [];
-        for (var i3 = 0; i3 < overlaySources.length; i3++) {
-          if (overlaySources[i3].validZoom(zMini)) {
-            if (!overlayLayers[i3])
-              overlayLayers[i3] = rendererTileLayer(context);
-            activeOverlayLayers.push(overlayLayers[i3].source(overlaySources[i3]).projection(projection2).dimensions(_dMini));
+      if (source.type === "wms") {
+        var tileToProjectedCoords = function(x2, y2, z2) {
+          var zoomSize = Math.pow(2, z2);
+          var lon = x2 / zoomSize * Math.PI * 2 - Math.PI;
+          var lat = Math.atan(Math.sinh(Math.PI * (1 - 2 * y2 / zoomSize)));
+          switch (source.projection) {
+            case "EPSG:4326":
+              return {
+                x: lon * 180 / Math.PI,
+                y: lat * 180 / Math.PI
+              };
+            default:
+              var mercCoords = mercatorRaw(lon, lat);
+              return {
+                x: 2003750834e-2 / Math.PI * mercCoords[0],
+                y: 2003750834e-2 / Math.PI * mercCoords[1]
+              };
+          }
+        };
+        var tileSize = source.tileSize;
+        var projection2 = source.projection;
+        var minXmaxY = tileToProjectedCoords(coord2[0], coord2[1], coord2[2]);
+        var maxXminY = tileToProjectedCoords(coord2[0] + 1, coord2[1] + 1, coord2[2]);
+        result = result.replace(/\{(\w+)\}/g, function(token, key) {
+          switch (key) {
+            case "width":
+            case "height":
+              return tileSize;
+            case "proj":
+              return projection2;
+            case "wkid":
+              return projection2.replace(/^EPSG:/, "");
+            case "bbox":
+              if (projection2 === "EPSG:4326" && // The CRS parameter implies version 1.3 (prior versions use SRS)
+              /VERSION=1.3|CRS={proj}/.test(source.template().toUpperCase())) {
+                return maxXminY.y + "," + minXmaxY.x + "," + minXmaxY.y + "," + maxXminY.x;
+              } else {
+                return minXmaxY.x + "," + maxXminY.y + "," + maxXminY.x + "," + minXmaxY.y;
+              }
+            case "w":
+              return minXmaxY.x;
+            case "s":
+              return maxXminY.y;
+            case "n":
+              return maxXminY.x;
+            case "e":
+              return minXmaxY.y;
+            default:
+              return token;
           }
-        }
-        var overlay = tiles.selectAll(".map-in-map-overlay").data([0]);
-        overlay = overlay.enter().append("div").attr("class", "map-in-map-overlay").merge(overlay);
-        var overlays = overlay.selectAll("div").data(activeOverlayLayers, function(d2) {
-          return d2.source().name();
         });
-        overlays.exit().remove();
-        overlays = overlays.enter().append("div").merge(overlays).each(function(layer) {
-          select_default2(this).call(layer);
+      } else if (source.type === "tms") {
+        result = result.replace("{x}", coord2[0]).replace("{y}", coord2[1]).replace(/\{[t-]y\}/, Math.pow(2, coord2[2]) - coord2[1] - 1).replace(/\{z(oom)?\}/, coord2[2]).replace(/\{@2x\}|\{r\}/, isRetina ? "@2x" : "");
+      } else if (source.type === "bing") {
+        result = result.replace("{u}", function() {
+          var u2 = "";
+          for (var zoom = coord2[2]; zoom > 0; zoom--) {
+            var b2 = 0;
+            var mask = 1 << zoom - 1;
+            if ((coord2[0] & mask) !== 0) b2++;
+            if ((coord2[1] & mask) !== 0) b2 += 2;
+            u2 += b2.toString();
+          }
+          return u2;
         });
-        var dataLayers = tiles.selectAll(".map-in-map-data").data([0]);
-        dataLayers.exit().remove();
-        dataLayers = dataLayers.enter().append("svg").attr("class", "map-in-map-data").merge(dataLayers).call(dataLayer).call(debugLayer);
-        if (_gesture !== "pan") {
-          var getPath = path_default(projection2);
-          var bbox2 = { type: "Polygon", coordinates: [context.map().extent().polygon()] };
-          viewport = wrap2.selectAll(".map-in-map-viewport").data([0]);
-          viewport = viewport.enter().append("svg").attr("class", "map-in-map-viewport").merge(viewport);
-          var path = viewport.selectAll(".map-in-map-bbox").data([bbox2]);
-          path.enter().append("path").attr("class", "map-in-map-bbox").merge(path).attr("d", getPath).classed("thick", function(d2) {
-            return getPath.area(d2) < 30;
-          });
-        }
-      }
-      function queueRedraw() {
-        clearTimeout(_timeoutID);
-        _timeoutID = setTimeout(function() {
-          redraw();
-        }, 750);
-      }
-      function toggle(d3_event) {
-        if (d3_event)
-          d3_event.preventDefault();
-        _isHidden = !_isHidden;
-        context.container().select(".minimap-toggle-item").classed("active", !_isHidden).select("input").property("checked", !_isHidden);
-        if (_isHidden) {
-          wrap2.style("display", "block").style("opacity", "1").transition().duration(200).style("opacity", "0").on("end", function() {
-            selection2.selectAll(".map-in-map").style("display", "none");
-          });
-        } else {
-          wrap2.style("display", "block").style("opacity", "0").transition().duration(200).style("opacity", "1").on("end", function() {
-            redraw();
-          });
-        }
       }
-      uiMapInMap.toggle = toggle;
-      wrap2 = selection2.selectAll(".map-in-map").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "map-in-map").style("display", _isHidden ? "none" : "block").call(zoom).on("dblclick.zoom", null).merge(wrap2);
-      _dMini = [200, 150];
-      _cMini = geoVecScale(_dMini, 0.5);
-      context.map().on("drawn.map-in-map", function(drawn) {
-        if (drawn.full === true) {
-          redraw();
-        }
+      result = result.replace(/\{switch:([^}]+)\}/, function(s2, r2) {
+        var subdomains = r2.split(",");
+        return subdomains[(coord2[0] + coord2[1]) % subdomains.length];
       });
-      redraw();
-      context.keybinding().on(_t("background.minimap.key"), toggle);
-    }
-    return mapInMap;
+      return result;
+    };
+    source.validZoom = function(z2) {
+      return source.zoomExtent[0] <= z2 && (source.overzoom || source.zoomExtent[1] > z2);
+    };
+    source.isLocatorOverlay = function() {
+      return source.id === "mapbox_locator_overlay";
+    };
+    source.isHidden = function() {
+      return source.id === "DigitalGlobe-Premium-vintage" || source.id === "DigitalGlobe-Standard-vintage";
+    };
+    source.copyrightNotices = function() {
+    };
+    source.getMetadata = function(center, tileCoord, callback) {
+      var vintage = {
+        start: localeDateString(source.startDate),
+        end: localeDateString(source.endDate)
+      };
+      vintage.range = vintageRange(vintage);
+      var metadata = { vintage };
+      callback(null, metadata);
+    };
+    return source;
   }
-
-  // modules/ui/notice.js
-  function uiNotice(context) {
-    return function(selection2) {
-      var div = selection2.append("div").attr("class", "notice");
-      var button = div.append("button").attr("class", "zoom-to notice fillD").on("click", function() {
-        context.map().zoomEase(context.minEditableZoom());
-      }).on("wheel", function(d3_event) {
-        var e22 = new WheelEvent(d3_event.type, d3_event);
-        context.surface().node().dispatchEvent(e22);
+  rendererBackgroundSource.Bing = function(data, dispatch14) {
+    data.template = "https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=1&pr=odbl&n=z";
+    var bing = rendererBackgroundSource(data);
+    var key = utilAesDecrypt("5c875730b09c6b422433e807e1ff060b6536c791dbfffcffc4c6b18a1bdba1f14593d151adb50e19e1be1ab19aef813bf135d0f103475e5c724dec94389e45d0");
+    const strictParam = "n";
+    var url = "https://dev.virtualearth.net/REST/v1/Imagery/Metadata/AerialOSM?include=ImageryProviders&uriScheme=https&key=" + key;
+    var cache = {};
+    var inflight = {};
+    var providers = [];
+    var taskQueue = new IntervalTasksQueue(250);
+    var metadataLastZoom = -1;
+    json_default(url).then(function(json) {
+      let imageryResource = json.resourceSets[0].resources[0];
+      let template = imageryResource.imageUrl;
+      let subDomains = imageryResource.imageUrlSubdomains;
+      let subDomainNumbers = subDomains.map((subDomain) => {
+        return subDomain.substring(1);
+      }).join(",");
+      template = template.replace("{subdomain}", "t{switch:".concat(subDomainNumbers, "}")).replace("{quadkey}", "{u}");
+      if (!new URLSearchParams(template).has(strictParam)) {
+        template += "&".concat(strictParam, "=z");
+      }
+      bing.template(template);
+      providers = imageryResource.imageryProviders.map(function(provider) {
+        return {
+          attribution: provider.attribution,
+          areas: provider.coverageAreas.map(function(area) {
+            return {
+              zoom: [area.zoomMin, area.zoomMax],
+              extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
+            };
+          })
+        };
       });
-      button.call(svgIcon("#iD-icon-plus", "pre-text")).append("span").attr("class", "label").call(_t.append("zoom_in_edit"));
-      function disableTooHigh() {
-        var canEdit = context.map().zoom() >= context.minEditableZoom();
-        div.style("display", canEdit ? "none" : "block");
+      dispatch14.call("change");
+    }).catch(function() {
+    });
+    bing.copyrightNotices = function(zoom, extent) {
+      zoom = Math.min(zoom, 21);
+      return providers.filter(function(provider) {
+        return provider.areas.some(function(area) {
+          return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
+        });
+      }).map(function(provider) {
+        return provider.attribution;
+      }).join(", ");
+    };
+    bing.getMetadata = function(center, tileCoord, callback) {
+      var tileID = tileCoord.slice(0, 3).join("/");
+      var zoom = Math.min(tileCoord[2], 21);
+      var centerPoint = center[1] + "," + center[0];
+      var url2 = "https://dev.virtualearth.net/REST/v1/Imagery/BasicMetadata/AerialOSM/" + centerPoint + "?zl=" + zoom + "&key=" + key;
+      if (inflight[tileID]) return;
+      if (!cache[tileID]) {
+        cache[tileID] = {};
       }
-      context.map().on("move.notice", debounce_default(disableTooHigh, 500));
-      disableTooHigh();
+      if (cache[tileID] && cache[tileID].metadata) {
+        return callback(null, cache[tileID].metadata);
+      }
+      inflight[tileID] = true;
+      if (metadataLastZoom !== tileCoord[2]) {
+        metadataLastZoom = tileCoord[2];
+        taskQueue.clear();
+      }
+      taskQueue.enqueue(() => {
+        json_default(url2).then(function(result) {
+          delete inflight[tileID];
+          if (!result) {
+            throw new Error("Unknown Error");
+          }
+          var vintage = {
+            start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
+            end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
+          };
+          vintage.range = vintageRange(vintage);
+          var metadata = { vintage };
+          cache[tileID].metadata = metadata;
+          if (callback) callback(null, metadata);
+        }).catch(function(err) {
+          delete inflight[tileID];
+          if (callback) callback(err.message);
+        });
+      });
     };
-  }
-
-  // modules/ui/photoviewer.js
-  function uiPhotoviewer(context) {
-    var dispatch14 = dispatch_default("resize");
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    function photoviewer(selection2) {
-      selection2.append("button").attr("class", "thumb-hide").attr("title", _t("icons.close")).on("click", function() {
-        if (services.streetside) {
-          services.streetside.hideViewer(context);
-        }
-        if (services.mapillary) {
-          services.mapillary.hideViewer(context);
-        }
-        if (services.kartaview) {
-          services.kartaview.hideViewer(context);
+    bing.terms_url = "https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details";
+    return bing;
+  };
+  rendererBackgroundSource.Esri = function(data) {
+    if (data.template.match(/blankTile/) === null) {
+      data.template = data.template + "?blankTile=false";
+    }
+    var esri = rendererBackgroundSource(data);
+    var cache = {};
+    var inflight = {};
+    var _prevCenter;
+    esri.fetchTilemap = function(center) {
+      if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5e3) return;
+      _prevCenter = center;
+      var z2 = 20;
+      var dummyUrl = esri.url([1, 2, 3]);
+      var x2 = Math.floor((center[0] + 180) / 360 * Math.pow(2, z2));
+      var y2 = Math.floor((1 - Math.log(Math.tan(center[1] * Math.PI / 180) + 1 / Math.cos(center[1] * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, z2));
+      var tilemapUrl = dummyUrl.replace(/tile\/[0-9]+\/[0-9]+\/[0-9]+\?blankTile=false/, "tilemap") + "/" + z2 + "/" + y2 + "/" + x2 + "/8/8";
+      json_default(tilemapUrl).then(function(tilemap) {
+        if (!tilemap) {
+          throw new Error("Unknown Error");
         }
-        if (services.mapilio) {
-          services.mapilio.hideViewer(context);
-        }
-        if (services.vegbilder) {
-          services.vegbilder.hideViewer(context);
+        var hasTiles = true;
+        for (var i3 = 0; i3 < tilemap.data.length; i3++) {
+          if (!tilemap.data[i3]) {
+            hasTiles = false;
+            break;
+          }
         }
-      }).append("div").call(svgIcon("#iD-icon-close"));
-      function preventDefault(d3_event) {
-        d3_event.preventDefault();
+        esri.zoomExtent[1] = hasTiles ? 22 : 19;
+      }).catch(function() {
+      });
+    };
+    esri.getMetadata = function(center, tileCoord, callback) {
+      if (esri.id !== "EsriWorldImagery") {
+        return callback(null, {});
       }
-      selection2.append("button").attr("class", "resize-handle-xy").on("touchstart touchdown touchend", preventDefault).on(
-        _pointerPrefix + "down",
-        buildResizeListener(selection2, "resize", dispatch14, { resizeOnX: true, resizeOnY: true })
-      );
-      selection2.append("button").attr("class", "resize-handle-x").on("touchstart touchdown touchend", preventDefault).on(
-        _pointerPrefix + "down",
-        buildResizeListener(selection2, "resize", dispatch14, { resizeOnX: true })
-      );
-      selection2.append("button").attr("class", "resize-handle-y").on("touchstart touchdown touchend", preventDefault).on(
-        _pointerPrefix + "down",
-        buildResizeListener(selection2, "resize", dispatch14, { resizeOnY: true })
-      );
-      function buildResizeListener(target, eventName, dispatch15, options2) {
-        var resizeOnX = !!options2.resizeOnX;
-        var resizeOnY = !!options2.resizeOnY;
-        var minHeight = options2.minHeight || 240;
-        var minWidth = options2.minWidth || 320;
-        var pointerId;
-        var startX;
-        var startY;
-        var startWidth;
-        var startHeight;
-        function startResize(d3_event) {
-          if (pointerId !== (d3_event.pointerId || "mouse"))
-            return;
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          var mapSize = context.map().dimensions();
-          if (resizeOnX) {
-            var maxWidth = mapSize[0];
-            var newWidth = clamp3(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
-            target.style("width", newWidth + "px");
-          }
-          if (resizeOnY) {
-            var maxHeight = mapSize[1] - 90;
-            var newHeight = clamp3(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
-            target.style("height", newHeight + "px");
-          }
-          dispatch15.call(eventName, target, subtractPadding(utilGetDimensions(target, true), target));
+      var tileID = tileCoord.slice(0, 3).join("/");
+      var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
+      var centerPoint = center[0] + "," + center[1];
+      var unknown = _t("info_panels.background.unknown");
+      var vintage = {};
+      var metadata = {};
+      if (inflight[tileID]) return;
+      var url = "https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/4/query";
+      url += "?returnGeometry=false&geometry=" + centerPoint + "&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json";
+      if (!cache[tileID]) {
+        cache[tileID] = {};
+      }
+      if (cache[tileID] && cache[tileID].metadata) {
+        return callback(null, cache[tileID].metadata);
+      }
+      inflight[tileID] = true;
+      json_default(url).then(function(result) {
+        delete inflight[tileID];
+        result = result.features.map((f2) => f2.attributes).filter((a2) => a2.MinMapLevel <= zoom && a2.MaxMapLevel >= zoom)[0];
+        if (!result) {
+          throw new Error("Unknown Error");
+        } else if (result.features && result.features.length < 1) {
+          throw new Error("No Results");
+        } else if (result.error && result.error.message) {
+          throw new Error(result.error.message);
         }
-        function clamp3(num, min3, max3) {
-          return Math.max(min3, Math.min(num, max3));
+        var captureDate = localeDateString(result.SRC_DATE2);
+        vintage = {
+          start: captureDate,
+          end: captureDate,
+          range: captureDate
+        };
+        metadata = {
+          vintage,
+          source: clean2(result.NICE_NAME),
+          description: clean2(result.NICE_DESC),
+          resolution: clean2(+Number(result.SRC_RES).toFixed(4)),
+          accuracy: clean2(+Number(result.SRC_ACC).toFixed(4))
+        };
+        if (isFinite(metadata.resolution)) {
+          metadata.resolution += " m";
         }
-        function stopResize(d3_event) {
-          if (pointerId !== (d3_event.pointerId || "mouse"))
-            return;
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          select_default2(window).on("." + eventName, null);
+        if (isFinite(metadata.accuracy)) {
+          metadata.accuracy += " m";
         }
-        return function initResize(d3_event) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          pointerId = d3_event.pointerId || "mouse";
-          startX = d3_event.clientX;
-          startY = d3_event.clientY;
-          var targetRect = target.node().getBoundingClientRect();
-          startWidth = targetRect.width;
-          startHeight = targetRect.height;
-          select_default2(window).on(_pointerPrefix + "move." + eventName, startResize, false).on(_pointerPrefix + "up." + eventName, stopResize, false);
-          if (_pointerPrefix === "pointer") {
-            select_default2(window).on("pointercancel." + eventName, stopResize, false);
+        cache[tileID].metadata = metadata;
+        if (callback) callback(null, metadata);
+      }).catch(function(err) {
+        delete inflight[tileID];
+        if (callback) callback(err.message);
+      });
+      function clean2(val) {
+        return String(val).trim() || unknown;
+      }
+    };
+    return esri;
+  };
+  rendererBackgroundSource.None = function() {
+    var source = rendererBackgroundSource({ id: "none", template: "" });
+    source.name = function() {
+      return _t("background.none");
+    };
+    source.label = function() {
+      return _t.append("background.none");
+    };
+    source.imageryUsed = function() {
+      return null;
+    };
+    source.area = function() {
+      return -1;
+    };
+    return source;
+  };
+  rendererBackgroundSource.Custom = function(template) {
+    var source = rendererBackgroundSource({ id: "custom", template });
+    source.name = function() {
+      return _t("background.custom");
+    };
+    source.label = function() {
+      return _t.append("background.custom");
+    };
+    source.imageryUsed = function() {
+      var cleaned = source.template();
+      if (cleaned.indexOf("?") !== -1) {
+        var parts = cleaned.split("?", 2);
+        var qs = utilStringQs(parts[1]);
+        ["access_token", "connectId", "token", "Signature"].forEach(function(param) {
+          if (qs[param]) {
+            qs[param] = "{apikey}";
           }
-        };
+        });
+        cleaned = parts[0] + "?" + utilQsString(qs, true);
       }
+      cleaned = cleaned.replace(/token\/(\w+)/, "token/{apikey}").replace(/key=(\w+)/, "key={apikey}");
+      return "Custom (" + cleaned + " )";
+    };
+    source.area = function() {
+      return -2;
+    };
+    return source;
+  };
+
+  // node_modules/@turf/helpers/dist/esm/index.js
+  var earthRadius = 63710088e-1;
+  var factors = {
+    centimeters: earthRadius * 100,
+    centimetres: earthRadius * 100,
+    degrees: 360 / (2 * Math.PI),
+    feet: earthRadius * 3.28084,
+    inches: earthRadius * 39.37,
+    kilometers: earthRadius / 1e3,
+    kilometres: earthRadius / 1e3,
+    meters: earthRadius,
+    metres: earthRadius,
+    miles: earthRadius / 1609.344,
+    millimeters: earthRadius * 1e3,
+    millimetres: earthRadius * 1e3,
+    nauticalmiles: earthRadius / 1852,
+    radians: 1,
+    yards: earthRadius * 1.0936
+  };
+  function feature2(geom, properties, options2 = {}) {
+    const feat = { type: "Feature" };
+    if (options2.id === 0 || options2.id) {
+      feat.id = options2.id;
     }
-    photoviewer.onMapResize = function() {
-      var photoviewer2 = context.container().select(".photoviewer");
-      var content = context.container().select(".main-content");
-      var mapDimensions = utilGetDimensions(content, true);
-      var photoDimensions = utilGetDimensions(photoviewer2, true);
-      if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
-        var setPhotoDimensions = [
-          Math.min(photoDimensions[0], mapDimensions[0]),
-          Math.min(photoDimensions[1], mapDimensions[1] - 90)
-        ];
-        photoviewer2.style("width", setPhotoDimensions[0] + "px").style("height", setPhotoDimensions[1] + "px");
-        dispatch14.call("resize", photoviewer2, subtractPadding(setPhotoDimensions, photoviewer2));
+    if (options2.bbox) {
+      feat.bbox = options2.bbox;
+    }
+    feat.properties = properties || {};
+    feat.geometry = geom;
+    return feat;
+  }
+  function polygon(coordinates, properties, options2 = {}) {
+    for (const ring of coordinates) {
+      if (ring.length < 4) {
+        throw new Error(
+          "Each LinearRing of a Polygon must have 4 or more Positions."
+        );
+      }
+      if (ring[ring.length - 1].length !== ring[0].length) {
+        throw new Error("First and last Position are not equivalent.");
+      }
+      for (let j2 = 0; j2 < ring[ring.length - 1].length; j2++) {
+        if (ring[ring.length - 1][j2] !== ring[0][j2]) {
+          throw new Error("First and last Position are not equivalent.");
+        }
       }
+    }
+    const geom = {
+      type: "Polygon",
+      coordinates
     };
-    function subtractPadding(dimensions, selection2) {
-      return [
-        dimensions[0] - parseFloat(selection2.style("padding-left")) - parseFloat(selection2.style("padding-right")),
-        dimensions[1] - parseFloat(selection2.style("padding-top")) - parseFloat(selection2.style("padding-bottom"))
-      ];
+    return feature2(geom, properties, options2);
+  }
+  function lineString(coordinates, properties, options2 = {}) {
+    if (coordinates.length < 2) {
+      throw new Error("coordinates must be an array of two or more positions");
     }
-    return utilRebind(photoviewer, dispatch14, "on");
+    const geom = {
+      type: "LineString",
+      coordinates
+    };
+    return feature2(geom, properties, options2);
   }
-
-  // modules/ui/restore.js
-  function uiRestore(context) {
-    return function(selection2) {
-      if (!context.history().hasRestorableChanges())
-        return;
-      let modalSelection = uiModal(selection2, true);
-      modalSelection.select(".modal").attr("class", "modal fillL");
-      let introModal = modalSelection.select(".content");
-      introModal.append("div").attr("class", "modal-section").append("h3").call(_t.append("restore.heading"));
-      introModal.append("div").attr("class", "modal-section").append("p").call(_t.append("restore.description"));
-      let buttonWrap = introModal.append("div").attr("class", "modal-actions");
-      let restore = buttonWrap.append("button").attr("class", "restore").on("click", () => {
-        context.history().restore();
-        modalSelection.remove();
-      });
-      restore.append("svg").attr("class", "logo logo-restore").append("use").attr("xlink:href", "#iD-logo-restore");
-      restore.append("div").call(_t.append("restore.restore"));
-      let reset = buttonWrap.append("button").attr("class", "reset").on("click", () => {
-        context.history().clearSaved();
-        modalSelection.remove();
-      });
-      reset.append("svg").attr("class", "logo logo-reset").append("use").attr("xlink:href", "#iD-logo-reset");
-      reset.append("div").call(_t.append("restore.reset"));
-      restore.node().focus();
+  function multiLineString(coordinates, properties, options2 = {}) {
+    const geom = {
+      type: "MultiLineString",
+      coordinates
+    };
+    return feature2(geom, properties, options2);
+  }
+  function multiPolygon(coordinates, properties, options2 = {}) {
+    const geom = {
+      type: "MultiPolygon",
+      coordinates
     };
+    return feature2(geom, properties, options2);
   }
 
-  // modules/ui/scale.js
-  function uiScale(context) {
-    var projection2 = context.projection, isImperial = !_mainLocalizer.usesMetric(), maxLength = 180, tickHeight = 8;
-    function scaleDefs(loc1, loc2) {
-      var lat = (loc2[1] + loc1[1]) / 2, conversion = isImperial ? 3.28084 : 1, dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion, scale = { dist: 0, px: 0, text: "" }, buckets, i3, val, dLon;
-      if (isImperial) {
-        buckets = [528e4, 528e3, 52800, 5280, 500, 50, 5, 1];
-      } else {
-        buckets = [5e6, 5e5, 5e4, 5e3, 500, 50, 5, 1];
-      }
-      for (i3 = 0; i3 < buckets.length; i3++) {
-        val = buckets[i3];
-        if (dist >= val) {
-          scale.dist = Math.floor(dist / val) * val;
+  // node_modules/@turf/invariant/dist/esm/index.js
+  function getGeom(geojson) {
+    if (geojson.type === "Feature") {
+      return geojson.geometry;
+    }
+    return geojson;
+  }
+
+  // node_modules/@turf/bbox-clip/dist/esm/index.js
+  function lineclip(points, bbox2, result) {
+    var len = points.length, codeA = bitCode(points[0], bbox2), part = [], i3, codeB, lastCode;
+    let a2;
+    let b2;
+    if (!result)
+      result = [];
+    for (i3 = 1; i3 < len; i3++) {
+      a2 = points[i3 - 1];
+      b2 = points[i3];
+      codeB = lastCode = bitCode(b2, bbox2);
+      while (true) {
+        if (!(codeA | codeB)) {
+          part.push(a2);
+          if (codeB !== lastCode) {
+            part.push(b2);
+            if (i3 < len - 1) {
+              result.push(part);
+              part = [];
+            }
+          } else if (i3 === len - 1) {
+            part.push(b2);
+          }
+          break;
+        } else if (codeA & codeB) {
           break;
+        } else if (codeA) {
+          a2 = intersect(a2, b2, codeA, bbox2);
+          codeA = bitCode(a2, bbox2);
         } else {
-          scale.dist = +dist.toFixed(2);
+          b2 = intersect(a2, b2, codeB, bbox2);
+          codeB = bitCode(b2, bbox2);
         }
       }
-      dLon = geoMetersToLon(scale.dist / conversion, lat);
-      scale.px = Math.round(projection2([loc1[0] + dLon, loc1[1]])[0]);
-      scale.text = displayLength(scale.dist / conversion, isImperial);
-      return scale;
-    }
-    function update(selection2) {
-      var dims = context.map().dimensions(), loc1 = projection2.invert([0, dims[1]]), loc2 = projection2.invert([maxLength, dims[1]]), scale = scaleDefs(loc1, loc2);
-      selection2.select(".scale-path").attr("d", "M0.5,0.5v" + tickHeight + "h" + scale.px + "v-" + tickHeight);
-      selection2.select(".scale-text").style(_mainLocalizer.textDirection() === "ltr" ? "left" : "right", scale.px + 16 + "px").text(scale.text);
+      codeA = lastCode;
     }
-    return function(selection2) {
-      function switchUnits() {
-        isImperial = !isImperial;
-        selection2.call(update);
-      }
-      var scalegroup = selection2.append("svg").attr("class", "scale").on("click", switchUnits).append("g").attr("transform", "translate(10,11)");
-      scalegroup.append("path").attr("class", "scale-path");
-      selection2.append("div").attr("class", "scale-text");
-      selection2.call(update);
-      context.map().on("move.scale", function() {
-        update(selection2);
-      });
-    };
+    if (part.length)
+      result.push(part);
+    return result;
   }
-
-  // modules/ui/shortcuts.js
-  function uiShortcuts(context) {
-    var detected = utilDetect();
-    var _activeTab = 0;
-    var _modalSelection;
-    var _selection = select_default2(null);
-    var _dataShortcuts;
-    function shortcutsModal(_modalSelection2) {
-      _modalSelection2.select(".modal").classed("modal-shortcuts", true);
-      var content = _modalSelection2.select(".content");
-      content.append("div").attr("class", "modal-section header").append("h2").call(_t.append("shortcuts.title"));
-      _mainFileFetcher.get("shortcuts").then(function(data) {
-        _dataShortcuts = data;
-        content.call(render);
-      }).catch(function() {
-      });
+  function polygonclip(points, bbox2) {
+    var result, edge, prev, prevInside, i3, p2, inside;
+    for (edge = 1; edge <= 8; edge *= 2) {
+      result = [];
+      prev = points[points.length - 1];
+      prevInside = !(bitCode(prev, bbox2) & edge);
+      for (i3 = 0; i3 < points.length; i3++) {
+        p2 = points[i3];
+        inside = !(bitCode(p2, bbox2) & edge);
+        if (inside !== prevInside)
+          result.push(intersect(prev, p2, edge, bbox2));
+        if (inside)
+          result.push(p2);
+        prev = p2;
+        prevInside = inside;
+      }
+      points = result;
+      if (!points.length)
+        break;
     }
-    function render(selection2) {
-      if (!_dataShortcuts)
-        return;
-      var wrapper = selection2.selectAll(".wrapper").data([0]);
-      var wrapperEnter = wrapper.enter().append("div").attr("class", "wrapper modal-section");
-      var tabsBar = wrapperEnter.append("div").attr("class", "tabs-bar");
-      var shortcutsList = wrapperEnter.append("div").attr("class", "shortcuts-list");
-      wrapper = wrapper.merge(wrapperEnter);
-      var tabs = tabsBar.selectAll(".tab").data(_dataShortcuts);
-      var tabsEnter = tabs.enter().append("a").attr("class", "tab").attr("href", "#").on("click", function(d3_event, d2) {
-        d3_event.preventDefault();
-        var i3 = _dataShortcuts.indexOf(d2);
-        _activeTab = i3;
-        render(selection2);
-      });
-      tabsEnter.append("span").html(function(d2) {
-        return _t.html(d2.text);
-      });
-      wrapper.selectAll(".tab").classed("active", function(d2, i3) {
-        return i3 === _activeTab;
-      });
-      var shortcuts = shortcutsList.selectAll(".shortcut-tab").data(_dataShortcuts);
-      var shortcutsEnter = shortcuts.enter().append("div").attr("class", function(d2) {
-        return "shortcut-tab shortcut-tab-" + d2.tab;
-      });
-      var columnsEnter = shortcutsEnter.selectAll(".shortcut-column").data(function(d2) {
-        return d2.columns;
-      }).enter().append("table").attr("class", "shortcut-column");
-      var rowsEnter = columnsEnter.selectAll(".shortcut-row").data(function(d2) {
-        return d2.rows;
-      }).enter().append("tr").attr("class", "shortcut-row");
-      var sectionRows = rowsEnter.filter(function(d2) {
-        return !d2.shortcuts;
-      });
-      sectionRows.append("td");
-      sectionRows.append("td").attr("class", "shortcut-section").append("h3").html(function(d2) {
-        return _t.html(d2.text);
-      });
-      var shortcutRows = rowsEnter.filter(function(d2) {
-        return d2.shortcuts;
-      });
-      var shortcutKeys = shortcutRows.append("td").attr("class", "shortcut-keys");
-      var modifierKeys = shortcutKeys.filter(function(d2) {
-        return d2.modifiers;
-      });
-      modifierKeys.selectAll("kbd.modifier").data(function(d2) {
-        if (detected.os === "win" && d2.text === "shortcuts.editing.commands.redo") {
-          return ["\u2318"];
-        } else if (detected.os !== "mac" && d2.text === "shortcuts.browsing.display_options.fullscreen") {
-          return [];
-        } else {
-          return d2.modifiers;
+    return result;
+  }
+  function intersect(a2, b2, edge, bbox2) {
+    return edge & 8 ? [a2[0] + (b2[0] - a2[0]) * (bbox2[3] - a2[1]) / (b2[1] - a2[1]), bbox2[3]] : edge & 4 ? [a2[0] + (b2[0] - a2[0]) * (bbox2[1] - a2[1]) / (b2[1] - a2[1]), bbox2[1]] : edge & 2 ? [bbox2[2], a2[1] + (b2[1] - a2[1]) * (bbox2[2] - a2[0]) / (b2[0] - a2[0])] : edge & 1 ? [bbox2[0], a2[1] + (b2[1] - a2[1]) * (bbox2[0] - a2[0]) / (b2[0] - a2[0])] : null;
+  }
+  function bitCode(p2, bbox2) {
+    var code = 0;
+    if (p2[0] < bbox2[0])
+      code |= 1;
+    else if (p2[0] > bbox2[2])
+      code |= 2;
+    if (p2[1] < bbox2[1])
+      code |= 4;
+    else if (p2[1] > bbox2[3])
+      code |= 8;
+    return code;
+  }
+  function bboxClip(feature3, bbox2) {
+    const geom = getGeom(feature3);
+    const type2 = geom.type;
+    const properties = feature3.type === "Feature" ? feature3.properties : {};
+    let coords = geom.coordinates;
+    switch (type2) {
+      case "LineString":
+      case "MultiLineString": {
+        const lines = [];
+        if (type2 === "LineString") {
+          coords = [coords];
         }
-      }).enter().each(function() {
-        var selection3 = select_default2(this);
-        selection3.append("kbd").attr("class", "modifier").text(function(d2) {
-          return uiCmd.display(d2);
+        coords.forEach((line) => {
+          lineclip(line, bbox2, lines);
         });
-        selection3.append("span").text("+");
-      });
-      shortcutKeys.selectAll("kbd.shortcut").data(function(d2) {
-        var arr = d2.shortcuts;
-        if (detected.os === "win" && d2.text === "shortcuts.editing.commands.redo") {
-          arr = ["Y"];
-        } else if (detected.os !== "mac" && d2.text === "shortcuts.browsing.display_options.fullscreen") {
-          arr = ["F11"];
+        if (lines.length === 1) {
+          return lineString(lines[0], properties);
         }
-        arr = arr.map(function(s2) {
-          return uiCmd.display(s2.indexOf(".") !== -1 ? _t(s2) : s2);
-        });
-        return utilArrayUniq(arr).map(function(s2) {
-          return {
-            shortcut: s2,
-            separator: d2.separator,
-            suffix: d2.suffix
-          };
-        });
-      }).enter().each(function(d2, i3, nodes) {
-        var selection3 = select_default2(this);
-        var click = d2.shortcut.toLowerCase().match(/(.*).click/);
-        if (click && click[1]) {
-          selection3.call(svgIcon("#iD-walkthrough-mouse-" + click[1], "operation"));
-        } else if (d2.shortcut.toLowerCase() === "long-press") {
-          selection3.call(svgIcon("#iD-walkthrough-longpress", "longpress operation"));
-        } else if (d2.shortcut.toLowerCase() === "tap") {
-          selection3.call(svgIcon("#iD-walkthrough-tap", "tap operation"));
-        } else {
-          selection3.append("kbd").attr("class", "shortcut").text(function(d4) {
-            return d4.shortcut;
-          });
+        return multiLineString(lines, properties);
+      }
+      case "Polygon":
+        return polygon(clipPolygon(coords, bbox2), properties);
+      case "MultiPolygon":
+        return multiPolygon(
+          coords.map((poly) => {
+            return clipPolygon(poly, bbox2);
+          }),
+          properties
+        );
+      default:
+        throw new Error("geometry " + type2 + " not supported");
+    }
+  }
+  function clipPolygon(rings, bbox2) {
+    const outRings = [];
+    for (const ring of rings) {
+      const clipped = polygonclip(ring, bbox2);
+      if (clipped.length > 0) {
+        if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
+          clipped.push(clipped[0]);
         }
-        if (i3 < nodes.length - 1) {
-          selection3.append("span").html(d2.separator || "\xA0" + _t.html("shortcuts.or") + "\xA0");
-        } else if (i3 === nodes.length - 1 && d2.suffix) {
-          selection3.append("span").text(d2.suffix);
+        if (clipped.length >= 4) {
+          outRings.push(clipped);
         }
-      });
-      shortcutKeys.filter(function(d2) {
-        return d2.gesture;
-      }).each(function() {
-        var selection3 = select_default2(this);
-        selection3.append("span").text("+");
-        selection3.append("span").attr("class", "gesture").html(function(d2) {
-          return _t.html(d2.gesture);
-        });
-      });
-      shortcutRows.append("td").attr("class", "shortcut-desc").html(function(d2) {
-        return d2.text ? _t.html(d2.text) : "\xA0";
-      });
-      wrapper.selectAll(".shortcut-tab").style("display", function(d2, i3) {
-        return i3 === _activeTab ? "flex" : "none";
-      });
-    }
-    return function(selection2, show) {
-      _selection = selection2;
-      if (show) {
-        _modalSelection = uiModal(selection2);
-        _modalSelection.call(shortcutsModal);
-      } else {
-        context.keybinding().on([_t("shortcuts.toggle.key"), "?"], function() {
-          if (context.container().selectAll(".modal-shortcuts").size()) {
-            if (_modalSelection) {
-              _modalSelection.close();
-              _modalSelection = null;
-            }
-          } else {
-            _modalSelection = uiModal(_selection);
-            _modalSelection.call(shortcutsModal);
-          }
-        });
       }
-    };
-  }
-
-  // modules/ui/data_header.js
-  function uiDataHeader() {
-    var _datum;
-    function dataHeader(selection2) {
-      var header = selection2.selectAll(".data-header").data(
-        _datum ? [_datum] : [],
-        function(d2) {
-          return d2.__featurehash__;
-        }
-      );
-      header.exit().remove();
-      var headerEnter = header.enter().append("div").attr("class", "data-header");
-      var iconEnter = headerEnter.append("div").attr("class", "data-header-icon");
-      iconEnter.append("div").attr("class", "preset-icon-28").call(svgIcon("#iD-icon-data", "note-fill"));
-      headerEnter.append("div").attr("class", "data-header-label").call(_t.append("map_data.layers.custom.title"));
     }
-    dataHeader.datum = function(val) {
-      if (!arguments.length)
-        return _datum;
-      _datum = val;
-      return this;
-    };
-    return dataHeader;
+    return outRings;
   }
+  var turf_bbox_clip_default = bboxClip;
 
-  // modules/ui/combobox.js
-  var _comboHideTimerID;
-  function uiCombobox(context, klass) {
-    var dispatch14 = dispatch_default("accept", "cancel", "update");
-    var container = context.container();
-    var _suggestions = [];
-    var _data = [];
-    var _fetched = {};
-    var _selected = null;
-    var _canAutocomplete = true;
-    var _caseSensitive = false;
-    var _cancelFetch = false;
-    var _minItems = 2;
-    var _tDown = 0;
-    var _mouseEnterHandler, _mouseLeaveHandler;
-    var _fetcher = function(val, cb) {
-      cb(_data.filter(function(d2) {
-        var terms = d2.terms || [];
-        terms.push(d2.value);
-        if (d2.key) {
-          terms.push(d2.key);
-        }
-        return terms.some(function(term) {
-          return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
-        });
-      }));
-    };
-    var combobox = function(input, attachTo) {
-      if (!input || input.empty())
-        return;
-      input.classed("combobox-input", true).on("focus.combo-input", focus).on("blur.combo-input", blur).on("keydown.combo-input", keydown).on("keyup.combo-input", keyup).on("input.combo-input", change).on("mousedown.combo-input", mousedown).each(function() {
-        var parent = this.parentNode;
-        var sibling = this.nextSibling;
-        select_default2(parent).selectAll(".combobox-caret").filter(function(d2) {
-          return d2 === input.node();
-        }).data([input.node()]).enter().insert("div", function() {
-          return sibling;
-        }).attr("class", "combobox-caret").on("mousedown.combo-caret", function(d3_event) {
-          d3_event.preventDefault();
-          input.node().focus();
-          mousedown(d3_event);
-        }).on("mouseup.combo-caret", function(d3_event) {
-          d3_event.preventDefault();
-          mouseup(d3_event);
-        });
-      });
-      function mousedown(d3_event) {
-        if (d3_event.button !== 0)
-          return;
-        if (input.classed("disabled"))
-          return;
-        _tDown = +/* @__PURE__ */ new Date();
-        var start2 = input.property("selectionStart");
-        var end = input.property("selectionEnd");
-        if (start2 !== end) {
-          var val = utilGetSetValue(input);
-          input.node().setSelectionRange(val.length, val.length);
-          return;
-        }
-        input.on("mouseup.combo-input", mouseup);
-      }
-      function mouseup(d3_event) {
-        input.on("mouseup.combo-input", null);
-        if (d3_event.button !== 0)
-          return;
-        if (input.classed("disabled"))
-          return;
-        if (input.node() !== document.activeElement)
-          return;
-        var start2 = input.property("selectionStart");
-        var end = input.property("selectionEnd");
-        if (start2 !== end)
-          return;
-        var combo = container.selectAll(".combobox");
-        if (combo.empty() || combo.datum() !== input.node()) {
-          var tOrig = _tDown;
-          window.setTimeout(function() {
-            if (tOrig !== _tDown)
-              return;
-            fetchComboData("", function() {
-              show();
-              render();
-            });
-          }, 250);
-        } else {
-          hide();
-        }
-      }
-      function focus() {
-        fetchComboData("");
-      }
-      function blur() {
-        _comboHideTimerID = window.setTimeout(hide, 75);
-      }
-      function show() {
-        hide();
-        container.insert("div", ":first-child").datum(input.node()).attr("class", "combobox" + (klass ? " combobox-" + klass : "")).style("position", "absolute").style("display", "block").style("left", "0px").on("mousedown.combo-container", function(d3_event) {
-          d3_event.preventDefault();
-        });
-        container.on("scroll.combo-scroll", render, true);
-      }
-      function hide() {
-        if (_comboHideTimerID) {
-          window.clearTimeout(_comboHideTimerID);
-          _comboHideTimerID = void 0;
-        }
-        container.selectAll(".combobox").remove();
-        container.on("scroll.combo-scroll", null);
-      }
-      function keydown(d3_event) {
-        var shown = !container.selectAll(".combobox").empty();
-        var tagName = input.node() ? input.node().tagName.toLowerCase() : "";
-        switch (d3_event.keyCode) {
-          case 8:
-          case 46:
-            d3_event.stopPropagation();
-            _selected = null;
-            render();
-            input.on("input.combo-input", function() {
-              var start2 = input.property("selectionStart");
-              input.node().setSelectionRange(start2, start2);
-              input.on("input.combo-input", change);
-              change(false);
-            });
+  // node_modules/@turf/meta/dist/esm/index.js
+  function coordEach(geojson, callback, excludeWrapCoord) {
+    if (geojson === null)
+      return;
+    var j2, k2, l2, geometry, stopG, coords, geometryMaybeCollection, wrapShrink = 0, coordIndex = 0, isGeometryCollection, type2 = geojson.type, isFeatureCollection = type2 === "FeatureCollection", isFeature = type2 === "Feature", stop = isFeatureCollection ? geojson.features.length : 1;
+    for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
+      geometryMaybeCollection = isFeatureCollection ? geojson.features[featureIndex].geometry : isFeature ? geojson.geometry : geojson;
+      isGeometryCollection = geometryMaybeCollection ? geometryMaybeCollection.type === "GeometryCollection" : false;
+      stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
+      for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
+        var multiFeatureIndex = 0;
+        var geometryIndex = 0;
+        geometry = isGeometryCollection ? geometryMaybeCollection.geometries[geomIndex] : geometryMaybeCollection;
+        if (geometry === null)
+          continue;
+        coords = geometry.coordinates;
+        var geomType = geometry.type;
+        wrapShrink = excludeWrapCoord && (geomType === "Polygon" || geomType === "MultiPolygon") ? 1 : 0;
+        switch (geomType) {
+          case null:
             break;
-          case 9:
-            accept(d3_event);
+          case "Point":
+            if (callback(
+              coords,
+              coordIndex,
+              featureIndex,
+              multiFeatureIndex,
+              geometryIndex
+            ) === false)
+              return false;
+            coordIndex++;
+            multiFeatureIndex++;
             break;
-          case 13:
-            d3_event.preventDefault();
-            d3_event.stopPropagation();
-            accept(d3_event);
+          case "LineString":
+          case "MultiPoint":
+            for (j2 = 0; j2 < coords.length; j2++) {
+              if (callback(
+                coords[j2],
+                coordIndex,
+                featureIndex,
+                multiFeatureIndex,
+                geometryIndex
+              ) === false)
+                return false;
+              coordIndex++;
+              if (geomType === "MultiPoint")
+                multiFeatureIndex++;
+            }
+            if (geomType === "LineString")
+              multiFeatureIndex++;
             break;
-          case 38:
-            if (tagName === "textarea" && !shown)
-              return;
-            d3_event.preventDefault();
-            if (tagName === "input" && !shown) {
-              show();
+          case "Polygon":
+          case "MultiLineString":
+            for (j2 = 0; j2 < coords.length; j2++) {
+              for (k2 = 0; k2 < coords[j2].length - wrapShrink; k2++) {
+                if (callback(
+                  coords[j2][k2],
+                  coordIndex,
+                  featureIndex,
+                  multiFeatureIndex,
+                  geometryIndex
+                ) === false)
+                  return false;
+                coordIndex++;
+              }
+              if (geomType === "MultiLineString")
+                multiFeatureIndex++;
+              if (geomType === "Polygon")
+                geometryIndex++;
             }
-            nav(-1);
+            if (geomType === "Polygon")
+              multiFeatureIndex++;
             break;
-          case 40:
-            if (tagName === "textarea" && !shown)
-              return;
-            d3_event.preventDefault();
-            if (tagName === "input" && !shown) {
-              show();
+          case "MultiPolygon":
+            for (j2 = 0; j2 < coords.length; j2++) {
+              geometryIndex = 0;
+              for (k2 = 0; k2 < coords[j2].length; k2++) {
+                for (l2 = 0; l2 < coords[j2][k2].length - wrapShrink; l2++) {
+                  if (callback(
+                    coords[j2][k2][l2],
+                    coordIndex,
+                    featureIndex,
+                    multiFeatureIndex,
+                    geometryIndex
+                  ) === false)
+                    return false;
+                  coordIndex++;
+                }
+                geometryIndex++;
+              }
+              multiFeatureIndex++;
             }
-            nav(1);
             break;
-        }
-      }
-      function keyup(d3_event) {
-        switch (d3_event.keyCode) {
-          case 27:
-            cancel();
+          case "GeometryCollection":
+            for (j2 = 0; j2 < geometry.geometries.length; j2++)
+              if (coordEach(geometry.geometries[j2], callback, excludeWrapCoord) === false)
+                return false;
             break;
+          default:
+            throw new Error("Unknown Geometry Type");
         }
       }
-      function change(doAutoComplete) {
-        if (doAutoComplete === void 0)
-          doAutoComplete = true;
-        fetchComboData(value(), function(skipAutosuggest) {
-          _selected = null;
-          var val = input.property("value");
-          if (_suggestions.length) {
-            if (doAutoComplete && !skipAutosuggest && input.property("selectionEnd") === val.length) {
-              _selected = tryAutocomplete();
-            }
-            if (!_selected) {
-              _selected = val;
-            }
-          }
-          if (val.length) {
-            var combo = container.selectAll(".combobox");
-            if (combo.empty()) {
-              show();
-            }
-          } else {
-            hide();
-          }
-          render();
-        });
+    }
+  }
+
+  // node_modules/@turf/bbox/dist/esm/index.js
+  function bbox(geojson, options2 = {}) {
+    if (geojson.bbox != null && true !== options2.recompute) {
+      return geojson.bbox;
+    }
+    const result = [Infinity, Infinity, -Infinity, -Infinity];
+    coordEach(geojson, (coord2) => {
+      if (result[0] > coord2[0]) {
+        result[0] = coord2[0];
       }
-      function nav(dir) {
-        if (_suggestions.length) {
-          var index = -1;
-          for (var i3 = 0; i3 < _suggestions.length; i3++) {
-            if (_selected && _suggestions[i3].value === _selected) {
-              index = i3;
-              break;
-            }
-          }
-          index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
-          _selected = _suggestions[index].value;
-          utilGetSetValue(input, _selected);
-          dispatch14.call("update");
-        }
-        render();
-        ensureVisible();
+      if (result[1] > coord2[1]) {
+        result[1] = coord2[1];
       }
-      function ensureVisible() {
-        var combo = container.selectAll(".combobox");
-        if (combo.empty())
-          return;
-        var containerRect = container.node().getBoundingClientRect();
-        var comboRect = combo.node().getBoundingClientRect();
-        if (comboRect.bottom > containerRect.bottom) {
-          var node = attachTo ? attachTo.node() : input.node();
-          node.scrollIntoView({ behavior: "instant", block: "center" });
-          render();
-        }
-        var selected = combo.selectAll(".combobox-option.selected").node();
-        if (selected) {
-          selected.scrollIntoView({ behavior: "smooth", block: "nearest" });
+      if (result[2] < coord2[0]) {
+        result[2] = coord2[0];
+      }
+      if (result[3] < coord2[1]) {
+        result[3] = coord2[1];
+      }
+    });
+    return result;
+  }
+  var turf_bbox_default = bbox;
+
+  // modules/renderer/background.js
+  var import_which_polygon3 = __toESM(require_which_polygon());
+
+  // modules/renderer/tile_layer.js
+  function rendererTileLayer(context) {
+    var transformProp = utilPrefixCSSProperty("Transform");
+    var tiler8 = utilTiler();
+    var _tileSize = 256;
+    var _projection;
+    var _cache5 = {};
+    var _tileOrigin;
+    var _zoom;
+    var _source;
+    function tileSizeAtZoom(d2, z2) {
+      var EPSILON = 2e-3;
+      return _tileSize * Math.pow(2, z2 - d2[2]) / _tileSize + EPSILON;
+    }
+    function atZoom(t2, distance) {
+      var power = Math.pow(2, distance);
+      return [
+        Math.floor(t2[0] * power),
+        Math.floor(t2[1] * power),
+        t2[2] + distance
+      ];
+    }
+    function lookUp(d2) {
+      for (var up = -1; up > -d2[2]; up--) {
+        var tile = atZoom(d2, up);
+        if (_cache5[_source.url(tile)] !== false) {
+          return tile;
         }
       }
-      function value() {
-        var value2 = input.property("value");
-        var start2 = input.property("selectionStart");
-        var end = input.property("selectionEnd");
-        if (start2 && end) {
-          value2 = value2.substring(0, start2);
+    }
+    function uniqueBy(a2, n3) {
+      var o2 = [];
+      var seen = {};
+      for (var i3 = 0; i3 < a2.length; i3++) {
+        if (seen[a2[i3][n3]] === void 0) {
+          o2.push(a2[i3]);
+          seen[a2[i3][n3]] = true;
         }
-        return value2;
       }
-      function fetchComboData(v2, cb) {
-        _cancelFetch = false;
-        _fetcher.call(input, v2, function(results, skipAutosuggest) {
-          if (_cancelFetch)
-            return;
-          _suggestions = results;
-          results.forEach(function(d2) {
-            _fetched[d2.value] = d2;
-          });
-          if (cb) {
-            cb(skipAutosuggest);
-          }
-        });
+      return o2;
+    }
+    function addSource(d2) {
+      d2.push(_source.url(d2));
+      return d2;
+    }
+    function background(selection2) {
+      _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
+      var pixelOffset;
+      if (_source) {
+        pixelOffset = [
+          _source.offset()[0] * Math.pow(2, _zoom),
+          _source.offset()[1] * Math.pow(2, _zoom)
+        ];
+      } else {
+        pixelOffset = [0, 0];
       }
-      function tryAutocomplete() {
-        if (!_canAutocomplete)
-          return;
-        var val = _caseSensitive ? value() : value().toLowerCase();
-        if (!val)
-          return;
-        if (isFinite(val))
-          return;
-        const suggestionValues = [];
-        _suggestions.forEach((s2) => {
-          suggestionValues.push(s2.value);
-          if (s2.key && s2.key !== s2.value) {
-            suggestionValues.push(s2.key);
+      var translate = [
+        _projection.translate()[0] + pixelOffset[0],
+        _projection.translate()[1] + pixelOffset[1]
+      ];
+      tiler8.scale(_projection.scale() * 2 * Math.PI).translate(translate);
+      _tileOrigin = [
+        _projection.scale() * Math.PI - translate[0],
+        _projection.scale() * Math.PI - translate[1]
+      ];
+      render(selection2);
+    }
+    function render(selection2) {
+      if (!_source) return;
+      var requests = [];
+      var showDebug = context.getDebug("tile") && !_source.overlay;
+      if (_source.validZoom(_zoom)) {
+        tiler8.skipNullIsland(!!_source.overlay);
+        tiler8().forEach(function(d2) {
+          addSource(d2);
+          if (d2[3] === "") return;
+          if (typeof d2[3] !== "string") return;
+          requests.push(d2);
+          if (_cache5[d2[3]] === false && lookUp(d2)) {
+            requests.push(addSource(lookUp(d2)));
           }
         });
-        var bestIndex = -1;
-        for (var i3 = 0; i3 < suggestionValues.length; i3++) {
-          var suggestion = suggestionValues[i3];
-          var compare2 = _caseSensitive ? suggestion : suggestion.toLowerCase();
-          if (compare2 === val) {
-            bestIndex = i3;
-            break;
-          } else if (bestIndex === -1 && compare2.indexOf(val) === 0) {
-            bestIndex = i3;
-          }
-        }
-        if (bestIndex !== -1) {
-          var bestVal = suggestionValues[bestIndex];
-          input.property("value", bestVal);
-          input.node().setSelectionRange(val.length, bestVal.length);
-          dispatch14.call("update");
-          return bestVal;
-        }
-      }
-      function render() {
-        if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
-          hide();
-          return;
-        }
-        var shown = !container.selectAll(".combobox").empty();
-        if (!shown)
-          return;
-        var combo = container.selectAll(".combobox");
-        var options2 = combo.selectAll(".combobox-option").data(_suggestions, function(d2) {
-          return d2.value;
+        requests = uniqueBy(requests, 3).filter(function(r2) {
+          return _cache5[r2[3]] !== false;
         });
-        options2.exit().remove();
-        options2.enter().append("a").attr("class", function(d2) {
-          return "combobox-option " + (d2.klass || "");
-        }).attr("title", function(d2) {
-          return d2.title;
-        }).each(function(d2) {
-          if (d2.display) {
-            d2.display(select_default2(this));
-          } else {
-            select_default2(this).text(d2.value);
-          }
-        }).on("mouseenter", _mouseEnterHandler).on("mouseleave", _mouseLeaveHandler).merge(options2).classed("selected", function(d2) {
-          return d2.value === _selected || d2.key === _selected;
-        }).on("click.combo-option", accept).order();
-        var node = attachTo ? attachTo.node() : input.node();
-        var containerRect = container.node().getBoundingClientRect();
-        var rect = node.getBoundingClientRect();
-        combo.style("left", rect.left + 5 - containerRect.left + "px").style("width", rect.width - 10 + "px").style("top", rect.height + rect.top - containerRect.top + "px");
       }
-      function accept(d3_event, d2) {
-        _cancelFetch = true;
-        var thiz = input.node();
-        if (d2) {
-          utilGetSetValue(input, d2.value);
-          utilTriggerEvent(input, "change");
-        }
-        var val = utilGetSetValue(input);
-        thiz.setSelectionRange(val.length, val.length);
-        d2 = _fetched[val];
-        dispatch14.call("accept", thiz, d2, val);
-        hide();
+      function load(d3_event, d2) {
+        _cache5[d2[3]] = true;
+        select_default2(this).on("error", null).on("load", null).classed("tile-loaded", true);
+        render(selection2);
       }
-      function cancel() {
-        _cancelFetch = true;
-        var thiz = input.node();
-        var val = utilGetSetValue(input);
-        var start2 = input.property("selectionStart");
-        var end = input.property("selectionEnd");
-        val = val.slice(0, start2) + val.slice(end);
-        utilGetSetValue(input, val);
-        thiz.setSelectionRange(val.length, val.length);
-        dispatch14.call("cancel", thiz);
-        hide();
+      function error(d3_event, d2) {
+        _cache5[d2[3]] = false;
+        select_default2(this).on("error", null).on("load", null).remove();
+        render(selection2);
       }
+      function imageTransform(d2) {
+        var ts = _tileSize * Math.pow(2, _zoom - d2[2]);
+        var scale = tileSizeAtZoom(d2, _zoom);
+        return "translate(" + (d2[0] * ts - _tileOrigin[0]) + "px," + (d2[1] * ts - _tileOrigin[1]) + "px) scale(" + scale + "," + scale + ")";
+      }
+      function tileCenter(d2) {
+        var ts = _tileSize * Math.pow(2, _zoom - d2[2]);
+        return [
+          d2[0] * ts - _tileOrigin[0] + ts / 2,
+          d2[1] * ts - _tileOrigin[1] + ts / 2
+        ];
+      }
+      function debugTransform(d2) {
+        var coord2 = tileCenter(d2);
+        return "translate(" + coord2[0] + "px," + coord2[1] + "px)";
+      }
+      var dims = tiler8.size();
+      var mapCenter = [dims[0] / 2, dims[1] / 2];
+      var minDist = Math.max(dims[0], dims[1]);
+      var nearCenter;
+      requests.forEach(function(d2) {
+        var c2 = tileCenter(d2);
+        var dist = geoVecLength(c2, mapCenter);
+        if (dist < minDist) {
+          minDist = dist;
+          nearCenter = d2;
+        }
+      });
+      var image = selection2.selectAll("img").data(requests, function(d2) {
+        return d2[3];
+      });
+      image.exit().style(transformProp, imageTransform).classed("tile-removing", true).classed("tile-center", false).each(function() {
+        var tile = select_default2(this);
+        window.setTimeout(function() {
+          if (tile.classed("tile-removing")) {
+            tile.remove();
+          }
+        }, 300);
+      });
+      image.enter().append("img").attr("class", "tile").attr("alt", "").attr("draggable", "false").style("width", _tileSize + "px").style("height", _tileSize + "px").attr("src", function(d2) {
+        return d2[3];
+      }).on("error", error).on("load", load).merge(image).style(transformProp, imageTransform).classed("tile-debug", showDebug).classed("tile-removing", false).classed("tile-center", function(d2) {
+        return d2 === nearCenter;
+      });
+      var debug2 = selection2.selectAll(".tile-label-debug").data(showDebug ? requests : [], function(d2) {
+        return d2[3];
+      });
+      debug2.exit().remove();
+      if (showDebug) {
+        var debugEnter = debug2.enter().append("div").attr("class", "tile-label-debug");
+        debugEnter.append("div").attr("class", "tile-label-debug-coord");
+        debugEnter.append("div").attr("class", "tile-label-debug-vintage");
+        debug2 = debug2.merge(debugEnter);
+        debug2.style(transformProp, debugTransform);
+        debug2.selectAll(".tile-label-debug-coord").text(function(d2) {
+          return d2[2] + " / " + d2[0] + " / " + d2[1];
+        });
+        debug2.selectAll(".tile-label-debug-vintage").each(function(d2) {
+          var span = select_default2(this);
+          var center = context.projection.invert(tileCenter(d2));
+          _source.getMetadata(center, d2, function(err, result) {
+            if (result && result.vintage && result.vintage.range) {
+              span.text(result.vintage.range);
+            } else {
+              span.text("");
+              span.call(_t.append("info_panels.background.vintage"));
+              span.append("span").text(": ");
+              span.call(_t.append("info_panels.background.unknown"));
+            }
+          });
+        });
+      }
+    }
+    background.projection = function(val) {
+      if (!arguments.length) return _projection;
+      _projection = val;
+      return background;
     };
-    combobox.canAutocomplete = function(val) {
-      if (!arguments.length)
-        return _canAutocomplete;
-      _canAutocomplete = val;
-      return combobox;
-    };
-    combobox.caseSensitive = function(val) {
-      if (!arguments.length)
-        return _caseSensitive;
-      _caseSensitive = val;
-      return combobox;
-    };
-    combobox.data = function(val) {
-      if (!arguments.length)
-        return _data;
-      _data = val;
-      return combobox;
-    };
-    combobox.fetcher = function(val) {
-      if (!arguments.length)
-        return _fetcher;
-      _fetcher = val;
-      return combobox;
-    };
-    combobox.minItems = function(val) {
-      if (!arguments.length)
-        return _minItems;
-      _minItems = val;
-      return combobox;
-    };
-    combobox.itemsMouseEnter = function(val) {
-      if (!arguments.length)
-        return _mouseEnterHandler;
-      _mouseEnterHandler = val;
-      return combobox;
+    background.dimensions = function(val) {
+      if (!arguments.length) return tiler8.size();
+      tiler8.size(val);
+      return background;
     };
-    combobox.itemsMouseLeave = function(val) {
-      if (!arguments.length)
-        return _mouseLeaveHandler;
-      _mouseLeaveHandler = val;
-      return combobox;
+    background.source = function(val) {
+      if (!arguments.length) return _source;
+      _source = val;
+      _tileSize = _source.tileSize;
+      _cache5 = {};
+      tiler8.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
+      return background;
     };
-    return utilRebind(combobox, dispatch14, "on");
+    return background;
   }
-  uiCombobox.off = function(input, context) {
-    input.on("focus.combo-input", null).on("blur.combo-input", null).on("keydown.combo-input", null).on("keyup.combo-input", null).on("input.combo-input", null).on("mousedown.combo-input", null).on("mouseup.combo-input", null);
-    context.container().on("scroll.combo-scroll", null);
-  };
 
-  // modules/ui/disclosure.js
-  function uiDisclosure(context, key, expandedDefault) {
-    var dispatch14 = dispatch_default("toggled");
-    var _expanded;
-    var _label = utilFunctor("");
-    var _updatePreference = true;
-    var _content = function() {
-    };
-    var disclosure = function(selection2) {
-      if (_expanded === void 0 || _expanded === null) {
-        var preference = corePreferences("disclosure." + key + ".expanded");
-        _expanded = preference === null ? !!expandedDefault : preference === "true";
+  // modules/renderer/background.js
+  var _imageryIndex = null;
+  function rendererBackground(context) {
+    const dispatch14 = dispatch_default("change");
+    const baseLayer = rendererTileLayer(context).projection(context.projection);
+    let _checkedBlocklists = [];
+    let _isValid = true;
+    let _overlayLayers = [];
+    let _brightness = 1;
+    let _contrast = 1;
+    let _saturation = 1;
+    let _sharpness = 1;
+    function ensureImageryIndex() {
+      return _mainFileFetcher.get("imagery").then((sources) => {
+        if (_imageryIndex) return _imageryIndex;
+        _imageryIndex = {
+          imagery: sources,
+          features: {}
+        };
+        const features = sources.map((source) => {
+          if (!source.polygon) return null;
+          const rings = source.polygon.map((ring) => [ring]);
+          const feature3 = {
+            type: "Feature",
+            properties: { id: source.id },
+            geometry: { type: "MultiPolygon", coordinates: rings }
+          };
+          _imageryIndex.features[source.id] = feature3;
+          return feature3;
+        }).filter(Boolean);
+        _imageryIndex.query = (0, import_which_polygon3.default)({ type: "FeatureCollection", features });
+        _imageryIndex.backgrounds = sources.map((source) => {
+          if (source.type === "bing") {
+            return rendererBackgroundSource.Bing(source, dispatch14);
+          } else if (/^EsriWorldImagery/.test(source.id)) {
+            return rendererBackgroundSource.Esri(source);
+          } else {
+            return rendererBackgroundSource(source);
+          }
+        });
+        _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None());
+        let template = corePreferences("background-custom-template") || "";
+        const custom = rendererBackgroundSource.Custom(template);
+        _imageryIndex.backgrounds.unshift(custom);
+        return _imageryIndex;
+      });
+    }
+    function background(selection2) {
+      const currSource = baseLayer.source();
+      if (context.map().zoom() > 18) {
+        if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
+          const center = context.map().center();
+          currSource.fetchTilemap(center);
+        }
       }
-      var hideToggle = selection2.selectAll(".hide-toggle-" + key).data([0]);
-      var hideToggleEnter = hideToggle.enter().append("h3").append("a").attr("role", "button").attr("href", "#").attr("class", "hide-toggle hide-toggle-" + key).call(svgIcon("", "pre-text", "hide-toggle-icon"));
-      hideToggleEnter.append("span").attr("class", "hide-toggle-text");
-      hideToggle = hideToggleEnter.merge(hideToggle);
-      hideToggle.on("click", toggle).attr("title", _t("icons.".concat(_expanded ? "collapse" : "expand"))).attr("aria-expanded", _expanded).classed("expanded", _expanded);
-      const label = _label();
-      const labelSelection = hideToggle.selectAll(".hide-toggle-text");
-      if (typeof label !== "function") {
-        labelSelection.text(_label());
+      const sources = background.sources(context.map().extent());
+      const wasValid = _isValid;
+      _isValid = !!sources.filter((d2) => d2 === currSource).length;
+      if (wasValid !== _isValid) {
+        background.updateImagery();
+      }
+      let baseFilter = "";
+      if (_brightness !== 1) {
+        baseFilter += " brightness(".concat(_brightness, ")");
+      }
+      if (_contrast !== 1) {
+        baseFilter += " contrast(".concat(_contrast, ")");
+      }
+      if (_saturation !== 1) {
+        baseFilter += " saturate(".concat(_saturation, ")");
+      }
+      if (_sharpness < 1) {
+        const blur = number_default(0.5, 5)(1 - _sharpness);
+        baseFilter += " blur(".concat(blur, "px)");
+      }
+      let base = selection2.selectAll(".layer-background").data([0]);
+      base = base.enter().insert("div", ".layer-data").attr("class", "layer layer-background").merge(base);
+      base.style("filter", baseFilter || null);
+      let imagery = base.selectAll(".layer-imagery").data([0]);
+      imagery.enter().append("div").attr("class", "layer layer-imagery").merge(imagery).call(baseLayer);
+      let maskFilter = "";
+      let mixBlendMode = "";
+      if (_sharpness > 1) {
+        mixBlendMode = "overlay";
+        maskFilter = "saturate(0) blur(3px) invert(1)";
+        let contrast = _sharpness - 1;
+        maskFilter += " contrast(".concat(contrast, ")");
+        let brightness = number_default(1, 0.85)(_sharpness - 1);
+        maskFilter += " brightness(".concat(brightness, ")");
+      }
+      let mask = base.selectAll(".layer-unsharp-mask").data(_sharpness > 1 ? [0] : []);
+      mask.exit().remove();
+      mask.enter().append("div").attr("class", "layer layer-mask layer-unsharp-mask").merge(mask).call(baseLayer).style("filter", maskFilter || null).style("mix-blend-mode", mixBlendMode || null);
+      let overlays = selection2.selectAll(".layer-overlay").data(_overlayLayers, (d2) => d2.source().name());
+      overlays.exit().remove();
+      overlays.enter().insert("div", ".layer-data").attr("class", "layer layer-overlay").merge(overlays).each((layer, i3, nodes) => select_default2(nodes[i3]).call(layer));
+    }
+    background.updateImagery = function() {
+      let currSource = baseLayer.source();
+      if (context.inIntro() || !currSource) return;
+      let o2 = _overlayLayers.filter((d2) => !d2.source().isLocatorOverlay() && !d2.source().isHidden()).map((d2) => d2.source().id).join(",");
+      const meters = geoOffsetToMeters(currSource.offset());
+      const EPSILON = 0.01;
+      const x2 = +meters[0].toFixed(2);
+      const y2 = +meters[1].toFixed(2);
+      let hash = utilStringQs(window.location.hash);
+      let id2 = currSource.id;
+      if (id2 === "custom") {
+        id2 = "custom:".concat(currSource.template());
+      }
+      if (id2) {
+        hash.background = id2;
       } else {
-        labelSelection.text("").call(label);
+        delete hash.background;
       }
-      hideToggle.selectAll(".hide-toggle-icon").attr(
-        "xlink:href",
-        _expanded ? "#iD-icon-down" : _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward"
-      );
-      var wrap2 = selection2.selectAll(".disclosure-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "disclosure-wrap disclosure-wrap-" + key).merge(wrap2).classed("hide", !_expanded);
-      if (_expanded) {
-        wrap2.call(_content);
+      if (o2) {
+        hash.overlays = o2;
+      } else {
+        delete hash.overlays;
       }
-      function toggle(d3_event) {
-        d3_event.preventDefault();
-        _expanded = !_expanded;
-        if (_updatePreference) {
-          corePreferences("disclosure." + key + ".expanded", _expanded);
-        }
-        hideToggle.classed("expanded", _expanded).attr("aria-expanded", _expanded).attr("title", _t("icons.".concat(_expanded ? "collapse" : "expand")));
-        hideToggle.selectAll(".hide-toggle-icon").attr(
-          "xlink:href",
-          _expanded ? "#iD-icon-down" : _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward"
-        );
-        wrap2.call(uiToggle(_expanded));
-        if (_expanded) {
-          wrap2.call(_content);
+      if (Math.abs(x2) > EPSILON || Math.abs(y2) > EPSILON) {
+        hash.offset = "".concat(x2, ",").concat(y2);
+      } else {
+        delete hash.offset;
+      }
+      if (!window.mocha) {
+        window.location.replace("#" + utilQsString(hash, true));
+      }
+      let imageryUsed = [];
+      let photoOverlaysUsed = [];
+      const currUsed = currSource.imageryUsed();
+      if (currUsed && _isValid) {
+        imageryUsed.push(currUsed);
+      }
+      _overlayLayers.filter((d2) => !d2.source().isLocatorOverlay() && !d2.source().isHidden()).forEach((d2) => imageryUsed.push(d2.source().imageryUsed()));
+      const dataLayer = context.layers().layer("data");
+      if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
+        imageryUsed.push(dataLayer.getSrc());
+      }
+      const photoOverlayLayers = {
+        streetside: "Bing Streetside",
+        mapillary: "Mapillary Images",
+        "mapillary-map-features": "Mapillary Map Features",
+        "mapillary-signs": "Mapillary Signs",
+        kartaview: "KartaView Images",
+        vegbilder: "Norwegian Road Administration Images",
+        mapilio: "Mapilio Images",
+        panoramax: "Panoramax Images"
+      };
+      for (let layerID in photoOverlayLayers) {
+        const layer = context.layers().layer(layerID);
+        if (layer && layer.enabled()) {
+          photoOverlaysUsed.push(layerID);
+          imageryUsed.push(photoOverlayLayers[layerID]);
         }
-        dispatch14.call("toggled", this, _expanded);
       }
+      context.history().imageryUsed(imageryUsed);
+      context.history().photoOverlaysUsed(photoOverlaysUsed);
     };
-    disclosure.label = function(val) {
-      if (!arguments.length)
-        return _label;
-      _label = utilFunctor(val);
-      return disclosure;
-    };
-    disclosure.expanded = function(val) {
-      if (!arguments.length)
-        return _expanded;
-      _expanded = val;
-      return disclosure;
+    background.sources = (extent, zoom, includeCurrent) => {
+      if (!_imageryIndex) return [];
+      let visible = {};
+      (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach((d2) => visible[d2.id] = true);
+      const currSource = baseLayer.source();
+      const osm = context.connection();
+      const blocklists = osm && osm.imageryBlocklists() || [];
+      const blocklistChanged = blocklists.length !== _checkedBlocklists.length || blocklists.some((regex, index) => String(regex) !== _checkedBlocklists[index]);
+      if (blocklistChanged) {
+        _imageryIndex.backgrounds.forEach((source) => {
+          source.isBlocked = blocklists.some((regex) => regex.test(source.template()));
+        });
+        _checkedBlocklists = blocklists.map((regex) => String(regex));
+      }
+      return _imageryIndex.backgrounds.filter((source) => {
+        if (includeCurrent && currSource === source) return true;
+        if (source.isBlocked) return false;
+        if (!source.polygon) return true;
+        if (zoom && zoom < 6) return false;
+        return visible[source.id];
+      });
     };
-    disclosure.updatePreference = function(val) {
-      if (!arguments.length)
-        return _updatePreference;
-      _updatePreference = val;
-      return disclosure;
+    background.dimensions = (val) => {
+      if (!val) return;
+      baseLayer.dimensions(val);
+      _overlayLayers.forEach((layer) => layer.dimensions(val));
     };
-    disclosure.content = function(val) {
-      if (!arguments.length)
-        return _content;
-      _content = val;
-      return disclosure;
+    background.baseLayerSource = function(d2) {
+      if (!arguments.length) return baseLayer.source();
+      const osm = context.connection();
+      if (!osm) return background;
+      const blocklists = osm.imageryBlocklists();
+      const template = d2.template();
+      let fail = false;
+      let tested = 0;
+      let regex;
+      for (let i3 = 0; i3 < blocklists.length; i3++) {
+        regex = blocklists[i3];
+        fail = regex.test(template);
+        tested++;
+        if (fail) break;
+      }
+      if (!tested) {
+        regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
+        fail = regex.test(template);
+      }
+      baseLayer.source(!fail ? d2 : background.findSource("none"));
+      dispatch14.call("change");
+      background.updateImagery();
+      return background;
     };
-    return utilRebind(disclosure, dispatch14, "on");
-  }
-
-  // modules/ui/section.js
-  function uiSection(id2, context) {
-    var _classes = utilFunctor("");
-    var _shouldDisplay;
-    var _content;
-    var _disclosure;
-    var _label;
-    var _expandedByDefault = utilFunctor(true);
-    var _disclosureContent;
-    var _disclosureExpanded;
-    var _containerSelection = select_default2(null);
-    var section = {
-      id: id2
+    background.findSource = (id2) => {
+      if (!id2 || !_imageryIndex) return null;
+      return _imageryIndex.backgrounds.find((d2) => d2.id && d2.id === id2);
     };
-    section.classes = function(val) {
-      if (!arguments.length)
-        return _classes;
-      _classes = utilFunctor(val);
-      return section;
+    background.bing = () => {
+      background.baseLayerSource(background.findSource("Bing"));
     };
-    section.label = function(val) {
-      if (!arguments.length)
-        return _label;
-      _label = utilFunctor(val);
-      return section;
+    background.showsLayer = (d2) => {
+      const currSource = baseLayer.source();
+      if (!d2 || !currSource) return false;
+      return d2.id === currSource.id || _overlayLayers.some((layer) => d2.id === layer.source().id);
     };
-    section.expandedByDefault = function(val) {
-      if (!arguments.length)
-        return _expandedByDefault;
-      _expandedByDefault = utilFunctor(val);
-      return section;
+    background.overlayLayerSources = () => {
+      return _overlayLayers.map((layer) => layer.source());
     };
-    section.shouldDisplay = function(val) {
-      if (!arguments.length)
-        return _shouldDisplay;
-      _shouldDisplay = utilFunctor(val);
-      return section;
+    background.toggleOverlayLayer = (d2) => {
+      let layer;
+      for (let i3 = 0; i3 < _overlayLayers.length; i3++) {
+        layer = _overlayLayers[i3];
+        if (layer.source() === d2) {
+          _overlayLayers.splice(i3, 1);
+          dispatch14.call("change");
+          background.updateImagery();
+          return;
+        }
+      }
+      layer = rendererTileLayer(context).source(d2).projection(context.projection).dimensions(
+        baseLayer.dimensions()
+      );
+      _overlayLayers.push(layer);
+      dispatch14.call("change");
+      background.updateImagery();
     };
-    section.content = function(val) {
-      if (!arguments.length)
-        return _content;
-      _content = val;
-      return section;
+    background.nudge = (d2, zoom) => {
+      const currSource = baseLayer.source();
+      if (currSource) {
+        currSource.nudge(d2, zoom);
+        dispatch14.call("change");
+        background.updateImagery();
+      }
+      return background;
     };
-    section.disclosureContent = function(val) {
-      if (!arguments.length)
-        return _disclosureContent;
-      _disclosureContent = val;
-      return section;
+    background.offset = function(d2) {
+      const currSource = baseLayer.source();
+      if (!arguments.length) {
+        return currSource && currSource.offset() || [0, 0];
+      }
+      if (currSource) {
+        currSource.offset(d2);
+        dispatch14.call("change");
+        background.updateImagery();
+      }
+      return background;
     };
-    section.disclosureExpanded = function(val) {
-      if (!arguments.length)
-        return _disclosureExpanded;
-      _disclosureExpanded = val;
-      return section;
+    background.brightness = function(d2) {
+      if (!arguments.length) return _brightness;
+      _brightness = d2;
+      if (context.mode()) dispatch14.call("change");
+      return background;
     };
-    section.render = function(selection2) {
-      _containerSelection = selection2.selectAll(".section-" + id2).data([0]);
-      var sectionEnter = _containerSelection.enter().append("div").attr("class", "section section-" + id2 + " " + (_classes && _classes() || ""));
-      _containerSelection = sectionEnter.merge(_containerSelection);
-      _containerSelection.call(renderContent);
+    background.contrast = function(d2) {
+      if (!arguments.length) return _contrast;
+      _contrast = d2;
+      if (context.mode()) dispatch14.call("change");
+      return background;
     };
-    section.reRender = function() {
-      _containerSelection.call(renderContent);
+    background.saturation = function(d2) {
+      if (!arguments.length) return _saturation;
+      _saturation = d2;
+      if (context.mode()) dispatch14.call("change");
+      return background;
     };
-    section.selection = function() {
-      return _containerSelection;
+    background.sharpness = function(d2) {
+      if (!arguments.length) return _sharpness;
+      _sharpness = d2;
+      if (context.mode()) dispatch14.call("change");
+      return background;
     };
-    section.disclosure = function() {
-      return _disclosure;
+    let _loadPromise;
+    background.ensureLoaded = () => {
+      if (_loadPromise) return _loadPromise;
+      return _loadPromise = ensureImageryIndex();
     };
-    function renderContent(selection2) {
-      if (_shouldDisplay) {
-        var shouldDisplay = _shouldDisplay();
-        selection2.classed("hide", !shouldDisplay);
-        if (!shouldDisplay) {
-          selection2.html("");
-          return;
-        }
-      }
-      if (_disclosureContent) {
-        if (!_disclosure) {
-          _disclosure = uiDisclosure(context, id2.replace(/-/g, "_"), _expandedByDefault()).label(_label || "").content(_disclosureContent);
-        }
-        if (_disclosureExpanded !== void 0) {
-          _disclosure.expanded(_disclosureExpanded);
-          _disclosureExpanded = void 0;
-        }
-        selection2.call(_disclosure);
-        return;
-      }
-      if (_content) {
-        selection2.call(_content);
-      }
-    }
-    return section;
+    background.init = () => {
+      const loadPromise = background.ensureLoaded();
+      const hash = utilStringQs(window.location.hash);
+      const requestedBackground = hash.background || hash.layer;
+      const lastUsedBackground = corePreferences("background-last-used");
+      return loadPromise.then((imageryIndex) => {
+        const extent = context.map().extent();
+        const validBackgrounds = background.sources(extent).filter((d2) => d2.id !== "none" && d2.id !== "custom");
+        const first = validBackgrounds.length && validBackgrounds[0];
+        const isLastUsedValid = !!validBackgrounds.find((d2) => d2.id && d2.id === lastUsedBackground);
+        let best;
+        if (!requestedBackground && extent) {
+          const viewArea = extent.area();
+          best = validBackgrounds.find((s2) => {
+            if (!s2.best() || s2.overlay) return false;
+            let bbox2 = turf_bbox_default(turf_bbox_clip_default(
+              { type: "MultiPolygon", coordinates: [s2.polygon || [extent.polygon()]] },
+              extent.rectangle()
+            ));
+            let area = geoExtent(bbox2.slice(0, 2), bbox2.slice(2, 4)).area();
+            return area / viewArea > 0.5;
+          });
+        }
+        if (requestedBackground && requestedBackground.indexOf("custom:") === 0) {
+          const template = requestedBackground.replace(/^custom:/, "");
+          const custom = background.findSource("custom");
+          background.baseLayerSource(custom.template(template));
+          corePreferences("background-custom-template", template);
+        } else {
+          background.baseLayerSource(
+            background.findSource(requestedBackground) || best || isLastUsedValid && background.findSource(lastUsedBackground) || background.findSource("Bing") || first || background.findSource("none")
+          );
+        }
+        const locator = imageryIndex.backgrounds.find((d2) => d2.overlay && d2.default);
+        if (locator) {
+          background.toggleOverlayLayer(locator);
+        }
+        const overlays = (hash.overlays || "").split(",");
+        overlays.forEach((overlay) => {
+          overlay = background.findSource(overlay);
+          if (overlay) {
+            background.toggleOverlayLayer(overlay);
+          }
+        });
+        if (hash.gpx) {
+          const gpx2 = context.layers().layer("data");
+          if (gpx2) {
+            gpx2.url(hash.gpx, ".gpx");
+          }
+        }
+        if (hash.offset) {
+          const offset = hash.offset.replace(/;/g, ",").split(",").map((n3) => !isNaN(n3) && n3);
+          if (offset.length === 2) {
+            background.offset(geoMetersToOffset(offset));
+          }
+        }
+      }).catch((err) => {
+        console.error(err);
+      });
+    };
+    return utilRebind(background, dispatch14, "on");
   }
 
-  // modules/ui/tag_reference.js
-  function uiTagReference(what) {
-    var wikibase = what.qid ? services.wikidata : services.osmWikibase;
-    var tagReference = {};
-    var _button = select_default2(null);
-    var _body = select_default2(null);
-    var _loaded;
-    var _showing;
-    function load() {
-      if (!wikibase)
-        return;
-      _button.classed("tag-reference-loading", true);
-      wikibase.getDocs(what, gotDocs);
+  // modules/renderer/features.js
+  function rendererFeatures(context) {
+    var dispatch14 = dispatch_default("change", "redraw");
+    var features = utilRebind({}, dispatch14, "on");
+    var _deferred2 = /* @__PURE__ */ new Set();
+    var traffic_roads = {
+      "motorway": true,
+      "motorway_link": true,
+      "trunk": true,
+      "trunk_link": true,
+      "primary": true,
+      "primary_link": true,
+      "secondary": true,
+      "secondary_link": true,
+      "tertiary": true,
+      "tertiary_link": true,
+      "residential": true,
+      "unclassified": true,
+      "living_street": true,
+      "busway": true
+    };
+    var service_roads = {
+      "service": true,
+      "road": true,
+      "track": true
+    };
+    var paths = {
+      "path": true,
+      "footway": true,
+      "cycleway": true,
+      "bridleway": true,
+      "steps": true,
+      "ladder": true,
+      "pedestrian": true
+    };
+    var _cullFactor = 1;
+    var _cache5 = {};
+    var _rules = {};
+    var _stats = {};
+    var _keys = [];
+    var _hidden = [];
+    var _forceVisible = {};
+    function update() {
+      if (!window.mocha) {
+        var hash = utilStringQs(window.location.hash);
+        var disabled = features.disabled();
+        if (disabled.length) {
+          hash.disable_features = disabled.join(",");
+        } else {
+          delete hash.disable_features;
+        }
+        window.location.replace("#" + utilQsString(hash, true));
+        corePreferences("disabled-features", disabled.join(","));
+      }
+      _hidden = features.hidden();
+      dispatch14.call("change");
+      dispatch14.call("redraw");
     }
-    function gotDocs(err, docs) {
-      _body.html("");
-      if (!docs || !docs.title) {
-        _body.append("p").attr("class", "tag-reference-description").call(_t.append("inspector.no_documentation_key"));
-        done();
-        return;
+    function defineRule(k2, filter2, max3) {
+      var isEnabled = true;
+      _keys.push(k2);
+      _rules[k2] = {
+        filter: filter2,
+        enabled: isEnabled,
+        // whether the user wants it enabled..
+        count: 0,
+        currentMax: max3 || Infinity,
+        defaultMax: max3 || Infinity,
+        enable: function() {
+          this.enabled = true;
+          this.currentMax = this.defaultMax;
+        },
+        disable: function() {
+          this.enabled = false;
+          this.currentMax = 0;
+        },
+        hidden: function() {
+          return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
+        },
+        autoHidden: function() {
+          return this.hidden() && this.currentMax > 0;
+        }
+      };
+    }
+    defineRule("points", function isPoint(tags, geometry) {
+      return geometry === "point";
+    }, 200);
+    defineRule("traffic_roads", function isTrafficRoad(tags) {
+      return traffic_roads[tags.highway];
+    });
+    defineRule("service_roads", function isServiceRoad(tags) {
+      return service_roads[tags.highway];
+    });
+    defineRule("paths", function isPath(tags) {
+      return paths[tags.highway];
+    });
+    defineRule("buildings", function isBuilding(tags) {
+      return !!tags.building && tags.building !== "no" || tags.parking === "multi-storey" || tags.parking === "sheds" || tags.parking === "carports" || tags.parking === "garage_boxes";
+    }, 250);
+    defineRule("building_parts", function isBuildingPart(tags) {
+      return !!tags["building:part"];
+    });
+    defineRule("indoor", function isIndoor(tags) {
+      return !!tags.indoor;
+    });
+    defineRule("landuse", function isLanduse(tags, geometry) {
+      return geometry === "area" && (!!tags.landuse || !!tags.natural || !!tags.leisure || !!tags.amenity) && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
+    });
+    defineRule("boundaries", function isBoundary(tags, geometry) {
+      return (geometry === "line" && !!tags.boundary || geometry === "relation" && tags.type === "boundary") && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway] || tags.waterway || tags.railway || tags.landuse || tags.natural || tags.building || tags.power);
+    });
+    defineRule("water", function isWater(tags) {
+      return !!tags.waterway || tags.natural === "water" || tags.natural === "coastline" || tags.natural === "bay" || tags.landuse === "pond" || tags.landuse === "basin" || tags.landuse === "reservoir" || tags.landuse === "salt_pond";
+    });
+    defineRule("rail", function isRail(tags) {
+      return (!!tags.railway || tags.landuse === "railway") && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
+    });
+    defineRule("pistes", function isPiste(tags) {
+      return tags["piste:type"];
+    });
+    defineRule("aerialways", function isAerialways(tags) {
+      return !!(tags == null ? void 0 : tags.aerialway) && tags.aerialway !== "yes" && tags.aerialway !== "station";
+    });
+    defineRule("power", function isPower(tags) {
+      return !!tags.power;
+    });
+    defineRule("past_future", function isPastFuture(tags) {
+      if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
+        return false;
       }
-      if (docs.imageURL) {
-        _body.append("img").attr("class", "tag-reference-wiki-image").attr("alt", docs.description).attr("src", docs.imageURL).on("load", function() {
-          done();
-        }).on("error", function() {
-          select_default2(this).remove();
-          done();
+      const keys2 = Object.keys(tags);
+      for (let i3 = 0; i3 < keys2.length; i3++) {
+        const key = keys2[i3];
+        const s2 = key.split(":")[0];
+        if (osmLifecyclePrefixes[s2] || osmLifecyclePrefixes[tags[key]]) return true;
+      }
+      return false;
+    });
+    defineRule("others", function isOther(tags, geometry) {
+      return geometry === "line" || geometry === "area";
+    });
+    features.features = function() {
+      return _rules;
+    };
+    features.keys = function() {
+      return _keys;
+    };
+    features.enabled = function(k2) {
+      if (!arguments.length) {
+        return _keys.filter(function(k3) {
+          return _rules[k3].enabled;
         });
-      } else {
-        done();
       }
-      var tagReferenceDescription = _body.append("p").attr("class", "tag-reference-description").append("span");
-      if (docs.description) {
-        tagReferenceDescription = tagReferenceDescription.attr("class", "localized-text").attr("lang", docs.descriptionLocaleCode || "und").text(docs.description);
-      } else {
-        tagReferenceDescription = tagReferenceDescription.call(_t.append("inspector.no_documentation_key"));
+      return _rules[k2] && _rules[k2].enabled;
+    };
+    features.disabled = function(k2) {
+      if (!arguments.length) {
+        return _keys.filter(function(k3) {
+          return !_rules[k3].enabled;
+        });
       }
-      tagReferenceDescription.append("a").attr("class", "tag-reference-edit").attr("target", "_blank").attr("title", _t("inspector.edit_reference")).attr("href", docs.editURL).call(svgIcon("#iD-icon-edit", "inline"));
-      if (docs.wiki) {
-        _body.append("a").attr("class", "tag-reference-link").attr("target", "_blank").attr("href", docs.wiki.url).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append(docs.wiki.text));
+      return _rules[k2] && !_rules[k2].enabled;
+    };
+    features.hidden = function(k2) {
+      var _a3;
+      if (!arguments.length) {
+        return _keys.filter(function(k3) {
+          return _rules[k3].hidden();
+        });
       }
-      if (what.key === "comment") {
-        _body.append("a").attr("class", "tag-reference-comment-link").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", _t("commit.about_changeset_comments_link")).append("span").call(_t.append("commit.about_changeset_comments"));
+      return (_a3 = _rules[k2]) == null ? void 0 : _a3.hidden();
+    };
+    features.autoHidden = function(k2) {
+      if (!arguments.length) {
+        return _keys.filter(function(k3) {
+          return _rules[k3].autoHidden();
+        });
       }
-    }
-    function done() {
-      _loaded = true;
-      _button.classed("tag-reference-loading", false);
-      _body.classed("expanded", true).transition().duration(200).style("max-height", "200px").style("opacity", "1");
-      _showing = true;
-      _button.selectAll("svg.icon use").each(function() {
-        var iconUse = select_default2(this);
-        if (iconUse.attr("href") === "#iD-icon-info") {
-          iconUse.attr("href", "#iD-icon-info-filled");
-        }
-      });
-    }
-    function hide() {
-      _body.transition().duration(200).style("max-height", "0px").style("opacity", "0").on("end", function() {
-        _body.classed("expanded", false);
-      });
-      _showing = false;
-      _button.selectAll("svg.icon use").each(function() {
-        var iconUse = select_default2(this);
-        if (iconUse.attr("href") === "#iD-icon-info-filled") {
-          iconUse.attr("href", "#iD-icon-info");
-        }
-      });
-    }
-    tagReference.button = function(selection2, klass, iconName) {
-      _button = selection2.selectAll(".tag-reference-button").data([0]);
-      _button = _button.enter().append("button").attr("class", "tag-reference-button " + (klass || "")).attr("title", _t("icons.information")).call(svgIcon("#iD-icon-" + (iconName || "inspect"))).merge(_button);
-      _button.on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        this.blur();
-        if (_showing) {
-          hide();
-        } else if (_loaded) {
-          done();
-        } else {
-          load();
+      return _rules[k2] && _rules[k2].autoHidden();
+    };
+    features.enable = function(k2) {
+      if (_rules[k2] && !_rules[k2].enabled) {
+        _rules[k2].enable();
+        update();
+      }
+    };
+    features.enableAll = function() {
+      var didEnable = false;
+      for (var k2 in _rules) {
+        if (!_rules[k2].enabled) {
+          didEnable = true;
+          _rules[k2].enable();
         }
-      });
+      }
+      if (didEnable) update();
     };
-    tagReference.body = function(selection2) {
-      var itemID = what.qid || what.key + "-" + (what.value || "");
-      _body = selection2.selectAll(".tag-reference-body").data([itemID], function(d2) {
-        return d2;
-      });
-      _body.exit().remove();
-      _body = _body.enter().append("div").attr("class", "tag-reference-body").style("max-height", "0").style("opacity", "0").merge(_body);
-      if (_showing === false) {
-        hide();
+    features.disable = function(k2) {
+      if (_rules[k2] && _rules[k2].enabled) {
+        _rules[k2].disable();
+        update();
       }
     };
-    tagReference.showing = function(val) {
-      if (!arguments.length)
-        return _showing;
-      _showing = val;
-      return tagReference;
+    features.disableAll = function() {
+      var didDisable = false;
+      for (var k2 in _rules) {
+        if (_rules[k2].enabled) {
+          didDisable = true;
+          _rules[k2].disable();
+        }
+      }
+      if (didDisable) update();
     };
-    return tagReference;
-  }
-
-  // modules/ui/field_help.js
-  function uiFieldHelp(context, fieldName) {
-    var fieldHelp = {};
-    var _inspector = select_default2(null);
-    var _wrap = select_default2(null);
-    var _body = select_default2(null);
-    var fieldHelpKeys = {
-      restrictions: [
-        ["about", [
-          "about",
-          "from_via_to",
-          "maxdist",
-          "maxvia"
-        ]],
-        ["inspecting", [
-          "about",
-          "from_shadow",
-          "allow_shadow",
-          "restrict_shadow",
-          "only_shadow",
-          "restricted",
-          "only"
-        ]],
-        ["modifying", [
-          "about",
-          "indicators",
-          "allow_turn",
-          "restrict_turn",
-          "only_turn"
-        ]],
-        ["tips", [
-          "simple",
-          "simple_example",
-          "indirect",
-          "indirect_example",
-          "indirect_noedit"
-        ]]
-      ]
+    features.toggle = function(k2) {
+      if (_rules[k2]) {
+        (function(f2) {
+          return f2.enabled ? f2.disable() : f2.enable();
+        })(_rules[k2]);
+        update();
+      }
     };
-    var fieldHelpHeadings = {};
-    var replacements = {
-      distField: { html: _t.html("restriction.controls.distance") },
-      viaField: { html: _t.html("restriction.controls.via") },
-      fromShadow: { html: icon("#iD-turn-shadow", "inline shadow from") },
-      allowShadow: { html: icon("#iD-turn-shadow", "inline shadow allow") },
-      restrictShadow: { html: icon("#iD-turn-shadow", "inline shadow restrict") },
-      onlyShadow: { html: icon("#iD-turn-shadow", "inline shadow only") },
-      allowTurn: { html: icon("#iD-turn-yes", "inline turn") },
-      restrictTurn: { html: icon("#iD-turn-no", "inline turn") },
-      onlyTurn: { html: icon("#iD-turn-only", "inline turn") }
+    features.resetStats = function() {
+      for (var i3 = 0; i3 < _keys.length; i3++) {
+        _rules[_keys[i3]].count = 0;
+      }
+      dispatch14.call("change");
     };
-    var docs = fieldHelpKeys[fieldName].map(function(key) {
-      var helpkey = "help.field." + fieldName + "." + key[0];
-      var text = key[1].reduce(function(all, part) {
-        var subkey = helpkey + "." + part;
-        var depth = fieldHelpHeadings[subkey];
-        var hhh = depth ? Array(depth + 1).join("#") + " " : "";
-        return all + hhh + _t.html(subkey, replacements) + "\n\n";
-      }, "");
-      return {
-        key: helpkey,
-        title: _t.html(helpkey + ".title"),
-        html: marked(text.trim())
-      };
-    });
-    function show() {
-      updatePosition();
-      _body.classed("hide", false).style("opacity", "0").transition().duration(200).style("opacity", "1");
-    }
-    function hide() {
-      _body.classed("hide", true).transition().duration(200).style("opacity", "0").on("end", function() {
-        _body.classed("hide", true);
-      });
-    }
-    function clickHelp(index) {
-      var d2 = docs[index];
-      var tkeys = fieldHelpKeys[fieldName][index][1];
-      _body.selectAll(".field-help-nav-item").classed("active", function(d4, i3) {
-        return i3 === index;
-      });
-      var content = _body.selectAll(".field-help-content").html(d2.html);
-      content.selectAll("p").attr("class", function(d4, i3) {
-        return tkeys[i3];
-      });
-      if (d2.key === "help.field.restrictions.inspecting") {
-        content.insert("img", "p.from_shadow").attr("class", "field-help-image cf").attr("src", context.imagePath("tr_inspect.gif"));
-      } else if (d2.key === "help.field.restrictions.modifying") {
-        content.insert("img", "p.allow_turn").attr("class", "field-help-image cf").attr("src", context.imagePath("tr_modify.gif"));
+    features.gatherStats = function(d2, resolver, dimensions) {
+      var needsRedraw = false;
+      var types = utilArrayGroupBy(d2, "type");
+      var entities = [].concat(types.relation || [], types.way || [], types.node || []);
+      var currHidden, geometry, matches, i3, j2;
+      for (i3 = 0; i3 < _keys.length; i3++) {
+        _rules[_keys[i3]].count = 0;
       }
-    }
-    fieldHelp.button = function(selection2) {
-      if (_body.empty())
-        return;
-      var button = selection2.selectAll(".field-help-button").data([0]);
-      button.enter().append("button").attr("class", "field-help-button").call(svgIcon("#iD-icon-help")).merge(button).on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        if (_body.classed("hide")) {
-          show();
-        } else {
-          hide();
+      _cullFactor = dimensions[0] * dimensions[1] / 1e6;
+      for (i3 = 0; i3 < entities.length; i3++) {
+        geometry = entities[i3].geometry(resolver);
+        matches = Object.keys(features.getMatches(entities[i3], resolver, geometry));
+        for (j2 = 0; j2 < matches.length; j2++) {
+          _rules[matches[j2]].count++;
         }
+      }
+      currHidden = features.hidden();
+      if (currHidden !== _hidden) {
+        _hidden = currHidden;
+        needsRedraw = true;
+        dispatch14.call("change");
+      }
+      return needsRedraw;
+    };
+    features.stats = function() {
+      for (var i3 = 0; i3 < _keys.length; i3++) {
+        _stats[_keys[i3]] = _rules[_keys[i3]].count;
+      }
+      return _stats;
+    };
+    features.clear = function(d2) {
+      for (var i3 = 0; i3 < d2.length; i3++) {
+        features.clearEntity(d2[i3]);
+      }
+    };
+    features.clearEntity = function(entity) {
+      delete _cache5[osmEntity.key(entity)];
+    };
+    features.reset = function() {
+      Array.from(_deferred2).forEach(function(handle) {
+        window.cancelIdleCallback(handle);
+        _deferred2.delete(handle);
       });
+      _cache5 = {};
     };
-    function updatePosition() {
-      var wrap2 = _wrap.node();
-      var inspector = _inspector.node();
-      var wRect = wrap2.getBoundingClientRect();
-      var iRect = inspector.getBoundingClientRect();
-      _body.style("top", wRect.top + inspector.scrollTop - iRect.top + "px");
+    function relationShouldBeChecked(relation) {
+      return relation.tags.type === "boundary";
     }
-    fieldHelp.body = function(selection2) {
-      _wrap = selection2.selectAll(".form-field-input-wrap");
-      if (_wrap.empty())
-        return;
-      _inspector = context.container().select(".sidebar .entity-editor-pane .inspector-body");
-      if (_inspector.empty())
-        return;
-      _body = _inspector.selectAll(".field-help-body").data([0]);
-      var enter = _body.enter().append("div").attr("class", "field-help-body hide");
-      var titleEnter = enter.append("div").attr("class", "field-help-title cf");
-      titleEnter.append("h2").attr("class", _mainLocalizer.textDirection() === "rtl" ? "fr" : "fl").call(_t.append("help.field." + fieldName + ".title"));
-      titleEnter.append("button").attr("class", "fr close").attr("title", _t("icons.close")).on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        hide();
-      }).call(svgIcon("#iD-icon-close"));
-      var navEnter = enter.append("div").attr("class", "field-help-nav cf");
-      var titles = docs.map(function(d2) {
-        return d2.title;
-      });
-      navEnter.selectAll(".field-help-nav-item").data(titles).enter().append("div").attr("class", "field-help-nav-item").html(function(d2) {
-        return d2;
-      }).on("click", function(d3_event, d2) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        clickHelp(titles.indexOf(d2));
-      });
-      enter.append("div").attr("class", "field-help-content");
-      _body = _body.merge(enter);
-      clickHelp(0);
-    };
-    return fieldHelp;
-  }
-
-  // modules/ui/fields/check.js
-  function uiFieldCheck(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var options2 = field.options;
-    var values = [];
-    var texts = [];
-    var _tags;
-    var input = select_default2(null);
-    var text = select_default2(null);
-    var label = select_default2(null);
-    var reverser = select_default2(null);
-    var _impliedYes;
-    var _entityIDs = [];
-    var _value;
-    var stringsField = field.resolveReference("stringsCrossReference");
-    if (!options2 && stringsField.options) {
-      options2 = stringsField.options;
-    }
-    if (options2) {
-      for (var i3 in options2) {
-        var v2 = options2[i3];
-        values.push(v2 === "undefined" ? void 0 : v2);
-        texts.push(stringsField.t.html("options." + v2, { "default": v2 }));
-      }
-    } else {
-      values = [void 0, "yes"];
-      texts = [_t.html("inspector.unknown"), _t.html("inspector.check.yes")];
-      if (field.type !== "defaultCheck") {
-        values.push("no");
-        texts.push(_t.html("inspector.check.no"));
+    features.getMatches = function(entity, resolver, geometry) {
+      if (geometry === "vertex" || geometry === "relation" && !relationShouldBeChecked(entity)) return {};
+      var ent = osmEntity.key(entity);
+      if (!_cache5[ent]) {
+        _cache5[ent] = {};
       }
-    }
-    function checkImpliedYes() {
-      _impliedYes = field.id === "oneway_yes";
-      if (field.id === "oneway") {
-        var entity = context.entity(_entityIDs[0]);
-        for (var key in entity.tags) {
-          if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
-            _impliedYes = true;
-            texts[0] = _t.html("_tagging.presets.fields.oneway_yes.options.undefined");
-            break;
+      if (!_cache5[ent].matches) {
+        var matches = {};
+        var hasMatch = false;
+        for (var i3 = 0; i3 < _keys.length; i3++) {
+          if (_keys[i3] === "others") {
+            if (hasMatch) continue;
+            if (entity.type === "way") {
+              var parents = features.getParents(entity, resolver, geometry);
+              if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
+              parents.length > 0 && parents.every(function(parent) {
+                return parent.tags.type === "boundary";
+              })) {
+                var pkey = osmEntity.key(parents[0]);
+                if (_cache5[pkey] && _cache5[pkey].matches) {
+                  matches = Object.assign({}, _cache5[pkey].matches);
+                  continue;
+                }
+              }
+            }
+          }
+          if (_rules[_keys[i3]].filter(entity.tags, geometry)) {
+            matches[_keys[i3]] = hasMatch = true;
           }
         }
+        _cache5[ent].matches = matches;
       }
-    }
-    function reverserHidden() {
-      if (!context.container().select("div.inspector-hover").empty())
-        return true;
-      return !(_value === "yes" || _impliedYes && !_value);
-    }
-    function reverserSetText(selection2) {
-      var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
-      if (reverserHidden() || !entity)
-        return selection2;
-      var first = entity.first();
-      var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
-      var pseudoDirection = first < last;
-      var icon2 = pseudoDirection ? "#iD-icon-forward" : "#iD-icon-backward";
-      selection2.selectAll(".reverser-span").html("").call(_t.append("inspector.check.reverser")).call(svgIcon(icon2, "inline"));
-      return selection2;
-    }
-    var check = function(selection2) {
-      checkImpliedYes();
-      label = selection2.selectAll(".form-field-input-wrap").data([0]);
-      var enter = label.enter().append("label").attr("class", "form-field-input-wrap form-field-input-check");
-      enter.append("input").property("indeterminate", field.type !== "defaultCheck").attr("type", "checkbox").attr("id", field.domId);
-      enter.append("span").html(texts[0]).attr("class", "value");
-      if (field.type === "onewayCheck") {
-        enter.append("button").attr("class", "reverser" + (reverserHidden() ? " hide" : "")).append("span").attr("class", "reverser-span");
+      return _cache5[ent].matches;
+    };
+    features.getParents = function(entity, resolver, geometry) {
+      if (geometry === "point") return [];
+      var ent = osmEntity.key(entity);
+      if (!_cache5[ent]) {
+        _cache5[ent] = {};
       }
-      label = label.merge(enter);
-      input = label.selectAll("input");
-      text = label.selectAll("span.value");
-      input.on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        var t2 = {};
-        if (Array.isArray(_tags[field.key])) {
-          if (values.indexOf("yes") !== -1) {
-            t2[field.key] = "yes";
-          } else {
-            t2[field.key] = values[0];
-          }
+      if (!_cache5[ent].parents) {
+        var parents = [];
+        if (geometry === "vertex") {
+          parents = resolver.parentWays(entity);
         } else {
-          t2[field.key] = values[(values.indexOf(_value) + 1) % values.length];
+          parents = resolver.parentRelations(entity);
         }
-        if (t2[field.key] === "reversible" || t2[field.key] === "alternating") {
-          t2[field.key] = values[0];
+        _cache5[ent].parents = parents;
+      }
+      return _cache5[ent].parents;
+    };
+    features.isHiddenPreset = function(preset, geometry) {
+      if (!_hidden.length) return false;
+      if (!preset.tags) return false;
+      var test = preset.setTags({}, geometry);
+      for (var key in _rules) {
+        if (_rules[key].filter(test, geometry)) {
+          if (_hidden.indexOf(key) !== -1) {
+            return key;
+          }
+          return false;
         }
-        dispatch14.call("change", this, t2);
-      });
-      if (field.type === "onewayCheck") {
-        reverser = label.selectAll(".reverser");
-        reverser.call(reverserSetText).on("click", function(d3_event) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          context.perform(
-            function(graph) {
-              for (var i4 in _entityIDs) {
-                graph = actionReverse(_entityIDs[i4])(graph);
-              }
-              return graph;
-            },
-            _t("operations.reverse.annotation.line", { n: 1 })
-          );
-          context.validator().validate();
-          select_default2(this).call(reverserSetText);
-        });
       }
+      return false;
     };
-    check.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return check;
+    features.isHiddenFeature = function(entity, resolver, geometry) {
+      if (!_hidden.length) return false;
+      if (!entity.version) return false;
+      if (_forceVisible[entity.id]) return false;
+      var matches = Object.keys(features.getMatches(entity, resolver, geometry));
+      return matches.length && matches.every(function(k2) {
+        return features.hidden(k2);
+      });
     };
-    check.tags = function(tags) {
-      _tags = tags;
-      function isChecked(val) {
-        return val !== "no" && val !== "" && val !== void 0 && val !== null;
-      }
-      function textFor(val) {
-        if (val === "")
-          val = void 0;
-        var index = values.indexOf(val);
-        return index !== -1 ? texts[index] : '"' + val + '"';
-      }
-      checkImpliedYes();
-      var isMixed = Array.isArray(tags[field.key]);
-      _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
-      if (field.type === "onewayCheck" && (_value === "1" || _value === "-1")) {
-        _value = "yes";
+    features.isHiddenChild = function(entity, resolver, geometry) {
+      if (!_hidden.length) return false;
+      if (!entity.version || geometry === "point") return false;
+      if (_forceVisible[entity.id]) return false;
+      var parents = features.getParents(entity, resolver, geometry);
+      if (!parents.length) return false;
+      for (var i3 = 0; i3 < parents.length; i3++) {
+        if (!features.isHidden(parents[i3], resolver, parents[i3].geometry(resolver))) {
+          return false;
+        }
       }
-      input.property("indeterminate", isMixed || field.type !== "defaultCheck" && !_value).property("checked", isChecked(_value));
-      text.html(isMixed ? _t.html("inspector.multiple_values") : textFor(_value)).classed("mixed", isMixed);
-      label.classed("set", !!_value);
-      if (field.type === "onewayCheck") {
-        reverser.classed("hide", reverserHidden()).call(reverserSetText);
+      return true;
+    };
+    features.hasHiddenConnections = function(entity, resolver) {
+      if (!_hidden.length) return false;
+      var childNodes, connections;
+      if (entity.type === "midpoint") {
+        childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
+        connections = [];
+      } else {
+        childNodes = entity.nodes ? resolver.childNodes(entity) : [];
+        connections = features.getParents(entity, resolver, entity.geometry(resolver));
       }
+      connections = childNodes.reduce(function(result, e3) {
+        return resolver.isShared(e3) ? utilArrayUnion(result, resolver.parentWays(e3)) : result;
+      }, connections);
+      return connections.some(function(e3) {
+        return features.isHidden(e3, resolver, e3.geometry(resolver));
+      });
     };
-    check.focus = function() {
-      input.node().focus();
+    features.isHidden = function(entity, resolver, geometry) {
+      if (!_hidden.length) return false;
+      if (!entity.version) return false;
+      var fn = geometry === "vertex" ? features.isHiddenChild : features.isHiddenFeature;
+      return fn(entity, resolver, geometry);
     };
-    return utilRebind(check, dispatch14, "on");
-  }
-
-  // modules/ui/length_indicator.js
-  function uiLengthIndicator(maxChars) {
-    var _wrap = select_default2(null);
-    var _tooltip = uiPopover("tooltip max-length-warning").placement("bottom").hasArrow(true).content(() => (selection2) => {
-      selection2.text("");
-      selection2.call(svgIcon("#iD-icon-alert", "inline"));
-      selection2.call(_t.append("inspector.max_length_reached", { maxChars }));
-    });
-    var _silent = false;
-    var lengthIndicator = function(selection2) {
-      _wrap = selection2.selectAll("span.length-indicator-wrap").data([0]);
-      _wrap = _wrap.enter().append("span").merge(_wrap).classed("length-indicator-wrap", true);
-      selection2.call(_tooltip);
+    features.filter = function(d2, resolver) {
+      if (!_hidden.length) return d2;
+      var result = [];
+      for (var i3 = 0; i3 < d2.length; i3++) {
+        var entity = d2[i3];
+        if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
+          result.push(entity);
+        }
+      }
+      return result;
     };
-    lengthIndicator.update = function(val) {
-      const strLen = utilUnicodeCharsCount(utilCleanOsmString(val, Number.POSITIVE_INFINITY));
-      let indicator = _wrap.selectAll("span.length-indicator").data([strLen]);
-      indicator.enter().append("span").merge(indicator).classed("length-indicator", true).classed("limit-reached", (d2) => d2 > maxChars).style("border-right-width", (d2) => "".concat(Math.abs(maxChars - d2) * 2, "px")).style("margin-right", (d2) => d2 > maxChars ? "".concat((maxChars - d2) * 2, "px") : 0).style("opacity", (d2) => d2 > maxChars * 0.8 ? Math.min(1, (d2 / maxChars - 0.8) / (1 - 0.8)) : 0).style("pointer-events", (d2) => d2 > maxChars * 0.8 ? null : "none");
-      if (_silent)
-        return;
-      if (strLen > maxChars) {
-        _tooltip.show();
-      } else {
-        _tooltip.hide();
+    features.forceVisible = function(entityIDs) {
+      if (!arguments.length) return Object.keys(_forceVisible);
+      _forceVisible = {};
+      for (var i3 = 0; i3 < entityIDs.length; i3++) {
+        _forceVisible[entityIDs[i3]] = true;
+        var entity = context.hasEntity(entityIDs[i3]);
+        if (entity && entity.type === "relation") {
+          for (var j2 in entity.members) {
+            _forceVisible[entity.members[j2].id] = true;
+          }
+        }
       }
+      return features;
     };
-    lengthIndicator.silent = function(val) {
-      if (!arguments.length)
-        return _silent;
-      _silent = val;
-      return lengthIndicator;
+    features.init = function() {
+      var storage = corePreferences("disabled-features");
+      if (storage) {
+        var storageDisabled = storage.replace(/;/g, ",").split(",");
+        storageDisabled.forEach(features.disable);
+      }
+      var hash = utilStringQs(window.location.hash);
+      if (hash.disable_features) {
+        var hashDisabled = hash.disable_features.replace(/;/g, ",").split(",");
+        hashDisabled.forEach(features.disable);
+      }
     };
-    return lengthIndicator;
+    context.history().on("merge.features", function(newEntities) {
+      if (!newEntities) return;
+      var handle = window.requestIdleCallback(function() {
+        var graph = context.graph();
+        var types = utilArrayGroupBy(newEntities, "type");
+        var entities = [].concat(types.relation || [], types.way || [], types.node || []);
+        for (var i3 = 0; i3 < entities.length; i3++) {
+          var geometry = entities[i3].geometry(graph);
+          features.getMatches(entities[i3], graph, geometry);
+        }
+      });
+      _deferred2.add(handle);
+    });
+    return features;
   }
 
-  // modules/ui/fields/combo.js
-  function uiFieldCombo(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var _isMulti = field.type === "multiCombo" || field.type === "manyCombo";
-    var _isNetwork = field.type === "networkCombo";
-    var _isSemi = field.type === "semiCombo";
-    var _showTagInfoSuggestions = field.type !== "manyCombo" && field.autoSuggestions !== false;
-    var _allowCustomValues = field.type !== "manyCombo" && field.customValues !== false;
-    var _snake_case = field.snake_case || field.snake_case === void 0;
-    var _combobox = uiCombobox(context, "combo-" + field.safeid).caseSensitive(field.caseSensitive).minItems(1);
-    var _container = select_default2(null);
-    var _inputWrap = select_default2(null);
-    var _input = select_default2(null);
-    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
-    var _comboData = [];
-    var _multiData = [];
-    var _entityIDs = [];
-    var _tags;
-    var _countryCode;
-    var _staticPlaceholder;
-    var _dataDeprecated = [];
-    _mainFileFetcher.get("deprecated").then(function(d2) {
-      _dataDeprecated = d2;
-    }).catch(function() {
-    });
-    if (_isMulti && field.key && /[^:]$/.test(field.key)) {
-      field.key += ":";
-    }
-    function snake(s2) {
-      return s2.replace(/\s+/g, "_");
-    }
-    function clean2(s2) {
-      return s2.split(";").map(function(s3) {
-        return s3.trim();
-      }).join(";");
-    }
-    function tagValue(dval) {
-      dval = clean2(dval || "");
-      var found = getOptions(true).find(function(o2) {
-        return o2.key && clean2(o2.value) === dval;
-      });
-      if (found)
-        return found.key;
-      if (field.type === "typeCombo" && !dval) {
-        return "yes";
-      }
-      return restrictTagValueSpelling(dval) || void 0;
-    }
-    function restrictTagValueSpelling(dval) {
-      if (_snake_case) {
-        dval = snake(dval);
-      }
-      if (!field.caseSensitive) {
-        dval = dval.toLowerCase();
-      }
-      return dval;
-    }
-    function getLabelId(field2, v2) {
-      return field2.hasTextForStringId("options.".concat(v2, ".title")) ? "options.".concat(v2, ".title") : "options.".concat(v2);
+  // modules/util/bind_once.js
+  function utilBindOnce(target, type2, listener, capture) {
+    var typeOnce = type2 + ".once";
+    function one2() {
+      target.on(typeOnce, null);
+      listener.apply(this, arguments);
     }
-    function displayValue(tval) {
-      tval = tval || "";
-      var stringsField = field.resolveReference("stringsCrossReference");
-      const labelId = getLabelId(stringsField, tval);
-      if (stringsField.hasTextForStringId(labelId)) {
-        return stringsField.t(labelId, { default: tval });
-      }
-      if (field.type === "typeCombo" && tval.toLowerCase() === "yes") {
-        return "";
+    target.on(typeOnce, one2, capture);
+    return this;
+  }
+
+  // modules/util/zoom_pan.js
+  function defaultFilter3(d3_event) {
+    return !d3_event.ctrlKey && !d3_event.button;
+  }
+  function defaultExtent2() {
+    var e3 = this;
+    if (e3 instanceof SVGElement) {
+      e3 = e3.ownerSVGElement || e3;
+      if (e3.hasAttribute("viewBox")) {
+        e3 = e3.viewBox.baseVal;
+        return [[e3.x, e3.y], [e3.x + e3.width, e3.y + e3.height]];
       }
-      return tval;
+      return [[0, 0], [e3.width.baseVal.value, e3.height.baseVal.value]];
     }
-    function renderValue(tval) {
-      tval = tval || "";
-      var stringsField = field.resolveReference("stringsCrossReference");
-      const labelId = getLabelId(stringsField, tval);
-      if (stringsField.hasTextForStringId(labelId)) {
-        return stringsField.t.append(labelId, { default: tval });
-      }
-      if (field.type === "typeCombo" && tval.toLowerCase() === "yes") {
-        tval = "";
-      }
-      return (selection2) => selection2.text(tval);
+    return [[0, 0], [e3.clientWidth, e3.clientHeight]];
+  }
+  function defaultWheelDelta2(d3_event) {
+    return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 2e-3);
+  }
+  function defaultConstrain2(transform2, extent, translateExtent) {
+    var dx0 = transform2.invertX(extent[0][0]) - translateExtent[0][0], dx1 = transform2.invertX(extent[1][0]) - translateExtent[1][0], dy0 = transform2.invertY(extent[0][1]) - translateExtent[0][1], dy1 = transform2.invertY(extent[1][1]) - translateExtent[1][1];
+    return transform2.translate(
+      dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
+      dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
+    );
+  }
+  function utilZoomPan() {
+    var filter2 = defaultFilter3, extent = defaultExtent2, constrain = defaultConstrain2, wheelDelta = defaultWheelDelta2, scaleExtent = [0, Infinity], translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], interpolate = zoom_default, dispatch14 = dispatch_default("start", "zoom", "end"), _wheelDelay = 150, _transform = identity2, _activeGesture;
+    function zoom(selection2) {
+      selection2.on("pointerdown.zoom", pointerdown).on("wheel.zoom", wheeled).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
+      select_default2(window).on("pointermove.zoompan", pointermove).on("pointerup.zoompan pointercancel.zoompan", pointerup);
     }
-    function objectDifference(a2, b2) {
-      return a2.filter(function(d1) {
-        return !b2.some(function(d2) {
-          return d1.value === d2.value;
+    zoom.transform = function(collection, transform2, point) {
+      var selection2 = collection.selection ? collection.selection() : collection;
+      if (collection !== selection2) {
+        schedule(collection, transform2, point);
+      } else {
+        selection2.interrupt().each(function() {
+          gesture(this, arguments).start(null).zoom(null, null, typeof transform2 === "function" ? transform2.apply(this, arguments) : transform2).end(null);
         });
+      }
+    };
+    zoom.scaleBy = function(selection2, k2, p2) {
+      zoom.scaleTo(selection2, function() {
+        var k0 = _transform.k, k1 = typeof k2 === "function" ? k2.apply(this, arguments) : k2;
+        return k0 * k1;
+      }, p2);
+    };
+    zoom.scaleTo = function(selection2, k2, p2) {
+      zoom.transform(selection2, function() {
+        var e3 = extent.apply(this, arguments), t0 = _transform, p02 = !p2 ? centroid(e3) : typeof p2 === "function" ? p2.apply(this, arguments) : p2, p1 = t0.invert(p02), k1 = typeof k2 === "function" ? k2.apply(this, arguments) : k2;
+        return constrain(translate(scale(t0, k1), p02, p1), e3, translateExtent);
+      }, p2);
+    };
+    zoom.translateBy = function(selection2, x2, y2) {
+      zoom.transform(selection2, function() {
+        return constrain(_transform.translate(
+          typeof x2 === "function" ? x2.apply(this, arguments) : x2,
+          typeof y2 === "function" ? y2.apply(this, arguments) : y2
+        ), extent.apply(this, arguments), translateExtent);
       });
+    };
+    zoom.translateTo = function(selection2, x2, y2, p2) {
+      zoom.transform(selection2, function() {
+        var e3 = extent.apply(this, arguments), t2 = _transform, p02 = !p2 ? centroid(e3) : typeof p2 === "function" ? p2.apply(this, arguments) : p2;
+        return constrain(identity2.translate(p02[0], p02[1]).scale(t2.k).translate(
+          typeof x2 === "function" ? -x2.apply(this, arguments) : -x2,
+          typeof y2 === "function" ? -y2.apply(this, arguments) : -y2
+        ), e3, translateExtent);
+      }, p2);
+    };
+    function scale(transform2, k2) {
+      k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k2));
+      return k2 === transform2.k ? transform2 : new Transform(k2, transform2.x, transform2.y);
     }
-    function initCombo(selection2, attachTo) {
-      if (!_allowCustomValues) {
-        selection2.attr("readonly", "readonly");
-      }
-      if (_showTagInfoSuggestions && services.taginfo) {
-        selection2.call(_combobox.fetcher(setTaginfoValues), attachTo);
-        setTaginfoValues("", setPlaceholder);
-      } else {
-        selection2.call(_combobox, attachTo);
-        setTimeout(() => setStaticValues(setPlaceholder), 0);
-      }
+    function translate(transform2, p02, p1) {
+      var x2 = p02[0] - p1[0] * transform2.k, y2 = p02[1] - p1[1] * transform2.k;
+      return x2 === transform2.x && y2 === transform2.y ? transform2 : new Transform(transform2.k, x2, y2);
     }
-    function getOptions(allOptions) {
-      var stringsField = field.resolveReference("stringsCrossReference");
-      if (!(field.options || stringsField.options))
-        return [];
-      let options2;
-      if (allOptions !== true) {
-        options2 = field.options || stringsField.options;
-      } else {
-        options2 = [].concat(field.options, stringsField.options).filter(Boolean);
-      }
-      return options2.map(function(v2) {
-        const labelId = getLabelId(stringsField, v2);
-        return {
-          key: v2,
-          value: stringsField.t(labelId, { default: v2 }),
-          title: stringsField.t("options.".concat(v2, ".description"), { default: v2 }),
-          display: addComboboxIcons(stringsField.t.append(labelId, { default: v2 }), v2),
-          klass: stringsField.hasTextForStringId(labelId) ? "" : "raw-option"
+    function centroid(extent2) {
+      return [(+extent2[0][0] + +extent2[1][0]) / 2, (+extent2[0][1] + +extent2[1][1]) / 2];
+    }
+    function schedule(transition2, transform2, point) {
+      transition2.on("start.zoom", function() {
+        gesture(this, arguments).start(null);
+      }).on("interrupt.zoom end.zoom", function() {
+        gesture(this, arguments).end(null);
+      }).tween("zoom", function() {
+        var that = this, args = arguments, g3 = gesture(that, args), e3 = extent.apply(that, args), p2 = !point ? centroid(e3) : typeof point === "function" ? point.apply(that, args) : point, w2 = Math.max(e3[1][0] - e3[0][0], e3[1][1] - e3[0][1]), a2 = _transform, b2 = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i3 = interpolate(a2.invert(p2).concat(w2 / a2.k), b2.invert(p2).concat(w2 / b2.k));
+        return function(t2) {
+          if (t2 === 1) {
+            t2 = b2;
+          } else {
+            var l2 = i3(t2);
+            var k2 = w2 / l2[2];
+            t2 = new Transform(k2, p2[0] - l2[0] * k2, p2[1] - l2[1] * k2);
+          }
+          g3.zoom(null, null, t2);
         };
       });
     }
-    function hasStaticValues() {
-      return getOptions().length > 0;
+    function gesture(that, args, clean2) {
+      return !clean2 && _activeGesture || new Gesture(that, args);
     }
-    function setStaticValues(callback, filter2) {
-      _comboData = getOptions();
-      if (filter2 !== void 0) {
-        _comboData = _comboData.filter(filter2);
-      }
-      _comboData = objectDifference(_comboData, _multiData);
-      _combobox.data(_comboData);
-      if (callback)
-        callback(_comboData);
+    function Gesture(that, args) {
+      this.that = that;
+      this.args = args;
+      this.active = 0;
+      this.extent = extent.apply(that, args);
     }
-    function setTaginfoValues(q2, callback) {
-      var queryFilter = (d2) => d2.value.toLowerCase().includes(q2.toLowerCase()) || d2.key.toLowerCase().includes(q2.toLowerCase());
-      if (hasStaticValues()) {
-        setStaticValues(callback, queryFilter);
+    Gesture.prototype = {
+      start: function(d3_event) {
+        if (++this.active === 1) {
+          _activeGesture = this;
+          dispatch14.call("start", this, d3_event);
+        }
+        return this;
+      },
+      zoom: function(d3_event, key, transform2) {
+        if (this.mouse && key !== "mouse") this.mouse[1] = transform2.invert(this.mouse[0]);
+        if (this.pointer0 && key !== "touch") this.pointer0[1] = transform2.invert(this.pointer0[0]);
+        if (this.pointer1 && key !== "touch") this.pointer1[1] = transform2.invert(this.pointer1[0]);
+        _transform = transform2;
+        dispatch14.call("zoom", this, d3_event, key, transform2);
+        return this;
+      },
+      end: function(d3_event) {
+        if (--this.active === 0) {
+          _activeGesture = null;
+          dispatch14.call("end", this, d3_event);
+        }
+        return this;
       }
-      var stringsField = field.resolveReference("stringsCrossReference");
-      var fn = _isMulti ? "multikeys" : "values";
-      var query = (_isMulti ? field.key : "") + q2;
-      var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q2.toLowerCase()) === 0;
-      if (hasCountryPrefix) {
-        query = _countryCode + ":";
+    };
+    function wheeled(d3_event) {
+      if (!filter2.apply(this, arguments)) return;
+      var g3 = gesture(this, arguments), t2 = _transform, k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t2.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p2 = utilFastMouse(this)(d3_event);
+      if (g3.wheel) {
+        if (g3.mouse[0][0] !== p2[0] || g3.mouse[0][1] !== p2[1]) {
+          g3.mouse[1] = t2.invert(g3.mouse[0] = p2);
+        }
+        clearTimeout(g3.wheel);
+      } else {
+        g3.mouse = [p2, t2.invert(p2)];
+        interrupt_default(this);
+        g3.start(d3_event);
       }
-      var params = {
-        debounce: q2 !== "",
-        key: field.key,
-        query
-      };
-      if (_entityIDs.length) {
-        params.geometry = context.graph().geometry(_entityIDs[0]);
+      d3_event.preventDefault();
+      d3_event.stopImmediatePropagation();
+      g3.wheel = setTimeout(wheelidled, _wheelDelay);
+      g3.zoom(d3_event, "mouse", constrain(translate(scale(t2, k2), g3.mouse[0], g3.mouse[1]), g3.extent, translateExtent));
+      function wheelidled() {
+        g3.wheel = null;
+        g3.end(d3_event);
       }
-      services.taginfo[fn](params, function(err, data) {
-        if (err)
-          return;
-        data = data.filter((d2) => field.type !== "typeCombo" || d2.value !== "yes");
-        data = data.filter((d2) => {
-          var value = d2.value;
-          if (_isMulti) {
-            value = value.slice(field.key.length);
-          }
-          return value === restrictTagValueSpelling(value);
-        });
-        var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
-        if (deprecatedValues) {
-          data = data.filter((d2) => !deprecatedValues.includes(d2.value));
-        }
-        if (hasCountryPrefix) {
-          data = data.filter((d2) => d2.value.toLowerCase().indexOf(_countryCode + ":") === 0);
-        }
-        const additionalOptions = (field.options || stringsField.options || []).filter((v2) => !data.some((dv) => dv.value === (_isMulti ? field.key + v2 : v2))).map((v2) => ({ value: v2 }));
-        _container.classed("empty-combobox", data.length === 0);
-        _comboData = data.concat(additionalOptions).map(function(d2) {
-          var v2 = d2.value;
-          if (_isMulti)
-            v2 = v2.replace(field.key, "");
-          const labelId = getLabelId(stringsField, v2);
-          var isLocalizable = stringsField.hasTextForStringId(labelId);
-          var label = stringsField.t(labelId, { default: v2 });
-          return {
-            key: v2,
-            value: label,
-            title: stringsField.t("options.".concat(v2, ".description"), { default: isLocalizable ? v2 : d2.title !== label ? d2.title : "" }),
-            display: addComboboxIcons(stringsField.t.append(labelId, { default: v2 }), v2),
-            klass: isLocalizable ? "" : "raw-option"
-          };
-        });
-        _comboData = _comboData.filter(queryFilter);
-        _comboData = objectDifference(_comboData, _multiData);
-        if (callback)
-          callback(_comboData, hasStaticValues());
-      });
     }
-    function addComboboxIcons(disp, value) {
-      const iconsField = field.resolveReference("iconsCrossReference");
-      if (iconsField.icons) {
-        return function(selection2) {
-          var span = selection2.insert("span", ":first-child").attr("class", "tag-value-icon");
-          if (iconsField.icons[value]) {
-            span.call(svgIcon("#".concat(iconsField.icons[value])));
-          }
-          disp.call(this, selection2);
-        };
+    var _downPointerIDs = /* @__PURE__ */ new Set();
+    var _pointerLocGetter;
+    function pointerdown(d3_event) {
+      _downPointerIDs.add(d3_event.pointerId);
+      if (!filter2.apply(this, arguments)) return;
+      var g3 = gesture(this, arguments, _downPointerIDs.size === 1);
+      var started;
+      d3_event.stopImmediatePropagation();
+      _pointerLocGetter = utilFastMouse(this);
+      var loc = _pointerLocGetter(d3_event);
+      var p2 = [loc, _transform.invert(loc), d3_event.pointerId];
+      if (!g3.pointer0) {
+        g3.pointer0 = p2;
+        started = true;
+      } else if (!g3.pointer1 && g3.pointer0[2] !== p2[2]) {
+        g3.pointer1 = p2;
       }
-      return disp;
-    }
-    function setPlaceholder(values) {
-      if (_isMulti || _isSemi) {
-        _staticPlaceholder = field.placeholder() || _t("inspector.add");
-      } else {
-        var vals = values.map(function(d2) {
-          return d2.value;
-        }).filter(function(s2) {
-          return s2.length < 20;
-        });
-        var placeholders = vals.length > 1 ? vals : values.map(function(d2) {
-          return d2.key;
-        });
-        _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(", ");
+      if (started) {
+        interrupt_default(this);
+        g3.start(d3_event);
       }
-      if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
-        _staticPlaceholder += "\u2026";
+    }
+    function pointermove(d3_event) {
+      if (!_downPointerIDs.has(d3_event.pointerId)) return;
+      if (!_activeGesture || !_pointerLocGetter) return;
+      var g3 = gesture(this, arguments);
+      var isPointer0 = g3.pointer0 && g3.pointer0[2] === d3_event.pointerId;
+      var isPointer1 = !isPointer0 && g3.pointer1 && g3.pointer1[2] === d3_event.pointerId;
+      if ((isPointer0 || isPointer1) && "buttons" in d3_event && !d3_event.buttons) {
+        if (g3.pointer0) _downPointerIDs.delete(g3.pointer0[2]);
+        if (g3.pointer1) _downPointerIDs.delete(g3.pointer1[2]);
+        g3.end(d3_event);
+        return;
       }
-      var ph;
-      if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
-        ph = _t("inspector.multiple_values");
+      d3_event.preventDefault();
+      d3_event.stopImmediatePropagation();
+      var loc = _pointerLocGetter(d3_event);
+      var t2, p2, l2;
+      if (isPointer0) g3.pointer0[0] = loc;
+      else if (isPointer1) g3.pointer1[0] = loc;
+      t2 = _transform;
+      if (g3.pointer1) {
+        var p02 = g3.pointer0[0], l0 = g3.pointer0[1], p1 = g3.pointer1[0], l1 = g3.pointer1[1], dp = (dp = p1[0] - p02[0]) * dp + (dp = p1[1] - p02[1]) * dp, dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
+        t2 = scale(t2, Math.sqrt(dp / dl));
+        p2 = [(p02[0] + p1[0]) / 2, (p02[1] + p1[1]) / 2];
+        l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
+      } else if (g3.pointer0) {
+        p2 = g3.pointer0[0];
+        l2 = g3.pointer0[1];
       } else {
-        ph = _staticPlaceholder;
+        return;
       }
-      _container.selectAll("input").attr("placeholder", ph);
-      var hideAdd = !_allowCustomValues && !values.length;
-      _container.selectAll(".chiplist .input-wrap").style("display", hideAdd ? "none" : null);
+      g3.zoom(d3_event, "touch", constrain(translate(t2, p2, l2), g3.extent, translateExtent));
     }
-    function change() {
-      var t2 = {};
-      var val;
-      if (_isMulti || _isSemi) {
-        var vals;
-        if (_isMulti) {
-          vals = [tagValue(utilGetSetValue(_input))];
-        } else if (_isSemi) {
-          val = tagValue(utilGetSetValue(_input)) || "";
-          val = val.replace(/,/g, ";");
-          vals = val.split(";");
-        }
-        vals = vals.filter(Boolean);
-        if (!vals.length)
-          return;
-        _container.classed("active", false);
-        utilGetSetValue(_input, "");
-        if (_isMulti) {
-          utilArrayUniq(vals).forEach(function(v2) {
-            var key = (field.key || "") + v2;
-            if (_tags) {
-              var old = _tags[key];
-              if (typeof old === "string" && old.toLowerCase() !== "no")
-                return;
-            }
-            key = context.cleanTagKey(key);
-            field.keys.push(key);
-            t2[key] = "yes";
-          });
-        } else if (_isSemi) {
-          var arr = _multiData.map(function(d2) {
-            return d2.key;
-          });
-          arr = arr.concat(vals);
-          t2[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(";"));
-        }
-        window.setTimeout(function() {
-          _input.node().focus();
-        }, 10);
+    function pointerup(d3_event) {
+      if (!_downPointerIDs.has(d3_event.pointerId)) return;
+      _downPointerIDs.delete(d3_event.pointerId);
+      if (!_activeGesture) return;
+      var g3 = gesture(this, arguments);
+      d3_event.stopImmediatePropagation();
+      if (g3.pointer0 && g3.pointer0[2] === d3_event.pointerId) delete g3.pointer0;
+      else if (g3.pointer1 && g3.pointer1[2] === d3_event.pointerId) delete g3.pointer1;
+      if (g3.pointer1 && !g3.pointer0) {
+        g3.pointer0 = g3.pointer1;
+        delete g3.pointer1;
+      }
+      if (g3.pointer0) {
+        g3.pointer0[1] = _transform.invert(g3.pointer0[0]);
       } else {
-        var rawValue = utilGetSetValue(_input);
-        if (!rawValue && Array.isArray(_tags[field.key]))
-          return;
-        val = context.cleanTagValue(tagValue(rawValue));
-        t2[field.key] = val || void 0;
+        g3.end(d3_event);
       }
-      dispatch14.call("change", this, t2);
     }
-    function removeMultikey(d3_event, d2) {
-      d3_event.preventDefault();
-      d3_event.stopPropagation();
-      var t2 = {};
-      if (_isMulti) {
-        t2[d2.key] = void 0;
-      } else if (_isSemi) {
-        var arr = _multiData.map(function(md) {
-          return md.key === d2.key ? null : md.key;
-        }).filter(Boolean);
-        arr = utilArrayUniq(arr);
-        t2[field.key] = arr.length ? arr.join(";") : void 0;
-        _lengthIndicator.update(t2[field.key]);
-      }
-      dispatch14.call("change", this, t2);
+    zoom.wheelDelta = function(_2) {
+      return arguments.length ? (wheelDelta = utilFunctor(+_2), zoom) : wheelDelta;
+    };
+    zoom.filter = function(_2) {
+      return arguments.length ? (filter2 = utilFunctor(!!_2), zoom) : filter2;
+    };
+    zoom.extent = function(_2) {
+      return arguments.length ? (extent = utilFunctor([[+_2[0][0], +_2[0][1]], [+_2[1][0], +_2[1][1]]]), zoom) : extent;
+    };
+    zoom.scaleExtent = function(_2) {
+      return arguments.length ? (scaleExtent[0] = +_2[0], scaleExtent[1] = +_2[1], zoom) : [scaleExtent[0], scaleExtent[1]];
+    };
+    zoom.translateExtent = function(_2) {
+      return arguments.length ? (translateExtent[0][0] = +_2[0][0], translateExtent[1][0] = +_2[1][0], translateExtent[0][1] = +_2[0][1], translateExtent[1][1] = +_2[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
+    };
+    zoom.constrain = function(_2) {
+      return arguments.length ? (constrain = _2, zoom) : constrain;
+    };
+    zoom.interpolate = function(_2) {
+      return arguments.length ? (interpolate = _2, zoom) : interpolate;
+    };
+    zoom._transform = function(_2) {
+      return arguments.length ? (_transform = _2, zoom) : _transform;
+    };
+    return utilRebind(zoom, dispatch14, "on");
+  }
+
+  // modules/util/double_up.js
+  function utilDoubleUp() {
+    var dispatch14 = dispatch_default("doubleUp");
+    var _maxTimespan = 500;
+    var _maxDistance = 20;
+    var _pointer;
+    function pointerIsValidFor(loc) {
+      return (/* @__PURE__ */ new Date()).getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
+      geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
     }
-    function invertMultikey(d3_event, d2) {
-      d3_event.preventDefault();
-      d3_event.stopPropagation();
-      var t2 = {};
-      if (_isMulti) {
-        t2[d2.key] = _tags[d2.key] === "yes" ? "no" : "yes";
+    function pointerdown(d3_event) {
+      if (d3_event.ctrlKey || d3_event.button === 2) return;
+      var loc = [d3_event.clientX, d3_event.clientY];
+      if (_pointer && !pointerIsValidFor(loc)) {
+        _pointer = void 0;
+      }
+      if (!_pointer) {
+        _pointer = {
+          startLoc: loc,
+          startTime: (/* @__PURE__ */ new Date()).getTime(),
+          upCount: 0,
+          pointerId: d3_event.pointerId
+        };
+      } else {
+        _pointer.pointerId = d3_event.pointerId;
       }
-      dispatch14.call("change", this, t2);
     }
-    function combo(selection2) {
-      _container = selection2.selectAll(".form-field-input-wrap").data([0]);
-      var type2 = _isMulti || _isSemi ? "multicombo" : "combo";
-      _container = _container.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + type2).merge(_container);
-      if (_isMulti || _isSemi) {
-        _container = _container.selectAll(".chiplist").data([0]);
-        var listClass = "chiplist";
-        if (field.key === "destination" || field.key === "via") {
-          listClass += " full-line-chips";
+    function pointerup(d3_event) {
+      if (d3_event.ctrlKey || d3_event.button === 2) return;
+      if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
+      _pointer.upCount += 1;
+      if (_pointer.upCount === 2) {
+        var loc = [d3_event.clientX, d3_event.clientY];
+        if (pointerIsValidFor(loc)) {
+          var locInThis = utilFastMouse(this)(d3_event);
+          dispatch14.call("doubleUp", this, d3_event, locInThis);
         }
-        _container = _container.enter().append("ul").attr("class", listClass).on("click", function() {
-          window.setTimeout(function() {
-            _input.node().focus();
-          }, 10);
-        }).merge(_container);
-        _inputWrap = _container.selectAll(".input-wrap").data([0]);
-        _inputWrap = _inputWrap.enter().append("li").attr("class", "input-wrap").merge(_inputWrap);
-        var hideAdd = !_allowCustomValues && !_comboData.length;
-        _inputWrap.style("display", hideAdd ? "none" : null);
-        _input = _inputWrap.selectAll("input").data([0]);
-      } else {
-        _input = _container.selectAll("input").data([0]);
+        _pointer = void 0;
       }
-      _input = _input.enter().append("input").attr("type", "text").attr("id", field.domId).call(utilNoAuto).call(initCombo, _container).merge(_input);
-      if (_isSemi) {
-        _inputWrap.call(_lengthIndicator);
-      } else if (!_isMulti) {
-        _container.call(_lengthIndicator);
+    }
+    function doubleUp(selection2) {
+      if ("PointerEvent" in window) {
+        selection2.on("pointerdown.doubleUp", pointerdown).on("pointerup.doubleUp", pointerup);
+      } else {
+        selection2.on("dblclick.doubleUp", function(d3_event) {
+          dispatch14.call("doubleUp", this, d3_event, utilFastMouse(this)(d3_event));
+        });
       }
-      if (_isNetwork) {
-        var extent = combinedEntityExtent();
-        var countryCode = extent && iso1A2Code(extent.center());
-        _countryCode = countryCode && countryCode.toLowerCase();
+    }
+    doubleUp.off = function(selection2) {
+      selection2.on("pointerdown.doubleUp", null).on("pointerup.doubleUp", null).on("dblclick.doubleUp", null);
+    };
+    return utilRebind(doubleUp, dispatch14, "on");
+  }
+
+  // modules/renderer/map.js
+  var TILESIZE = 256;
+  var minZoom2 = 2;
+  var maxZoom = 24;
+  var kMin = geoZoomToScale(minZoom2, TILESIZE);
+  var kMax = geoZoomToScale(maxZoom, TILESIZE);
+  function clamp2(num, min3, max3) {
+    return Math.max(min3, Math.min(num, max3));
+  }
+  function rendererMap(context) {
+    var dispatch14 = dispatch_default(
+      "move",
+      "drawn",
+      "crossEditableZoom",
+      "hitMinZoom",
+      "changeHighlighting",
+      "changeAreaFill"
+    );
+    var projection2 = context.projection;
+    var curtainProjection = context.curtainProjection;
+    var drawLayers;
+    var drawPoints;
+    var drawVertices;
+    var drawLines;
+    var drawAreas;
+    var drawMidpoints;
+    var drawLabels;
+    var _selection = select_default2(null);
+    var supersurface = select_default2(null);
+    var wrapper = select_default2(null);
+    var surface = select_default2(null);
+    var _dimensions = [1, 1];
+    var _dblClickZoomEnabled = true;
+    var _redrawEnabled = true;
+    var _gestureTransformStart;
+    var _transformStart = projection2.transform();
+    var _transformLast;
+    var _isTransformed = false;
+    var _minzoom = 0;
+    var _getMouseCoords;
+    var _lastPointerEvent;
+    var _lastWithinEditableZoom;
+    var _pointerDown = false;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    var _zoomerPannerFunction = "PointerEvent" in window ? utilZoomPan : zoom_default2;
+    var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(value_default).filter(zoomEventFilter).on("zoom.map", zoomPan2).on("start.map", function(d3_event) {
+      _pointerDown = d3_event && (d3_event.type === "pointerdown" || d3_event.sourceEvent && d3_event.sourceEvent.type === "pointerdown");
+    }).on("end.map", function() {
+      _pointerDown = false;
+    });
+    var _doubleUpHandler = utilDoubleUp();
+    var scheduleRedraw = throttle_default(redraw, 750);
+    function cancelPendingRedraw() {
+      scheduleRedraw.cancel();
+    }
+    function map2(selection2) {
+      _selection = selection2;
+      context.on("change.map", immediateRedraw);
+      var osm = context.connection();
+      if (osm) {
+        osm.on("change.map", immediateRedraw);
       }
-      _input.on("change", change).on("blur", change).on("input", function() {
-        let val = utilGetSetValue(_input);
-        updateIcon(val);
-        if (_isSemi && _tags[field.key]) {
-          val += ";" + _tags[field.key];
+      function didUndoOrRedo(targetTransform) {
+        var mode = context.mode().id;
+        if (mode !== "browse" && mode !== "select") return;
+        if (targetTransform) {
+          map2.transformEase(targetTransform);
         }
-        _lengthIndicator.update(val);
+      }
+      context.history().on("merge.map", function() {
+        scheduleRedraw();
+      }).on("change.map", immediateRedraw).on("undone.map", function(stack, fromStack) {
+        didUndoOrRedo(fromStack.transform);
+      }).on("redone.map", function(stack) {
+        didUndoOrRedo(stack.transform);
       });
-      _input.on("keydown.field", function(d3_event) {
-        switch (d3_event.keyCode) {
-          case 13:
-            _input.node().blur();
-            d3_event.stopPropagation();
-            break;
+      context.background().on("change.map", immediateRedraw);
+      context.features().on("redraw.map", immediateRedraw);
+      drawLayers.on("change.map", function() {
+        context.background().updateImagery();
+        immediateRedraw();
+      });
+      selection2.on("wheel.map mousewheel.map", function(d3_event) {
+        d3_event.preventDefault();
+      }).call(_zoomerPanner).call(_zoomerPanner.transform, projection2.transform()).on("dblclick.zoom", null);
+      map2.supersurface = supersurface = selection2.append("div").attr("class", "supersurface").call(utilSetTransform, 0, 0);
+      wrapper = supersurface.append("div").attr("class", "layer layer-data");
+      map2.surface = surface = wrapper.call(drawLayers).selectAll(".surface");
+      surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + "down.zoom", function(d3_event) {
+        _lastPointerEvent = d3_event;
+        if (d3_event.button === 2) {
+          d3_event.stopPropagation();
+        }
+      }, true).on(_pointerPrefix + "up.zoom", function(d3_event) {
+        _lastPointerEvent = d3_event;
+        if (resetTransform()) {
+          immediateRedraw();
+        }
+      }).on(_pointerPrefix + "move.map", function(d3_event) {
+        _lastPointerEvent = d3_event;
+      }).on(_pointerPrefix + "over.vertices", function(d3_event) {
+        if (map2.editableDataEnabled() && !_isTransformed) {
+          var hover = d3_event.target.__data__;
+          surface.call(drawVertices.drawHover, context.graph(), hover, map2.extent());
+          dispatch14.call("drawn", this, { full: false });
+        }
+      }).on(_pointerPrefix + "out.vertices", function(d3_event) {
+        if (map2.editableDataEnabled() && !_isTransformed) {
+          var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
+          surface.call(drawVertices.drawHover, context.graph(), hover, map2.extent());
+          dispatch14.call("drawn", this, { full: false });
         }
       });
-      if (_isMulti || _isSemi) {
-        _combobox.on("accept", function() {
-          _input.node().blur();
-          _input.node().focus();
-        });
-        _input.on("focus", function() {
-          _container.classed("active", true);
-        });
+      var detected = utilDetect();
+      if ("GestureEvent" in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
+      // but we only need to do this on desktop Safari anyway. – #7694
+      !detected.isMobileWebKit) {
+        surface.on("gesturestart.surface", function(d3_event) {
+          d3_event.preventDefault();
+          _gestureTransformStart = projection2.transform();
+        }).on("gesturechange.surface", gestureChange);
       }
-      _combobox.on("cancel", function() {
-        _input.node().blur();
-      }).on("update", function() {
-        updateIcon(utilGetSetValue(_input));
+      updateAreaFill();
+      _doubleUpHandler.on("doubleUp.map", function(d3_event, p02) {
+        if (!_dblClickZoomEnabled) return;
+        if (typeof d3_event.target.__data__ === "object" && // or area fills
+        !select_default2(d3_event.target).classed("fill")) return;
+        var zoomOut2 = d3_event.shiftKey;
+        var t2 = projection2.transform();
+        var p1 = t2.invert(p02);
+        t2 = t2.scale(zoomOut2 ? 0.5 : 2);
+        t2.x = p02[0] - p1[0] * t2.k;
+        t2.y = p02[1] - p1[1] * t2.k;
+        map2.transformEase(t2);
       });
-    }
-    function updateIcon(value) {
-      value = tagValue(value);
-      let container = _container;
-      if (field.type === "multiCombo" || field.type === "semiCombo") {
-        container = _container.select(".input-wrap");
-      }
-      const iconsField = field.resolveReference("iconsCrossReference");
-      if (iconsField.icons) {
-        container.selectAll(".tag-value-icon").remove();
-        if (iconsField.icons[value]) {
-          container.selectAll(".tag-value-icon").data([value]).enter().insert("div", "input").attr("class", "tag-value-icon").call(svgIcon("#".concat(iconsField.icons[value])));
-        }
-      }
-    }
-    combo.tags = function(tags) {
-      _tags = tags;
-      var stringsField = field.resolveReference("stringsCrossReference");
-      var isMixed = Array.isArray(tags[field.key]);
-      var showsValue = (value) => !isMixed && value && !(field.type === "typeCombo" && value === "yes");
-      var isRawValue = (value) => showsValue(value) && !stringsField.hasTextForStringId("options.".concat(value)) && !stringsField.hasTextForStringId("options.".concat(value, ".title"));
-      var isKnownValue = (value) => showsValue(value) && !isRawValue(value);
-      var isReadOnly = !_allowCustomValues;
-      if (_isMulti || _isSemi) {
-        _multiData = [];
-        var maxLength;
-        if (_isMulti) {
-          for (var k2 in tags) {
-            if (field.key && k2.indexOf(field.key) !== 0)
-              continue;
-            if (!field.key && field.keys.indexOf(k2) === -1)
-              continue;
-            var v2 = tags[k2];
-            var suffix = field.key ? k2.slice(field.key.length) : k2;
-            _multiData.push({
-              key: k2,
-              value: displayValue(suffix),
-              display: addComboboxIcons(renderValue(suffix), suffix),
-              state: typeof v2 === "string" ? v2.toLowerCase() : "",
-              isMixed: Array.isArray(v2)
-            });
-          }
-          if (field.key) {
-            field.keys = _multiData.map(function(d2) {
-              return d2.key;
-            });
-            maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
-          } else {
-            maxLength = context.maxCharsForTagKey();
-          }
-        } else if (_isSemi) {
-          var allValues = [];
-          var commonValues;
-          if (Array.isArray(tags[field.key])) {
-            tags[field.key].forEach(function(tagVal) {
-              var thisVals = utilArrayUniq((tagVal || "").split(";")).filter(Boolean);
-              allValues = allValues.concat(thisVals);
-              if (!commonValues) {
-                commonValues = thisVals;
-              } else {
-                commonValues = commonValues.filter((value) => thisVals.includes(value));
-              }
-            });
-            allValues = utilArrayUniq(allValues).filter(Boolean);
-          } else {
-            allValues = utilArrayUniq((tags[field.key] || "").split(";")).filter(Boolean);
-            commonValues = allValues;
-          }
-          _multiData = allValues.map(function(v3) {
-            return {
-              key: v3,
-              value: displayValue(v3),
-              display: addComboboxIcons(renderValue(v3), v3),
-              isMixed: !commonValues.includes(v3)
-            };
-          });
-          var currLength = utilUnicodeCharsCount(commonValues.join(";"));
-          maxLength = context.maxCharsForTagValue() - currLength;
-          if (currLength > 0) {
-            maxLength -= 1;
-          }
-        }
-        maxLength = Math.max(0, maxLength);
-        var hideAdd = maxLength <= 0 || !_allowCustomValues && !_comboData.length;
-        _container.selectAll(".chiplist .input-wrap").style("display", hideAdd ? "none" : null);
-        var allowDragAndDrop = _isSemi && !Array.isArray(tags[field.key]);
-        var chips = _container.selectAll(".chip").data(_multiData);
-        chips.exit().remove();
-        var enter = chips.enter().insert("li", ".input-wrap").attr("class", "chip");
-        enter.append("span");
-        const field_buttons = enter.append("div").attr("class", "field_buttons");
-        field_buttons.append("a").attr("class", "remove");
-        chips = chips.merge(enter).order().classed("raw-value", function(d2) {
-          var k3 = d2.key;
-          if (_isMulti)
-            k3 = k3.replace(field.key, "");
-          return !stringsField.hasTextForStringId("options." + k3);
-        }).classed("draggable", allowDragAndDrop).classed("mixed", function(d2) {
-          return d2.isMixed;
-        }).attr("title", function(d2) {
-          if (d2.isMixed) {
-            return _t("inspector.unshared_value_tooltip");
-          }
-          if (!["yes", "no"].includes(d2.state)) {
-            return d2.state;
-          }
-          return null;
-        }).classed("negated", (d2) => d2.state === "no");
-        if (!_isSemi) {
-          chips.selectAll("input[type=checkbox]").remove();
-          chips.insert("input", "span").attr("type", "checkbox").property("checked", (d2) => d2.state === "yes").property("indeterminate", (d2) => d2.isMixed || !["yes", "no"].includes(d2.state)).on("click", invertMultikey);
-        }
-        if (allowDragAndDrop) {
-          registerDragAndDrop(chips);
-        }
-        chips.each(function(d2) {
-          const selection2 = select_default2(this);
-          const text_span = selection2.select("span");
-          const field_buttons2 = selection2.select(".field_buttons");
-          const clean_value = d2.value.trim();
-          text_span.text("");
-          if (!field_buttons2.select("button").empty()) {
-            field_buttons2.select("button").remove();
-          }
-          if (clean_value.startsWith("https://")) {
-            text_span.text(clean_value);
-            field_buttons2.append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", () => _t("icons.visit_website")).attr("aria-label", () => _t("icons.visit_website")).on("click", function(d3_event) {
-              d3_event.preventDefault();
-              window.open(clean_value, "_blank");
-            });
-            return;
-          }
-          if (d2.display) {
-            d2.display(text_span);
-            return;
-          }
-          text_span.text(d2.value);
-        });
-        chips.select("a.remove").attr("href", "#").on("click", removeMultikey).attr("class", "remove").text("\xD7");
-        updateIcon("");
-      } else {
-        var mixedValues = isMixed && tags[field.key].map(function(val) {
-          return displayValue(val);
-        }).filter(Boolean);
-        utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : "").data([tags[field.key]]).classed("raw-value", isRawValue).classed("known-value", isKnownValue).attr("readonly", isReadOnly ? "readonly" : void 0).attr("title", isMixed ? mixedValues.join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : _staticPlaceholder || "").classed("mixed", isMixed).on("keydown.deleteCapture", function(d3_event) {
-          if (isReadOnly && isKnownValue(tags[field.key]) && (d3_event.keyCode === utilKeybinding.keyCodes["\u232B"] || d3_event.keyCode === utilKeybinding.keyCodes["\u2326"])) {
-            d3_event.preventDefault();
-            d3_event.stopPropagation();
-            var t2 = {};
-            t2[field.key] = void 0;
-            dispatch14.call("change", this, t2);
-          }
-        });
-        if (!Array.isArray(tags[field.key])) {
-          updateIcon(tags[field.key]);
-        }
-        if (!isMixed) {
-          _lengthIndicator.update(tags[field.key]);
-        }
-      }
-      const refreshStyles = () => {
-        _input.data([tagValue(utilGetSetValue(_input))]).classed("raw-value", isRawValue).classed("known-value", isKnownValue);
-      };
-      _input.on("input.refreshStyles", refreshStyles);
-      _combobox.on("update.refreshStyles", refreshStyles);
-      refreshStyles();
-    };
-    function registerDragAndDrop(selection2) {
-      var dragOrigin, targetIndex;
-      selection2.call(
-        drag_default().on("start", function(d3_event) {
-          dragOrigin = {
-            x: d3_event.x,
-            y: d3_event.y
-          };
-          targetIndex = null;
-        }).on("drag", function(d3_event) {
-          var x2 = d3_event.x - dragOrigin.x, y2 = d3_event.y - dragOrigin.y;
-          if (!select_default2(this).classed("dragging") && // don't display drag until dragging beyond a distance threshold
-          Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2)) <= 5)
-            return;
-          var index = selection2.nodes().indexOf(this);
-          select_default2(this).classed("dragging", true);
-          targetIndex = null;
-          var targetIndexOffsetTop = null;
-          var draggedTagWidth = select_default2(this).node().offsetWidth;
-          if (field.key === "destination" || field.key === "via") {
-            _container.selectAll(".chip").style("transform", function(d2, index2) {
-              var node = select_default2(this).node();
-              if (index === index2) {
-                return "translate(" + x2 + "px, " + y2 + "px)";
-              } else if (index2 > index && d3_event.y > node.offsetTop) {
-                if (targetIndex === null || index2 > targetIndex) {
-                  targetIndex = index2;
-                }
-                return "translateY(-100%)";
-              } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
-                if (targetIndex === null || index2 < targetIndex) {
-                  targetIndex = index2;
-                }
-                return "translateY(100%)";
-              }
-              return null;
-            });
-          } else {
-            _container.selectAll(".chip").each(function(d2, index2) {
-              var node = select_default2(this).node();
-              if (index !== index2 && d3_event.x < node.offsetLeft + node.offsetWidth + 5 && d3_event.x > node.offsetLeft && d3_event.y < node.offsetTop + node.offsetHeight && d3_event.y > node.offsetTop) {
-                targetIndex = index2;
-                targetIndexOffsetTop = node.offsetTop;
-              }
-            }).style("transform", function(d2, index2) {
-              var node = select_default2(this).node();
-              if (index === index2) {
-                return "translate(" + x2 + "px, " + y2 + "px)";
-              }
-              if (node.offsetTop === targetIndexOffsetTop) {
-                if (index2 < index && index2 >= targetIndex) {
-                  return "translateX(" + draggedTagWidth + "px)";
-                } else if (index2 > index && index2 <= targetIndex) {
-                  return "translateX(-" + draggedTagWidth + "px)";
-                }
-              }
-              return null;
-            });
-          }
-        }).on("end", function() {
-          if (!select_default2(this).classed("dragging")) {
-            return;
-          }
-          var index = selection2.nodes().indexOf(this);
-          select_default2(this).classed("dragging", false);
-          _container.selectAll(".chip").style("transform", null);
-          if (typeof targetIndex === "number") {
-            var element = _multiData[index];
-            _multiData.splice(index, 1);
-            _multiData.splice(targetIndex, 0, element);
-            var t2 = {};
-            if (_multiData.length) {
-              t2[field.key] = _multiData.map(function(element2) {
-                return element2.key;
-              }).join(";");
-            } else {
-              t2[field.key] = void 0;
+      context.on("enter.map", function() {
+        if (!map2.editableDataEnabled(
+          true
+          /* skip zoom check */
+        )) return;
+        if (_isTransformed) return;
+        var graph = context.graph();
+        var selectedAndParents = {};
+        context.selectedIDs().forEach(function(id2) {
+          var entity = graph.hasEntity(id2);
+          if (entity) {
+            selectedAndParents[entity.id] = entity;
+            if (entity.type === "node") {
+              graph.parentWays(entity).forEach(function(parent) {
+                selectedAndParents[parent.id] = parent;
+              });
             }
-            dispatch14.call("change", this, t2);
           }
-          dragOrigin = void 0;
-          targetIndex = void 0;
-        })
-      );
-    }
-    combo.focus = function() {
-      _input.node().focus();
-    };
-    combo.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return combo;
-    };
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
-    }
-    return utilRebind(combo, dispatch14, "on");
-  }
-
-  // modules/ui/fields/input.js
-  var likelyRawNumberFormat = /^-?(0\.\d*|\d*\.\d{0,2}(\d{4,})?|\d{4,}\.\d{3})$/;
-  function uiFieldText(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var input = select_default2(null);
-    var outlinkButton = select_default2(null);
-    var wrap2 = select_default2(null);
-    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
-    var _entityIDs = [];
-    var _tags;
-    var _phoneFormats = {};
-    const isDirectionField = field.key.split(":").some((keyPart) => keyPart === "direction");
-    const formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
-    const parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
-    const countDecimalPlaces = _mainLocalizer.decimalPlaceCounter(_mainLocalizer.languageCode());
-    if (field.type === "tel") {
-      _mainFileFetcher.get("phone_formats").then(function(d2) {
-        _phoneFormats = d2;
-        updatePhonePlaceholder();
-      }).catch(function() {
-      });
-    }
-    function calcLocked() {
-      var isLocked = (field.id === "brand" || field.id === "network" || field.id === "operator" || field.id === "flag") && _entityIDs.length && _entityIDs.some(function(entityID) {
-        var entity = context.graph().hasEntity(entityID);
-        if (!entity)
-          return false;
-        if (entity.tags.wikidata)
-          return true;
-        var preset = _mainPresetIndex.match(entity, context.graph());
-        var isSuggestion = preset && preset.suggestion;
-        var which = field.id;
-        return isSuggestion && !!entity.tags[which] && !!entity.tags[which + ":wikidata"];
+        });
+        var data = Object.values(selectedAndParents);
+        var filter2 = function(d2) {
+          return d2.id in selectedAndParents;
+        };
+        data = context.features().filter(data, graph);
+        surface.call(drawVertices.drawSelected, graph, map2.extent()).call(drawLines, graph, data, filter2).call(drawAreas, graph, data, filter2).call(drawMidpoints, graph, data, filter2, map2.trimmedExtent());
+        dispatch14.call("drawn", this, { full: false });
+        scheduleRedraw();
       });
-      field.locked(isLocked);
+      map2.dimensions(utilGetDimensions(selection2));
     }
-    function i3(selection2) {
-      calcLocked();
-      var isLocked = field.locked();
-      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      input = wrap2.selectAll("input").data([0]);
-      input = input.enter().append("input").attr("type", field.type === "identifier" ? "text" : field.type).attr("id", field.domId).classed(field.type, true).call(utilNoAuto).merge(input);
-      input.classed("disabled", !!isLocked).attr("readonly", isLocked || null).on("input", change(true)).on("blur", change()).on("change", change());
-      wrap2.call(_lengthIndicator);
-      if (field.type === "tel") {
-        updatePhonePlaceholder();
-      } else if (field.type === "number") {
-        var rtl = _mainLocalizer.textDirection() === "rtl";
-        input.attr("type", "text");
-        var inc = field.increment;
-        var buttons = wrap2.selectAll(".increment, .decrement").data(rtl ? [inc, -inc] : [-inc, inc]);
-        buttons.enter().append("button").attr("class", function(d2) {
-          var which = d2 > 0 ? "increment" : "decrement";
-          return "form-field-button " + which;
-        }).attr("title", function(d2) {
-          var which = d2 > 0 ? "increment" : "decrement";
-          return _t("inspector.".concat(which));
-        }).merge(buttons).on("click", function(d3_event, d2) {
-          d3_event.preventDefault();
-          var isMixed = Array.isArray(_tags[field.key]);
-          if (isMixed)
-            return;
-          var raw_vals = input.node().value || "0";
-          var vals = raw_vals.split(";");
-          vals = vals.map(function(v2) {
-            v2 = v2.trim();
-            const isRawNumber = likelyRawNumberFormat.test(v2);
-            var num = isRawNumber ? parseFloat(v2) : parseLocaleFloat(v2);
-            if (isDirectionField) {
-              const compassDir = cardinal[v2.toLowerCase()];
-              if (compassDir !== void 0) {
-                num = compassDir;
-              }
-            }
-            if (!isFinite(num))
-              return v2;
-            num = parseFloat(num);
-            if (!isFinite(num))
-              return v2;
-            num += d2;
-            if (isDirectionField) {
-              num = (num % 360 + 360) % 360;
-            }
-            return formatFloat(clamped(num), isRawNumber ? v2.includes(".") ? v2.split(".")[1].length : 0 : countDecimalPlaces(v2));
-          });
-          input.node().value = vals.join(";");
-          change()();
-        });
-      } else if (field.type === "identifier" && field.urlFormat && field.pattern) {
-        input.attr("type", "text");
-        outlinkButton = wrap2.selectAll(".foreign-id-permalink").data([0]);
-        outlinkButton = outlinkButton.enter().append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", function() {
-          var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
-          if (domainResults.length >= 2 && domainResults[1]) {
-            var domain = domainResults[1];
-            return _t("icons.view_on", { domain });
+    function zoomEventFilter(d3_event) {
+      if (d3_event.type === "mousedown") {
+        var hasOrphan = false;
+        var listeners = window.__on;
+        for (var i3 = 0; i3 < listeners.length; i3++) {
+          var listener = listeners[i3];
+          if (listener.name === "zoom" && listener.type === "mouseup") {
+            hasOrphan = true;
+            break;
           }
-          return "";
-        }).merge(outlinkButton);
-        outlinkButton.on("click", function(d3_event) {
-          d3_event.preventDefault();
-          var value = validIdentifierValueForLink();
-          if (value) {
-            var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
-            window.open(url, "_blank");
+        }
+        if (hasOrphan) {
+          var event = window.CustomEvent;
+          if (event) {
+            event = new event("mouseup");
+          } else {
+            event = window.document.createEvent("Event");
+            event.initEvent("mouseup", false, false);
           }
-        }).classed("disabled", () => !validIdentifierValueForLink()).merge(outlinkButton);
-      } else if (field.type === "url") {
-        input.attr("type", "text");
-        outlinkButton = wrap2.selectAll(".foreign-id-permalink").data([0]);
-        outlinkButton.enter().append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", () => _t("icons.visit_website")).on("click", function(d3_event) {
-          d3_event.preventDefault();
-          const value = validIdentifierValueForLink();
-          if (value)
-            window.open(value, "_blank");
-        }).merge(outlinkButton);
-      } else if (field.type === "colour") {
-        input.attr("type", "text");
-        updateColourPreview();
-      } else if (field.type === "date") {
-        input.attr("type", "text");
-        updateDateField();
+          event.view = window;
+          window.dispatchEvent(event);
+        }
       }
+      return d3_event.button !== 2;
     }
-    function updateColourPreview() {
-      wrap2.selectAll(".colour-preview").remove();
-      const colour = utilGetSetValue(input);
-      if (!isColourValid(colour) && colour !== "") {
-        wrap2.selectAll("input.colour-selector").remove();
-        wrap2.selectAll(".form-field-button").remove();
-        return;
-      }
-      var colourSelector = wrap2.selectAll(".colour-selector").data([0]);
-      colourSelector.enter().append("input").attr("type", "color").attr("class", "colour-selector").on("input", debounce_default(function(d3_event) {
-        d3_event.preventDefault();
-        var colour2 = this.value;
-        if (!isColourValid(colour2))
-          return;
-        utilGetSetValue(input, this.value);
-        change()();
-        updateColourPreview();
-      }, 100));
-      wrap2.selectAll("input.colour-selector").attr("value", colour);
-      var chooserButton = wrap2.selectAll(".colour-preview").data([colour]);
-      chooserButton = chooserButton.enter().append("div").attr("class", "form-field-button colour-preview").append("div").style("background-color", (d2) => d2).attr("class", "colour-box");
-      if (colour === "") {
-        chooserButton = chooserButton.call(svgIcon("#iD-icon-edit"));
-      }
-      chooserButton.on("click", () => wrap2.select(".colour-selector").node().showPicker());
+    function pxCenter() {
+      return [_dimensions[0] / 2, _dimensions[1] / 2];
     }
-    function updateDateField() {
-      function isDateValid(date2) {
-        return date2.match(/^[0-9]{4}(-[0-9]{2}(-[0-9]{2})?)?$/);
-      }
-      const date = utilGetSetValue(input);
-      const now3 = /* @__PURE__ */ new Date();
-      const today = new Date(now3.getTime() - now3.getTimezoneOffset() * 6e4).toISOString().split("T")[0];
-      if ((field.key === "check_date" || field.key === "survey:date") && date !== today) {
-        wrap2.selectAll(".date-set-today").data([0]).enter().append("button").attr("class", "form-field-button date-set-today").call(svgIcon("#fas-rotate")).call(uiTooltip().title(() => _t.append("inspector.set_today"))).on("click", () => {
-          utilGetSetValue(input, today);
-          change()();
-          updateDateField();
+    function drawEditable(difference2, extent) {
+      var mode = context.mode();
+      var graph = context.graph();
+      var features = context.features();
+      var all = context.history().intersects(map2.extent());
+      var fullRedraw = false;
+      var data;
+      var set4;
+      var filter2;
+      var applyFeatureLayerFilters = true;
+      if (map2.isInWideSelection()) {
+        data = [];
+        utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function(id2) {
+          var entity = context.hasEntity(id2);
+          if (entity) data.push(entity);
         });
+        fullRedraw = true;
+        filter2 = utilFunctor(true);
+        applyFeatureLayerFilters = false;
+      } else if (difference2) {
+        var complete = difference2.complete(map2.extent());
+        data = Object.values(complete).filter(Boolean);
+        set4 = new Set(Object.keys(complete));
+        filter2 = function(d2) {
+          return set4.has(d2.id);
+        };
+        features.clear(data);
       } else {
-        wrap2.selectAll(".date-set-today").remove();
+        if (features.gatherStats(all, graph, _dimensions)) {
+          extent = void 0;
+        }
+        if (extent) {
+          data = context.history().intersects(map2.extent().intersection(extent));
+          set4 = new Set(data.map(function(entity) {
+            return entity.id;
+          }));
+          filter2 = function(d2) {
+            return set4.has(d2.id);
+          };
+        } else {
+          data = all;
+          fullRedraw = true;
+          filter2 = utilFunctor(true);
+        }
       }
-      if (!isDateValid(date) && date !== "") {
-        wrap2.selectAll("input.date-selector").remove();
-        wrap2.selectAll(".date-calendar").remove();
-        return;
+      if (applyFeatureLayerFilters) {
+        data = features.filter(data, graph);
+      } else {
+        context.features().resetStats();
       }
-      if (utilDetect().browser !== "Safari") {
-        var dateSelector = wrap2.selectAll(".date-selector").data([0]);
-        dateSelector.enter().append("input").attr("type", "date").attr("class", "date-selector").on("input", debounce_default(function(d3_event) {
-          d3_event.preventDefault();
-          var date2 = this.value;
-          if (!isDateValid(date2))
-            return;
-          utilGetSetValue(input, this.value);
-          change()();
-          updateDateField();
-        }, 100));
-        wrap2.selectAll("input.date-selector").attr("value", date);
-        var calendarButton = wrap2.selectAll(".date-calendar").data([date]);
-        calendarButton = calendarButton.enter().append("button").attr("class", "form-field-button date-calendar").call(svgIcon("#fas-calendar-days"));
-        calendarButton.on("click", () => wrap2.select(".date-selector").node().showPicker());
+      if (mode && mode.id === "select") {
+        surface.call(drawVertices.drawSelected, graph, map2.extent());
       }
+      surface.call(drawVertices, graph, data, filter2, map2.extent(), fullRedraw).call(drawLines, graph, data, filter2).call(drawAreas, graph, data, filter2).call(drawMidpoints, graph, data, filter2, map2.trimmedExtent()).call(drawLabels, graph, data, filter2, _dimensions, fullRedraw).call(drawPoints, graph, data, filter2);
+      dispatch14.call("drawn", this, { full: true });
     }
-    function updatePhonePlaceholder() {
-      if (input.empty() || !Object.keys(_phoneFormats).length)
-        return;
-      var extent = combinedEntityExtent();
-      var countryCode = extent && iso1A2Code(extent.center());
-      var format2 = countryCode && _phoneFormats[countryCode.toLowerCase()];
-      if (format2)
-        input.attr("placeholder", format2);
-    }
-    function validIdentifierValueForLink() {
-      var _a2;
-      const value = utilGetSetValue(input).trim();
-      if (field.type === "url" && value) {
-        try {
-          return new URL(value).href;
-        } catch {
-          return null;
-        }
-      }
-      if (field.type === "identifier" && field.pattern) {
-        return value && ((_a2 = value.match(new RegExp(field.pattern))) == null ? void 0 : _a2[0]);
+    map2.init = function() {
+      drawLayers = svgLayers(projection2, context);
+      drawPoints = svgPoints(projection2, context);
+      drawVertices = svgVertices(projection2, context);
+      drawLines = svgLines(projection2, context);
+      drawAreas = svgAreas(projection2, context);
+      drawMidpoints = svgMidpoints(projection2, context);
+      drawLabels = svgLabels(projection2, context);
+    };
+    function editOff() {
+      context.features().resetStats();
+      surface.selectAll(".layer-osm *").remove();
+      surface.selectAll(".layer-touch:not(.markers) *").remove();
+      var allowed = {
+        "browse": true,
+        "save": true,
+        "select-note": true,
+        "select-data": true,
+        "select-error": true
+      };
+      var mode = context.mode();
+      if (mode && !allowed[mode.id]) {
+        context.enter(modeBrowse(context));
       }
-      return null;
+      dispatch14.call("drawn", this, { full: true });
     }
-    function clamped(num) {
-      if (field.minValue !== void 0) {
-        num = Math.max(num, field.minValue);
+    function gestureChange(d3_event) {
+      var e3 = d3_event;
+      e3.preventDefault();
+      var props = {
+        deltaMode: 0,
+        // dummy values to ignore in zoomPan
+        deltaY: 1,
+        // dummy values to ignore in zoomPan
+        clientX: e3.clientX,
+        clientY: e3.clientY,
+        screenX: e3.screenX,
+        screenY: e3.screenY,
+        x: e3.x,
+        y: e3.y
+      };
+      var e22 = new WheelEvent("wheel", props);
+      e22._scale = e3.scale;
+      e22._rotation = e3.rotation;
+      _selection.node().dispatchEvent(e22);
+    }
+    function zoomPan2(event, key, transform2) {
+      var source = event && event.sourceEvent || event;
+      var eventTransform = transform2 || event && event.transform;
+      var x2 = eventTransform.x;
+      var y2 = eventTransform.y;
+      var k2 = eventTransform.k;
+      if (source && source.type === "wheel") {
+        if (_pointerDown) return;
+        var detected = utilDetect();
+        var dX = source.deltaX;
+        var dY = source.deltaY;
+        var x22 = x2;
+        var y22 = y2;
+        var k22 = k2;
+        var t0, p02, p1;
+        if (source.deltaMode === 1) {
+          var lines = Math.abs(source.deltaY);
+          var sign2 = source.deltaY > 0 ? 1 : -1;
+          dY = sign2 * clamp2(
+            Math.exp((lines - 1) * 0.75) * 4.000244140625,
+            4.000244140625,
+            // min
+            350.000244140625
+            // max
+          );
+          if (detected.os !== "mac") {
+            dY *= 5;
+          }
+          t0 = _isTransformed ? _transformLast : _transformStart;
+          p02 = _getMouseCoords(source);
+          p1 = t0.invert(p02);
+          k22 = t0.k * Math.pow(2, -dY / 500);
+          k22 = clamp2(k22, kMin, kMax);
+          x22 = p02[0] - p1[0] * k22;
+          y22 = p02[1] - p1[1] * k22;
+        } else if (source._scale) {
+          t0 = _gestureTransformStart;
+          p02 = _getMouseCoords(source);
+          p1 = t0.invert(p02);
+          k22 = t0.k * source._scale;
+          k22 = clamp2(k22, kMin, kMax);
+          x22 = p02[0] - p1[0] * k22;
+          y22 = p02[1] - p1[1] * k22;
+        } else if (source.ctrlKey && !isInteger(dY)) {
+          dY *= 6;
+          t0 = _isTransformed ? _transformLast : _transformStart;
+          p02 = _getMouseCoords(source);
+          p1 = t0.invert(p02);
+          k22 = t0.k * Math.pow(2, -dY / 500);
+          k22 = clamp2(k22, kMin, kMax);
+          x22 = p02[0] - p1[0] * k22;
+          y22 = p02[1] - p1[1] * k22;
+        } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
+          t0 = _isTransformed ? _transformLast : _transformStart;
+          p02 = _getMouseCoords(source);
+          p1 = t0.invert(p02);
+          k22 = t0.k * Math.pow(2, -dY / 500);
+          k22 = clamp2(k22, kMin, kMax);
+          x22 = p02[0] - p1[0] * k22;
+          y22 = p02[1] - p1[1] * k22;
+        } else if (detected.os === "mac" && detected.browser !== "Firefox" && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
+          p1 = projection2.translate();
+          x22 = p1[0] - dX;
+          y22 = p1[1] - dY;
+          k22 = projection2.scale();
+          k22 = clamp2(k22, kMin, kMax);
+        }
+        if (x22 !== x2 || y22 !== y2 || k22 !== k2) {
+          x2 = x22;
+          y2 = y22;
+          k2 = k22;
+          eventTransform = identity2.translate(x22, y22).scale(k22);
+          if (_zoomerPanner._transform) {
+            _zoomerPanner._transform(eventTransform);
+          } else {
+            _selection.node().__zoom = eventTransform;
+          }
+        }
       }
-      if (field.maxValue !== void 0) {
-        num = Math.min(num, field.maxValue);
+      if (_transformStart.x === x2 && _transformStart.y === y2 && _transformStart.k === k2) {
+        return;
+      }
+      if (geoScaleToZoom(k2, TILESIZE) < _minzoom) {
+        surface.interrupt();
+        dispatch14.call("hitMinZoom", this, map2);
+        setCenterZoom(map2.center(), context.minEditableZoom(), 0, true);
+        scheduleRedraw();
+        dispatch14.call("move", this, map2);
+        return;
+      }
+      projection2.transform(eventTransform);
+      var withinEditableZoom = map2.withinEditableZoom();
+      if (_lastWithinEditableZoom !== withinEditableZoom) {
+        if (_lastWithinEditableZoom !== void 0) {
+          dispatch14.call("crossEditableZoom", this, withinEditableZoom);
+        }
+        _lastWithinEditableZoom = withinEditableZoom;
+      }
+      var scale = k2 / _transformStart.k;
+      var tX = (x2 / scale - _transformStart.x) * scale;
+      var tY = (y2 / scale - _transformStart.y) * scale;
+      if (context.inIntro()) {
+        curtainProjection.transform({
+          x: x2 - tX,
+          y: y2 - tY,
+          k: k2
+        });
+      }
+      if (source) {
+        _lastPointerEvent = event;
+      }
+      _isTransformed = true;
+      _transformLast = eventTransform;
+      utilSetTransform(supersurface, tX, tY, scale);
+      scheduleRedraw();
+      dispatch14.call("move", this, map2);
+      function isInteger(val) {
+        return typeof val === "number" && isFinite(val) && Math.floor(val) === val;
       }
-      return num;
     }
-    function getVals(tags) {
-      if (field.keys) {
-        const multiSelection = context.selectedIDs();
-        tags = multiSelection.length > 1 ? context.selectedIDs().map((id2) => context.graph().entity(id2)).map((entity) => entity.tags) : [tags];
-        return tags.map((tags2) => new Set(field.keys.reduce((acc, key) => acc.concat(tags2[key]), []).filter(Boolean))).map((vals) => vals.size === 0 ? /* @__PURE__ */ new Set([void 0]) : vals).reduce((a2, b2) => /* @__PURE__ */ new Set([...a2, ...b2]));
-      } else {
-        return new Set([].concat(tags[field.key]));
+    function resetTransform() {
+      if (!_isTransformed) return false;
+      utilSetTransform(supersurface, 0, 0);
+      _isTransformed = false;
+      if (context.inIntro()) {
+        curtainProjection.transform(projection2.transform());
       }
+      return true;
     }
-    function change(onInput) {
-      return function() {
-        var t2 = {};
-        var val = utilGetSetValue(input);
-        if (!onInput)
-          val = context.cleanTagValue(val);
-        if (!val && getVals(_tags).size > 1)
-          return;
-        var displayVal = val;
-        if (field.type === "number" && val) {
-          var numbers2 = val.split(";");
-          numbers2 = numbers2.map(function(v2) {
-            if (likelyRawNumberFormat.test(v2)) {
-              return v2;
-            }
-            var num = parseLocaleFloat(v2);
-            const fractionDigits = countDecimalPlaces(v2);
-            return isFinite(num) ? clamped(num).toFixed(fractionDigits) : v2;
-          });
-          val = numbers2.join(";");
-        }
-        if (!onInput)
-          utilGetSetValue(input, displayVal);
-        t2[field.key] = val || void 0;
-        if (field.keys) {
-          dispatch14.call("change", this, (tags) => {
-            if (field.keys.some((key) => tags[key])) {
-              field.keys.filter((key) => tags[key]).forEach((key) => {
-                tags[key] = val || void 0;
-              });
-            } else {
-              tags[field.key] = val || void 0;
-            }
-            return tags;
-          }, onInput);
-        } else {
-          dispatch14.call("change", this, t2, onInput);
-        }
-      };
+    function redraw(difference2, extent) {
+      if (surface.empty() || !_redrawEnabled) return;
+      if (resetTransform()) {
+        difference2 = extent = void 0;
+      }
+      var zoom = map2.zoom();
+      var z2 = String(~~zoom);
+      if (surface.attr("data-zoom") !== z2) {
+        surface.attr("data-zoom", z2);
+      }
+      var lat = map2.center()[1];
+      var lowzoom = linear3().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
+      surface.classed("low-zoom", zoom <= lowzoom(lat));
+      if (!difference2) {
+        supersurface.call(context.background());
+        wrapper.call(drawLayers);
+      }
+      if (map2.editableDataEnabled() || map2.isInWideSelection()) {
+        context.loadTiles(projection2);
+        drawEditable(difference2, extent);
+      } else {
+        editOff();
+      }
+      _transformStart = projection2.transform();
+      return map2;
     }
-    i3.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return i3;
+    var immediateRedraw = function(difference2, extent) {
+      if (!difference2 && !extent) cancelPendingRedraw();
+      redraw(difference2, extent);
     };
-    i3.tags = function(tags) {
-      var _a2;
-      _tags = tags;
-      const vals = getVals(tags);
-      const isMixed = vals.size > 1;
-      var val = vals.size === 1 ? (_a2 = [...vals][0]) != null ? _a2 : "" : "";
-      var shouldUpdate;
-      if (field.type === "number" && val) {
-        var numbers2 = val.split(";");
-        var oriNumbers = utilGetSetValue(input).split(";");
-        if (numbers2.length !== oriNumbers.length)
-          shouldUpdate = true;
-        numbers2 = numbers2.map(function(v2) {
-          v2 = v2.trim();
-          var num = Number(v2);
-          if (!isFinite(num) || v2 === "")
-            return v2;
-          const fractionDigits = v2.includes(".") ? v2.split(".")[1].length : 0;
-          return formatFloat(num, fractionDigits);
-        });
-        val = numbers2.join(";");
-        shouldUpdate = (inputValue, setValue) => {
-          const inputNums = inputValue.split(";").map(
-            (setVal) => likelyRawNumberFormat.test(setVal) ? parseFloat(setVal) : parseLocaleFloat(setVal)
-          );
-          const setNums = setValue.split(";").map(parseLocaleFloat);
-          return !isEqual_default(inputNums, setNums);
-        };
-      }
-      utilGetSetValue(input, val, shouldUpdate).attr("title", isMixed ? [...vals].join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder() || _t("inspector.unknown")).classed("mixed", isMixed);
-      if (field.type === "number") {
-        const buttons = wrap2.selectAll(".increment, .decrement");
-        if (isMixed) {
-          buttons.attr("disabled", "disabled").classed("disabled", true);
-        } else {
-          var raw_vals = tags[field.key] || "0";
-          const canIncDec = raw_vals.split(";").some((val2) => isFinite(Number(val2)) || isDirectionField && cardinal[val2.trim().toLowerCase()]);
-          buttons.attr("disabled", canIncDec ? null : "disabled").classed("disabled", !canIncDec);
+    map2.lastPointerEvent = function() {
+      return _lastPointerEvent;
+    };
+    map2.mouse = function(d3_event) {
+      var event = d3_event || _lastPointerEvent;
+      if (event) {
+        var s2;
+        while (s2 = event.sourceEvent) {
+          event = s2;
         }
+        return _getMouseCoords(event);
       }
-      if (field.type === "tel")
-        updatePhonePlaceholder();
-      if (field.type === "colour")
-        updateColourPreview();
-      if (field.type === "date")
-        updateDateField();
-      if (outlinkButton && !outlinkButton.empty()) {
-        var disabled = !validIdentifierValueForLink();
-        outlinkButton.classed("disabled", disabled);
+      return null;
+    };
+    map2.mouseCoordinates = function() {
+      var coord2 = map2.mouse() || pxCenter();
+      return projection2.invert(coord2);
+    };
+    map2.dblclickZoomEnable = function(val) {
+      if (!arguments.length) return _dblClickZoomEnabled;
+      _dblClickZoomEnabled = val;
+      return map2;
+    };
+    map2.redrawEnable = function(val) {
+      if (!arguments.length) return _redrawEnabled;
+      _redrawEnabled = val;
+      return map2;
+    };
+    map2.isTransformed = function() {
+      return _isTransformed;
+    };
+    function setTransform(t2, duration, force) {
+      var t3 = projection2.transform();
+      if (!force && t2.k === t3.k && t2.x === t3.x && t2.y === t3.y) return false;
+      if (duration) {
+        _selection.transition().duration(duration).on("start", function() {
+          map2.startEase();
+        }).call(_zoomerPanner.transform, identity2.translate(t2.x, t2.y).scale(t2.k));
+      } else {
+        projection2.transform(t2);
+        _transformStart = t2;
+        _selection.call(_zoomerPanner.transform, _transformStart);
       }
-      if (!isMixed) {
-        _lengthIndicator.update(tags[field.key]);
+      return true;
+    }
+    function setCenterZoom(loc2, z2, duration, force) {
+      var c2 = map2.center();
+      var z3 = map2.zoom();
+      if (loc2[0] === c2[0] && loc2[1] === c2[1] && z2 === z3 && !force) return false;
+      var proj = geoRawMercator().transform(projection2.transform());
+      var k2 = clamp2(geoZoomToScale(z2, TILESIZE), kMin, kMax);
+      proj.scale(k2);
+      var t2 = proj.translate();
+      var point = proj(loc2);
+      var center = pxCenter();
+      t2[0] += center[0] - point[0];
+      t2[1] += center[1] - point[1];
+      return setTransform(identity2.translate(t2[0], t2[1]).scale(k2), duration, force);
+    }
+    map2.pan = function(delta, duration) {
+      var t2 = projection2.translate();
+      var k2 = projection2.scale();
+      t2[0] += delta[0];
+      t2[1] += delta[1];
+      if (duration) {
+        _selection.transition().duration(duration).on("start", function() {
+          map2.startEase();
+        }).call(_zoomerPanner.transform, identity2.translate(t2[0], t2[1]).scale(k2));
+      } else {
+        projection2.translate(t2);
+        _transformStart = projection2.transform();
+        _selection.call(_zoomerPanner.transform, _transformStart);
+        dispatch14.call("move", this, map2);
+        immediateRedraw();
       }
+      return map2;
     };
-    i3.focus = function() {
-      var node = input.node();
-      if (node)
-        node.focus();
+    map2.dimensions = function(val) {
+      if (!arguments.length) return _dimensions;
+      _dimensions = val;
+      drawLayers.dimensions(_dimensions);
+      context.background().dimensions(_dimensions);
+      projection2.clipExtent([[0, 0], _dimensions]);
+      _getMouseCoords = utilFastMouse(supersurface.node());
+      scheduleRedraw();
+      return map2;
     };
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
-    }
-    return utilRebind(i3, dispatch14, "on");
-  }
-
-  // modules/ui/fields/access.js
-  function uiFieldAccess(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var items = select_default2(null);
-    var _tags;
-    function access(selection2) {
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var list2 = wrap2.selectAll("ul").data([0]);
-      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
-      items = list2.selectAll("li").data(field.keys);
-      var enter = items.enter().append("li").attr("class", function(d2) {
-        return "labeled-input preset-access-" + d2;
-      });
-      enter.append("div").attr("class", "label preset-label-access").attr("for", function(d2) {
-        return "preset-input-access-" + d2;
-      }).html(function(d2) {
-        return field.t.html("types." + d2);
-      });
-      enter.append("div").attr("class", "preset-input-access-wrap").append("input").attr("type", "text").attr("class", function(d2) {
-        return "preset-input-access preset-input-access-" + d2;
-      }).call(utilNoAuto).each(function(d2) {
-        select_default2(this).call(
-          uiCombobox(context, "access-" + d2).data(access.options(d2))
-        );
-      });
-      items = items.merge(enter);
-      wrap2.selectAll(".preset-input-access").on("change", change).on("blur", change);
+    function zoomIn(delta) {
+      setCenterZoom(map2.center(), ~~map2.zoom() + delta, 250, true);
     }
-    function change(d3_event, d2) {
-      var tag2 = {};
-      var value = context.cleanTagValue(utilGetSetValue(select_default2(this)));
-      if (!value && typeof _tags[d2] !== "string")
-        return;
-      tag2[d2] = value || void 0;
-      dispatch14.call("change", this, tag2);
+    function zoomOut(delta) {
+      setCenterZoom(map2.center(), ~~map2.zoom() - delta, 250, true);
     }
-    access.options = function(type2) {
-      var options2 = [
-        "yes",
-        "no",
-        "designated",
-        "permissive",
-        "destination",
-        "customers",
-        "private",
-        "permit",
-        "unknown"
-      ];
-      if (type2 === "access") {
-        options2 = options2.filter((v2) => v2 !== "yes" && v2 !== "designated");
+    map2.zoomIn = function() {
+      zoomIn(1);
+    };
+    map2.zoomInFurther = function() {
+      zoomIn(4);
+    };
+    map2.canZoomIn = function() {
+      return map2.zoom() < maxZoom;
+    };
+    map2.zoomOut = function() {
+      zoomOut(1);
+    };
+    map2.zoomOutFurther = function() {
+      zoomOut(4);
+    };
+    map2.canZoomOut = function() {
+      return map2.zoom() > minZoom2;
+    };
+    map2.center = function(loc2) {
+      if (!arguments.length) {
+        return projection2.invert(pxCenter());
       }
-      if (type2 === "bicycle") {
-        options2.splice(options2.length - 4, 0, "dismount");
+      if (setCenterZoom(loc2, map2.zoom())) {
+        dispatch14.call("move", this, map2);
       }
-      var stringsField = field.resolveReference("stringsCrossReference");
-      return options2.map(function(option) {
-        return {
-          title: stringsField.t("options." + option + ".description"),
-          value: option
-        };
-      });
+      scheduleRedraw();
+      return map2;
     };
-    const placeholdersByTag = {
-      highway: {
-        footway: {
-          foot: "designated",
-          motor_vehicle: "no"
-        },
-        steps: {
-          foot: "yes",
-          motor_vehicle: "no",
-          bicycle: "no",
-          horse: "no"
-        },
-        pedestrian: {
-          foot: "yes",
-          motor_vehicle: "no"
-        },
-        cycleway: {
-          motor_vehicle: "no",
-          bicycle: "designated"
-        },
-        bridleway: {
-          motor_vehicle: "no",
-          horse: "designated"
-        },
-        path: {
-          foot: "yes",
-          motor_vehicle: "no",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        motorway: {
-          foot: "no",
-          motor_vehicle: "yes",
-          bicycle: "no",
-          horse: "no"
-        },
-        trunk: {
-          motor_vehicle: "yes"
-        },
-        primary: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        secondary: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        tertiary: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        residential: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        unclassified: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        service: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        motorway_link: {
-          foot: "no",
-          motor_vehicle: "yes",
-          bicycle: "no",
-          horse: "no"
-        },
-        trunk_link: {
-          motor_vehicle: "yes"
-        },
-        primary_link: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        secondary_link: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        tertiary_link: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        construction: {
-          access: "no"
-        },
-        busway: {
-          access: "no",
-          bus: "designated",
-          emergency: "yes"
-        }
-      },
-      barrier: {
-        bollard: {
-          access: "no",
-          bicycle: "yes",
-          foot: "yes"
-        },
-        bus_trap: {
-          motor_vehicle: "no",
-          psv: "yes",
-          foot: "yes",
-          bicycle: "yes"
-        },
-        city_wall: {
-          access: "no"
-        },
-        coupure: {
-          access: "yes"
-        },
-        cycle_barrier: {
-          motor_vehicle: "no"
-        },
-        ditch: {
-          access: "no"
-        },
-        entrance: {
-          access: "yes"
-        },
-        fence: {
-          access: "no"
-        },
-        hedge: {
-          access: "no"
-        },
-        jersey_barrier: {
-          access: "no"
-        },
-        motorcycle_barrier: {
-          motor_vehicle: "no"
-        },
-        rail_guard: {
-          access: "no"
-        }
+    map2.unobscuredCenterZoomEase = function(loc, zoom) {
+      var offset = map2.unobscuredOffsetPx();
+      var proj = geoRawMercator().transform(projection2.transform());
+      proj.scale(geoZoomToScale(zoom, TILESIZE));
+      var locPx = proj(loc);
+      var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
+      var offsetLoc = proj.invert(offsetLocPx);
+      map2.centerZoomEase(offsetLoc, zoom);
+    };
+    map2.unobscuredOffsetPx = function() {
+      var openPane = context.container().select(".map-panes .map-pane.shown");
+      if (!openPane.empty()) {
+        return [openPane.node().offsetWidth / 2, 0];
       }
+      return [0, 0];
     };
-    access.tags = function(tags) {
-      _tags = tags;
-      utilGetSetValue(items.selectAll(".preset-input-access"), function(d2) {
-        return typeof tags[d2] === "string" ? tags[d2] : "";
-      }).classed("mixed", function(d2) {
-        return tags[d2] && Array.isArray(tags[d2]);
-      }).attr("title", function(d2) {
-        return tags[d2] && Array.isArray(tags[d2]) && tags[d2].filter(Boolean).join("\n");
-      }).attr("placeholder", function(d2) {
-        if (tags[d2] && Array.isArray(tags[d2])) {
-          return _t("inspector.multiple_values");
-        }
-        if (d2 === "bicycle" || d2 === "motor_vehicle") {
-          if (tags.vehicle && typeof tags.vehicle === "string") {
-            return tags.vehicle;
-          }
-        }
-        if (tags.access && typeof tags.access === "string") {
-          return tags.access;
-        }
-        function getPlaceholdersByTag(key, placeholdersByKey) {
-          if (typeof tags[key] === "string") {
-            if (placeholdersByKey[tags[key]] && placeholdersByKey[tags[key]][d2]) {
-              return placeholdersByKey[tags[key]][d2];
-            }
+    map2.zoom = function(z2) {
+      if (!arguments.length) {
+        return Math.max(geoScaleToZoom(projection2.scale(), TILESIZE), 0);
+      }
+      if (z2 < _minzoom) {
+        surface.interrupt();
+        dispatch14.call("hitMinZoom", this, map2);
+        z2 = context.minEditableZoom();
+      }
+      if (setCenterZoom(map2.center(), z2)) {
+        dispatch14.call("move", this, map2);
+      }
+      scheduleRedraw();
+      return map2;
+    };
+    map2.centerZoom = function(loc2, z2) {
+      if (setCenterZoom(loc2, z2)) {
+        dispatch14.call("move", this, map2);
+      }
+      scheduleRedraw();
+      return map2;
+    };
+    map2.zoomTo = function(entities) {
+      if (!isArray_default(entities)) {
+        entities = [entities];
+      }
+      if (entities.length === 0) return map2;
+      var extent = entities.map((entity) => entity.extent(context.graph())).reduce((a2, b2) => a2.extend(b2));
+      if (!isFinite(extent.area())) return map2;
+      var z2 = clamp2(map2.trimmedExtentZoom(extent), 0, 20);
+      return map2.centerZoom(extent.center(), z2);
+    };
+    map2.centerEase = function(loc2, duration) {
+      duration = duration || 250;
+      setCenterZoom(loc2, map2.zoom(), duration);
+      return map2;
+    };
+    map2.zoomEase = function(z2, duration) {
+      duration = duration || 250;
+      setCenterZoom(map2.center(), z2, duration, false);
+      return map2;
+    };
+    map2.centerZoomEase = function(loc2, z2, duration) {
+      duration = duration || 250;
+      setCenterZoom(loc2, z2, duration, false);
+      return map2;
+    };
+    map2.transformEase = function(t2, duration) {
+      duration = duration || 250;
+      setTransform(
+        t2,
+        duration,
+        false
+        /* don't force */
+      );
+      return map2;
+    };
+    map2.zoomToEase = function(obj, duration) {
+      var extent;
+      if (Array.isArray(obj)) {
+        obj.forEach(function(entity) {
+          var entityExtent = entity.extent(context.graph());
+          if (!extent) {
+            extent = entityExtent;
           } else {
-            var impliedAccesses = tags[key].filter(Boolean).map(function(val) {
-              return placeholdersByKey[val] && placeholdersByKey[val][d2];
-            }).filter(Boolean);
-            if (impliedAccesses.length === tags[key].length && new Set(impliedAccesses).size === 1) {
-              return impliedAccesses[0];
-            }
-          }
-        }
-        for (const key in placeholdersByTag) {
-          if (tags[key]) {
-            const impliedAccess = getPlaceholdersByTag(key, placeholdersByTag[key]);
-            if (impliedAccess) {
-              return impliedAccess;
-            }
+            extent = extent.extend(entityExtent);
           }
-        }
-        if (d2 === "access" && !tags.barrier) {
-          return "yes";
-        }
-        return field.placeholder();
+        });
+      } else {
+        extent = obj.extent(context.graph());
+      }
+      if (!isFinite(extent.area())) return map2;
+      var z2 = clamp2(map2.trimmedExtentZoom(extent), 0, 20);
+      return map2.centerZoomEase(extent.center(), z2, duration);
+    };
+    map2.startEase = function() {
+      utilBindOnce(surface, _pointerPrefix + "down.ease", function() {
+        map2.cancelEase();
       });
+      return map2;
     };
-    access.focus = function() {
-      items.selectAll(".preset-input-access").node().focus();
+    map2.cancelEase = function() {
+      _selection.interrupt();
+      return map2;
     };
-    return utilRebind(access, dispatch14, "on");
+    map2.extent = function(val) {
+      if (!arguments.length) {
+        return new geoExtent(
+          projection2.invert([0, _dimensions[1]]),
+          projection2.invert([_dimensions[0], 0])
+        );
+      } else {
+        var extent = geoExtent(val);
+        map2.centerZoom(extent.center(), map2.extentZoom(extent));
+      }
+    };
+    map2.trimmedExtent = function(val) {
+      if (!arguments.length) {
+        var headerY = 71;
+        var footerY = 30;
+        var pad2 = 10;
+        return new geoExtent(
+          projection2.invert([pad2, _dimensions[1] - footerY - pad2]),
+          projection2.invert([_dimensions[0] - pad2, headerY + pad2])
+        );
+      } else {
+        var extent = geoExtent(val);
+        map2.centerZoom(extent.center(), map2.trimmedExtentZoom(extent));
+      }
+    };
+    function calcExtentZoom(extent, dim) {
+      var tl = projection2([extent[0][0], extent[1][1]]);
+      var br2 = projection2([extent[1][0], extent[0][1]]);
+      var hFactor = (br2[0] - tl[0]) / dim[0];
+      var vFactor = (br2[1] - tl[1]) / dim[1];
+      var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
+      var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
+      var newZoom = map2.zoom() - Math.max(hZoomDiff, vZoomDiff);
+      return newZoom;
+    }
+    map2.extentZoom = function(val) {
+      return calcExtentZoom(geoExtent(val), _dimensions);
+    };
+    map2.trimmedExtentZoom = function(val) {
+      var trimY = 120;
+      var trimX = 40;
+      var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
+      return calcExtentZoom(geoExtent(val), trimmed);
+    };
+    map2.withinEditableZoom = function() {
+      return map2.zoom() >= context.minEditableZoom();
+    };
+    map2.isInWideSelection = function() {
+      return !map2.withinEditableZoom() && context.selectedIDs().length;
+    };
+    map2.editableDataEnabled = function(skipZoomCheck) {
+      var layer = context.layers().layer("osm");
+      if (!layer || !layer.enabled()) return false;
+      return skipZoomCheck || map2.withinEditableZoom();
+    };
+    map2.notesEditable = function() {
+      var layer = context.layers().layer("notes");
+      if (!layer || !layer.enabled()) return false;
+      return map2.withinEditableZoom();
+    };
+    map2.minzoom = function(val) {
+      if (!arguments.length) return _minzoom;
+      _minzoom = val;
+      return map2;
+    };
+    map2.toggleHighlightEdited = function() {
+      surface.classed("highlight-edited", !surface.classed("highlight-edited"));
+      map2.pan([0, 0]);
+      dispatch14.call("changeHighlighting", this);
+    };
+    map2.areaFillOptions = ["wireframe", "partial", "full"];
+    map2.activeAreaFill = function(val) {
+      if (!arguments.length) return corePreferences("area-fill") || "partial";
+      corePreferences("area-fill", val);
+      if (val !== "wireframe") {
+        corePreferences("area-fill-toggle", val);
+      }
+      updateAreaFill();
+      map2.pan([0, 0]);
+      dispatch14.call("changeAreaFill", this);
+      return map2;
+    };
+    map2.toggleWireframe = function() {
+      var activeFill = map2.activeAreaFill();
+      if (activeFill === "wireframe") {
+        activeFill = corePreferences("area-fill-toggle") || "partial";
+      } else {
+        activeFill = "wireframe";
+      }
+      map2.activeAreaFill(activeFill);
+    };
+    function updateAreaFill() {
+      var activeFill = map2.activeAreaFill();
+      map2.areaFillOptions.forEach(function(opt) {
+        surface.classed("fill-" + opt, Boolean(opt === activeFill));
+      });
+    }
+    map2.layers = () => drawLayers;
+    map2.doubleUpHandler = function() {
+      return _doubleUpHandler;
+    };
+    return utilRebind(map2, dispatch14, "on");
   }
 
-  // modules/ui/fields/address.js
-  function uiFieldAddress(field, context) {
+  // modules/renderer/photos.js
+  function rendererPhotos(context) {
     var dispatch14 = dispatch_default("change");
-    var _selection = select_default2(null);
-    var _wrap = select_default2(null);
-    var addrField = _mainPresetIndex.field("address");
-    var _entityIDs = [];
-    var _tags;
-    var _countryCode;
-    var _addressFormats = [{
-      format: [
-        ["housenumber", "street"],
-        ["city", "postcode"]
-      ]
-    }];
-    _mainFileFetcher.get("address_formats").then(function(d2) {
-      _addressFormats = d2;
-      if (!_selection.empty()) {
-        _selection.call(address);
+    var _layerIDs = ["streetside", "mapillary", "mapillary-map-features", "mapillary-signs", "kartaview", "mapilio", "vegbilder", "panoramax"];
+    var _allPhotoTypes = ["flat", "panoramic"];
+    var _shownPhotoTypes = _allPhotoTypes.slice();
+    var _dateFilters = ["fromDate", "toDate"];
+    var _fromDate;
+    var _toDate;
+    var _usernames;
+    function photos() {
+    }
+    function updateStorage() {
+      if (window.mocha) return;
+      var hash = utilStringQs(window.location.hash);
+      var enabled = context.layers().all().filter(function(d2) {
+        return _layerIDs.indexOf(d2.id) !== -1 && d2.layer && d2.layer.supported() && d2.layer.enabled();
+      }).map(function(d2) {
+        return d2.id;
+      });
+      if (enabled.length) {
+        hash.photo_overlay = enabled.join(",");
+      } else {
+        delete hash.photo_overlay;
       }
-    }).catch(function() {
-    });
-    function getNear(isAddressable, type2, searchRadius, resultProp) {
-      var extent = combinedEntityExtent();
-      var l2 = extent.center();
-      var box = geoExtent(l2).padByMeters(searchRadius);
-      var features = context.history().intersects(box).filter(isAddressable).map((d2) => {
-        let dist = geoSphericalDistance(d2.extent(context.graph()).center(), l2);
-        if (d2.geometry(context.graph()) === "line") {
-          var loc = context.projection([
-            (extent[0][0] + extent[1][0]) / 2,
-            (extent[0][1] + extent[1][1]) / 2
-          ]);
-          var choice = geoChooseEdge(context.graph().childNodes(d2), loc, context.projection);
-          dist = geoSphericalDistance(choice.loc, l2);
+      window.location.replace("#" + utilQsString(hash, true));
+    }
+    photos.overlayLayerIDs = function() {
+      return _layerIDs;
+    };
+    photos.allPhotoTypes = function() {
+      return _allPhotoTypes;
+    };
+    photos.dateFilters = function() {
+      return _dateFilters;
+    };
+    photos.dateFilterValue = function(val) {
+      return val === _dateFilters[0] ? _fromDate : _toDate;
+    };
+    photos.setDateFilter = function(type2, val, updateUrl) {
+      var date = val && new Date(val);
+      if (date && !isNaN(date)) {
+        val = date.toISOString().slice(0, 10);
+      } else {
+        val = null;
+      }
+      if (type2 === _dateFilters[0]) {
+        _fromDate = val;
+        if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
+          _toDate = _fromDate;
         }
-        const value = resultProp && d2.tags[resultProp] ? d2.tags[resultProp] : d2.tags.name;
-        let title = value;
-        if (type2 === "street") {
-          title = "".concat(addrField.t("placeholders.street"), ": ").concat(title);
-        } else if (type2 === "place") {
-          title = "".concat(addrField.t("placeholders.place"), ": ").concat(title);
+      }
+      if (type2 === _dateFilters[1]) {
+        _toDate = val;
+        if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
+          _fromDate = _toDate;
         }
-        return {
-          title,
-          value,
-          dist,
-          type: type2,
-          klass: "address-".concat(type2)
-        };
-      }).sort(function(a2, b2) {
-        return a2.dist - b2.dist;
-      });
-      return utilArrayUniqBy(features, "value");
-    }
-    function getNearStreets() {
-      function isAddressable(d2) {
-        return d2.tags.highway && d2.tags.name && d2.type === "way";
       }
-      return getNear(isAddressable, "street", 200);
-    }
-    function getNearPlaces() {
-      function isAddressable(d2) {
-        if (d2.tags.name) {
-          if (d2.tags.place)
-            return true;
-          if (d2.tags.boundary === "administrative" && d2.tags.admin_level > 8)
-            return true;
+      dispatch14.call("change", this);
+      if (updateUrl) {
+        var rangeString;
+        if (_fromDate || _toDate) {
+          rangeString = (_fromDate || "") + "_" + (_toDate || "");
         }
-        return false;
+        setUrlFilterValue("photo_dates", rangeString);
       }
-      return getNear(isAddressable, "place", 200);
-    }
-    function getNearCities() {
-      function isAddressable(d2) {
-        if (d2.tags.name) {
-          if (d2.tags.boundary === "administrative" && d2.tags.admin_level === "8")
-            return true;
-          if (d2.tags.border_type === "city")
-            return true;
-          if (d2.tags.place === "city" || d2.tags.place === "town" || d2.tags.place === "village")
-            return true;
+    };
+    photos.setUsernameFilter = function(val, updateUrl) {
+      if (val && typeof val === "string") val = val.replace(/;/g, ",").split(",");
+      if (val) {
+        val = val.map((d2) => d2.trim()).filter(Boolean);
+        if (!val.length) {
+          val = null;
         }
-        if (d2.tags["".concat(field.key, ":city")])
-          return true;
-        return false;
       }
-      return getNear(isAddressable, "city", 200, "".concat(field.key, ":city"));
-    }
-    function getNearPostcodes() {
-      return [...new Set([].concat(getNearValues("postcode")).concat(getNear((d2) => d2.tags.postal_code, "postcode", 200, "postal_code")))];
-    }
-    function getNearValues(key) {
-      const tagKey = "".concat(field.key, ":").concat(key);
-      function hasTag(d2) {
-        return _entityIDs.indexOf(d2.id) === -1 && d2.tags[tagKey];
+      _usernames = val;
+      dispatch14.call("change", this);
+      if (updateUrl) {
+        var hashString;
+        if (_usernames) {
+          hashString = _usernames.join(",");
+        }
+        setUrlFilterValue("photo_username", hashString);
       }
-      return getNear(hasTag, key, 200, tagKey);
-    }
-    function updateForCountryCode() {
-      if (!_countryCode)
-        return;
-      var addressFormat;
-      for (var i3 = 0; i3 < _addressFormats.length; i3++) {
-        var format2 = _addressFormats[i3];
-        if (!format2.countryCodes) {
-          addressFormat = format2;
-        } else if (format2.countryCodes.indexOf(_countryCode) !== -1) {
-          addressFormat = format2;
-          break;
+    };
+    function setUrlFilterValue(property, val) {
+      if (!window.mocha) {
+        var hash = utilStringQs(window.location.hash);
+        if (val) {
+          if (hash[property] === val) return;
+          hash[property] = val;
+        } else {
+          if (!(property in hash)) return;
+          delete hash[property];
         }
+        window.location.replace("#" + utilQsString(hash, true));
       }
-      var dropdowns = addressFormat.dropdowns || [
-        "city",
-        "county",
-        "country",
-        "district",
-        "hamlet",
-        "neighbourhood",
-        "place",
-        "postcode",
-        "province",
-        "quarter",
-        "state",
-        "street",
-        "street+place",
-        "subdistrict",
-        "suburb"
-      ];
-      var widths = addressFormat.widths || {
-        housenumber: 1 / 5,
-        unit: 1 / 5,
-        street: 1 / 2,
-        place: 1 / 2,
-        city: 2 / 3,
-        state: 1 / 4,
-        postcode: 1 / 3
-      };
-      function row(r2) {
-        var total = r2.reduce(function(sum, key) {
-          return sum + (widths[key] || 0.5);
-        }, 0);
-        return r2.map(function(key) {
-          return {
-            id: key,
-            width: (widths[key] || 0.5) / total
-          };
+    }
+    function showsLayer(id2) {
+      var layer = context.layers().layer(id2);
+      return layer && layer.supported() && layer.enabled();
+    }
+    photos.shouldFilterByDate = function() {
+      return showsLayer("mapillary") || showsLayer("kartaview") || showsLayer("streetside") || showsLayer("vegbilder") || showsLayer("panoramax");
+    };
+    photos.shouldFilterByPhotoType = function() {
+      return showsLayer("mapillary") || showsLayer("streetside") && showsLayer("kartaview") || showsLayer("vegbilder") || showsLayer("panoramax");
+    };
+    photos.shouldFilterByUsername = function() {
+      return !showsLayer("mapillary") && showsLayer("kartaview") && !showsLayer("streetside") || showsLayer("panoramax");
+    };
+    photos.showsPhotoType = function(val) {
+      if (!photos.shouldFilterByPhotoType()) return true;
+      return _shownPhotoTypes.indexOf(val) !== -1;
+    };
+    photos.showsFlat = function() {
+      return photos.showsPhotoType("flat");
+    };
+    photos.showsPanoramic = function() {
+      return photos.showsPhotoType("panoramic");
+    };
+    photos.fromDate = function() {
+      return _fromDate;
+    };
+    photos.toDate = function() {
+      return _toDate;
+    };
+    photos.togglePhotoType = function(val) {
+      var index = _shownPhotoTypes.indexOf(val);
+      if (index !== -1) {
+        _shownPhotoTypes.splice(index, 1);
+      } else {
+        _shownPhotoTypes.push(val);
+      }
+      dispatch14.call("change", this);
+      return photos;
+    };
+    photos.usernames = function() {
+      return _usernames;
+    };
+    photos.init = function() {
+      var hash = utilStringQs(window.location.hash);
+      if (hash.photo_dates) {
+        var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
+        this.setDateFilter("fromDate", parts && parts.length >= 2 && parts[1], false);
+        this.setDateFilter("toDate", parts && parts.length >= 3 && parts[2], false);
+      }
+      if (hash.photo_username) {
+        this.setUsernameFilter(hash.photo_username, false);
+      }
+      if (hash.photo_overlay) {
+        var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ",").split(",");
+        hashOverlayIDs.forEach(function(id2) {
+          if (id2 === "openstreetcam") id2 = "kartaview";
+          var layer2 = _layerIDs.indexOf(id2) !== -1 && context.layers().layer(id2);
+          if (layer2 && !layer2.enabled()) layer2.enabled(true);
         });
       }
-      var rows = _wrap.selectAll(".addr-row").data(addressFormat.format, function(d2) {
-        return d2.toString();
-      });
-      rows.exit().remove();
-      rows.enter().append("div").attr("class", "addr-row").selectAll("input").data(row).enter().append("input").property("type", "text").call(updatePlaceholder).attr("class", function(d2) {
-        return "addr-" + d2.id;
-      }).call(utilNoAuto).each(addDropdown).style("width", function(d2) {
-        return d2.width * 100 + "%";
-      });
-      function addDropdown(d2) {
-        if (dropdowns.indexOf(d2.id) === -1)
-          return;
-        var nearValues;
-        switch (d2.id) {
-          case "street":
-            nearValues = getNearStreets;
-            break;
-          case "place":
-            nearValues = getNearPlaces;
-            break;
-          case "street+place":
-            nearValues = () => [].concat(getNearStreets()).concat(getNearPlaces());
-            d2.isAutoStreetPlace = true;
-            d2.id = _tags["".concat(field.key, ":place")] ? "place" : "street";
-            break;
-          case "city":
-            nearValues = getNearCities;
-            break;
-          case "postcode":
-            nearValues = getNearPostcodes;
-            break;
-          default:
-            nearValues = getNearValues;
+      if (hash.photo) {
+        var photoIds = hash.photo.replace(/;/g, ",").split(",");
+        var photoId = photoIds.length && photoIds[0].trim();
+        var results = /(.*)\/(.*)/g.exec(photoId);
+        if (results && results.length >= 3) {
+          var serviceId = results[1];
+          if (serviceId === "openstreetcam") serviceId = "kartaview";
+          var photoKey = results[2];
+          var service = services[serviceId];
+          if (service && service.ensureViewerLoaded) {
+            var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
+            if (layer && !layer.enabled()) layer.enabled(true);
+            var baselineTime = Date.now();
+            service.on("loadedImages.rendererPhotos", function() {
+              if (Date.now() - baselineTime > 45e3) {
+                service.on("loadedImages.rendererPhotos", null);
+                return;
+              }
+              if (!service.cachedImage(photoKey)) return;
+              service.on("loadedImages.rendererPhotos", null);
+              service.ensureViewerLoaded(context).then(function() {
+                service.selectImage(context, photoKey).showViewer(context);
+              });
+            });
+          }
         }
-        select_default2(this).call(
-          uiCombobox(context, "address-".concat(d2.isAutoStreetPlace ? "street-place" : d2.id)).minItems(1).caseSensitive(true).fetcher(function(typedValue, callback) {
-            typedValue = typedValue.toLowerCase();
-            callback(nearValues(d2.id).filter((v2) => v2.value.toLowerCase().indexOf(typedValue) !== -1));
-          }).on("accept", function(selected) {
-            if (d2.isAutoStreetPlace) {
-              d2.id = selected ? selected.type : "street";
-            }
-          })
-        );
       }
-      _wrap.selectAll("input").on("blur", change()).on("change", change());
-      _wrap.selectAll("input:not(.combobox-input)").on("input", change(true));
-      if (_tags)
-        updateTags(_tags);
-    }
-    function address(selection2) {
-      _selection = selection2;
-      _wrap = selection2.selectAll(".form-field-input-wrap").data([0]);
-      _wrap = _wrap.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(_wrap);
-      var extent = combinedEntityExtent();
-      if (extent) {
-        var countryCode;
-        if (context.inIntro()) {
-          countryCode = _t("intro.graph.countrycode");
+      context.layers().on("change.rendererPhotos", updateStorage);
+    };
+    return utilRebind(photos, dispatch14, "on");
+  }
+
+  // modules/ui/map_in_map.js
+  function uiMapInMap(context) {
+    function mapInMap(selection2) {
+      var backgroundLayer = rendererTileLayer(context);
+      var overlayLayers = {};
+      var projection2 = geoRawMercator();
+      var dataLayer = svgData(projection2, context).showLabels(false);
+      var debugLayer = svgDebug(projection2, context);
+      var zoom = zoom_default2().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on("start", zoomStarted).on("zoom", zoomed).on("end", zoomEnded);
+      var wrap2 = select_default2(null);
+      var tiles = select_default2(null);
+      var viewport = select_default2(null);
+      var _isTransformed = false;
+      var _isHidden = true;
+      var _skipEvents = false;
+      var _gesture = null;
+      var _zDiff = 6;
+      var _dMini;
+      var _cMini;
+      var _tStart;
+      var _tCurr;
+      var _timeoutID;
+      function zoomStarted() {
+        if (_skipEvents) return;
+        _tStart = _tCurr = projection2.transform();
+        _gesture = null;
+      }
+      function zoomed(d3_event) {
+        if (_skipEvents) return;
+        var x2 = d3_event.transform.x;
+        var y2 = d3_event.transform.y;
+        var k2 = d3_event.transform.k;
+        var isZooming = k2 !== _tStart.k;
+        var isPanning = x2 !== _tStart.x || y2 !== _tStart.y;
+        if (!isZooming && !isPanning) {
+          return;
+        }
+        if (!_gesture) {
+          _gesture = isZooming ? "zoom" : "pan";
+        }
+        var tMini = projection2.transform();
+        var tX, tY, scale;
+        if (_gesture === "zoom") {
+          scale = k2 / tMini.k;
+          tX = (_cMini[0] / scale - _cMini[0]) * scale;
+          tY = (_cMini[1] / scale - _cMini[1]) * scale;
         } else {
-          var center = extent.center();
-          countryCode = iso1A2Code(center);
+          k2 = tMini.k;
+          scale = 1;
+          tX = x2 - tMini.x;
+          tY = y2 - tMini.y;
         }
-        if (countryCode) {
-          _countryCode = countryCode.toLowerCase();
-          updateForCountryCode();
+        utilSetTransform(tiles, tX, tY, scale);
+        utilSetTransform(viewport, 0, 0, scale);
+        _isTransformed = true;
+        _tCurr = identity2.translate(x2, y2).scale(k2);
+        var zMain = geoScaleToZoom(context.projection.scale());
+        var zMini = geoScaleToZoom(k2);
+        _zDiff = zMain - zMini;
+        queueRedraw();
+      }
+      function zoomEnded() {
+        if (_skipEvents) return;
+        if (_gesture !== "pan") return;
+        updateProjection();
+        _gesture = null;
+        context.map().center(projection2.invert(_cMini));
+      }
+      function updateProjection() {
+        var loc = context.map().center();
+        var tMain = context.projection.transform();
+        var zMain = geoScaleToZoom(tMain.k);
+        var zMini = Math.max(zMain - _zDiff, 0.5);
+        var kMini = geoZoomToScale(zMini);
+        projection2.translate([tMain.x, tMain.y]).scale(kMini);
+        var point = projection2(loc);
+        var mouse = _gesture === "pan" ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
+        var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
+        var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
+        projection2.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
+        _tCurr = projection2.transform();
+        if (_isTransformed) {
+          utilSetTransform(tiles, 0, 0);
+          utilSetTransform(viewport, 0, 0);
+          _isTransformed = false;
         }
+        zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
+        _skipEvents = true;
+        wrap2.call(zoom.transform, _tCurr);
+        _skipEvents = false;
       }
-    }
-    function change(onInput) {
-      return function() {
-        setTimeout(() => {
-          var tags = {};
-          _wrap.selectAll("input").each(function(subfield) {
-            var key = field.key + ":" + subfield.id;
-            var value = this.value;
-            if (!onInput)
-              value = context.cleanTagValue(value);
-            if (Array.isArray(_tags[key]) && !value)
-              return;
-            if (subfield.isAutoStreetPlace) {
-              if (subfield.id === "street") {
-                tags["".concat(field.key, ":place")] = void 0;
-              } else if (subfield.id === "place") {
-                tags["".concat(field.key, ":street")] = void 0;
-              }
-            }
-            tags[key] = value || void 0;
-          });
-          Object.keys(tags).filter((k2) => tags[k2]).forEach((k2) => _tags[k2] = tags[k2]);
-          dispatch14.call("change", this, tags, onInput);
-        }, 0);
-      };
-    }
-    function updatePlaceholder(inputSelection) {
-      return inputSelection.attr("placeholder", function(subfield) {
-        if (_tags && Array.isArray(_tags[field.key + ":" + subfield.id])) {
-          return _t("inspector.multiple_values");
+      function redraw() {
+        clearTimeout(_timeoutID);
+        if (_isHidden) return;
+        updateProjection();
+        var zMini = geoScaleToZoom(projection2.scale());
+        tiles = wrap2.selectAll(".map-in-map-tiles").data([0]);
+        tiles = tiles.enter().append("div").attr("class", "map-in-map-tiles").merge(tiles);
+        backgroundLayer.source(context.background().baseLayerSource()).projection(projection2).dimensions(_dMini);
+        var background = tiles.selectAll(".map-in-map-background").data([0]);
+        background.enter().append("div").attr("class", "map-in-map-background").merge(background).call(backgroundLayer);
+        var overlaySources = context.background().overlayLayerSources();
+        var activeOverlayLayers = [];
+        for (var i3 = 0; i3 < overlaySources.length; i3++) {
+          if (overlaySources[i3].validZoom(zMini)) {
+            if (!overlayLayers[i3]) overlayLayers[i3] = rendererTileLayer(context);
+            activeOverlayLayers.push(overlayLayers[i3].source(overlaySources[i3]).projection(projection2).dimensions(_dMini));
+          }
         }
-        if (subfield.isAutoStreetPlace) {
-          return "".concat(getLocalPlaceholder("street"), " / ").concat(getLocalPlaceholder("place"));
+        var overlay = tiles.selectAll(".map-in-map-overlay").data([0]);
+        overlay = overlay.enter().append("div").attr("class", "map-in-map-overlay").merge(overlay);
+        var overlays = overlay.selectAll("div").data(activeOverlayLayers, function(d2) {
+          return d2.source().name();
+        });
+        overlays.exit().remove();
+        overlays = overlays.enter().append("div").merge(overlays).each(function(layer) {
+          select_default2(this).call(layer);
+        });
+        var dataLayers = tiles.selectAll(".map-in-map-data").data([0]);
+        dataLayers.exit().remove();
+        dataLayers = dataLayers.enter().append("svg").attr("class", "map-in-map-data").merge(dataLayers).call(dataLayer).call(debugLayer);
+        if (_gesture !== "pan") {
+          var getPath = path_default(projection2);
+          var bbox2 = { type: "Polygon", coordinates: [context.map().extent().polygon()] };
+          viewport = wrap2.selectAll(".map-in-map-viewport").data([0]);
+          viewport = viewport.enter().append("svg").attr("class", "map-in-map-viewport").merge(viewport);
+          var path = viewport.selectAll(".map-in-map-bbox").data([bbox2]);
+          path.enter().append("path").attr("class", "map-in-map-bbox").merge(path).attr("d", getPath).classed("thick", function(d2) {
+            return getPath.area(d2) < 30;
+          });
         }
-        return getLocalPlaceholder(subfield.id);
-      });
-    }
-    function getLocalPlaceholder(key) {
-      if (_countryCode) {
-        var localkey = key + "!" + _countryCode;
-        var tkey = addrField.hasTextForStringId("placeholders." + localkey) ? localkey : key;
-        return addrField.t("placeholders." + tkey);
       }
-    }
-    function updateTags(tags) {
-      utilGetSetValue(_wrap.selectAll("input"), (subfield) => {
-        var val;
-        if (subfield.isAutoStreetPlace) {
-          const streetKey = "".concat(field.key, ":street");
-          const placeKey = "".concat(field.key, ":place");
-          if (tags[streetKey] !== void 0 || tags[placeKey] === void 0) {
-            val = tags[streetKey];
-            subfield.id = "street";
-          } else {
-            val = tags[placeKey];
-            subfield.id = "place";
-          }
+      function queueRedraw() {
+        clearTimeout(_timeoutID);
+        _timeoutID = setTimeout(function() {
+          redraw();
+        }, 750);
+      }
+      function toggle(d3_event) {
+        if (d3_event) d3_event.preventDefault();
+        _isHidden = !_isHidden;
+        context.container().select(".minimap-toggle-item").classed("active", !_isHidden).select("input").property("checked", !_isHidden);
+        if (_isHidden) {
+          wrap2.style("display", "block").style("opacity", "1").transition().duration(200).style("opacity", "0").on("end", function() {
+            selection2.selectAll(".map-in-map").style("display", "none");
+          });
         } else {
-          val = tags["".concat(field.key, ":").concat(subfield.id)];
+          wrap2.style("display", "block").style("opacity", "0").transition().duration(200).style("opacity", "1").on("end", function() {
+            redraw();
+          });
         }
-        return typeof val === "string" ? val : "";
-      }).attr("title", function(subfield) {
-        var val = tags[field.key + ":" + subfield.id];
-        return val && Array.isArray(val) ? val.filter(Boolean).join("\n") : void 0;
-      }).classed("mixed", function(subfield) {
-        return Array.isArray(tags[field.key + ":" + subfield.id]);
-      }).call(updatePlaceholder);
-    }
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
-    }
-    address.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return address;
-    };
-    address.tags = function(tags) {
-      _tags = tags;
-      updateTags(tags);
-    };
-    address.focus = function() {
-      var node = _wrap.selectAll("input").node();
-      if (node)
-        node.focus();
-    };
-    return utilRebind(address, dispatch14, "on");
-  }
-
-  // modules/ui/fields/directional_combo.js
-  function uiFieldDirectionalCombo(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var items = select_default2(null);
-    var wrap2 = select_default2(null);
-    var _tags;
-    var _combos = {};
-    if (field.type === "cycleway") {
-      field = {
-        ...field,
-        key: field.keys[0],
-        keys: field.keys.slice(1)
-      };
-    }
-    function directionalCombo(selection2) {
-      function stripcolon(s2) {
-        return s2.replace(":", "");
       }
-      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var div = wrap2.selectAll("ul").data([0]);
-      div = div.enter().append("ul").attr("class", "rows rows-table").merge(div);
-      items = div.selectAll("li").data(field.keys);
-      var enter = items.enter().append("li").attr("class", function(d2) {
-        return "labeled-input preset-directionalcombo-" + stripcolon(d2);
-      });
-      enter.append("div").attr("class", "label preset-label-directionalcombo").attr("for", function(d2) {
-        return "preset-input-directionalcombo-" + stripcolon(d2);
-      }).html(function(d2) {
-        return field.t.html("types." + d2);
-      });
-      enter.append("div").attr("class", "preset-input-directionalcombo-wrap form-field-input-wrap").each(function(key) {
-        const subField = {
-          ...field,
-          type: "combo",
-          key
-        };
-        const combo = uiFieldCombo(subField, context);
-        combo.on("change", (t2) => change(key, t2[key]));
-        _combos[key] = combo;
-        select_default2(this).call(combo);
-      });
-      items = items.merge(enter);
-      wrap2.selectAll(".preset-input-directionalcombo").on("change", change).on("blur", change);
-    }
-    function change(key, newValue) {
-      const commonKey = field.key;
-      const otherKey = key === field.keys[0] ? field.keys[1] : field.keys[0];
-      dispatch14.call("change", this, (tags) => {
-        const otherValue = tags[otherKey] || tags[commonKey];
-        if (newValue === otherValue) {
-          tags[commonKey] = newValue;
-          delete tags[key];
-          delete tags[otherKey];
-        } else {
-          tags[key] = newValue;
-          delete tags[commonKey];
-          tags[otherKey] = otherValue;
+      uiMapInMap.toggle = toggle;
+      wrap2 = selection2.selectAll(".map-in-map").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "map-in-map").style("display", _isHidden ? "none" : "block").call(zoom).on("dblclick.zoom", null).merge(wrap2);
+      _dMini = [200, 150];
+      _cMini = geoVecScale(_dMini, 0.5);
+      context.map().on("drawn.map-in-map", function(drawn) {
+        if (drawn.full === true) {
+          redraw();
         }
-        return tags;
       });
+      redraw();
+      context.keybinding().on(_t("background.minimap.key"), toggle);
     }
-    directionalCombo.tags = function(tags) {
-      _tags = tags;
-      const commonKey = field.key;
-      for (let key in _combos) {
-        const uniqueValues = [...new Set([].concat(_tags[commonKey]).concat(_tags[key]).filter(Boolean))];
-        _combos[key].tags({ [key]: uniqueValues.length > 1 ? uniqueValues : uniqueValues[0] });
-      }
-    };
-    directionalCombo.focus = function() {
-      var node = wrap2.selectAll("input").node();
-      if (node)
-        node.focus();
-    };
-    return utilRebind(directionalCombo, dispatch14, "on");
+    return mapInMap;
   }
 
-  // modules/ui/fields/lanes.js
-  function uiFieldLanes(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var LANE_WIDTH = 40;
-    var LANE_HEIGHT = 200;
-    var _entityIDs = [];
-    function lanes(selection2) {
-      var lanesData = context.entity(_entityIDs[0]).lanes();
-      if (!context.container().select(".inspector-wrap.inspector-hidden").empty() || !selection2.node().parentNode) {
-        selection2.call(lanes.off);
-        return;
-      }
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var surface = wrap2.selectAll(".surface").data([0]);
-      var d2 = utilGetDimensions(wrap2);
-      var freeSpace = d2[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
-      surface = surface.enter().append("svg").attr("width", d2[0]).attr("height", 300).attr("class", "surface").merge(surface);
-      var lanesSelection = surface.selectAll(".lanes").data([0]);
-      lanesSelection = lanesSelection.enter().append("g").attr("class", "lanes").merge(lanesSelection);
-      lanesSelection.attr("transform", function() {
-        return "translate(" + freeSpace / 2 + ", 0)";
-      });
-      var lane = lanesSelection.selectAll(".lane").data(lanesData.lanes);
-      lane.exit().remove();
-      var enter = lane.enter().append("g").attr("class", "lane");
-      enter.append("g").append("rect").attr("y", 50).attr("width", LANE_WIDTH).attr("height", LANE_HEIGHT);
-      enter.append("g").attr("class", "forward").append("text").attr("y", 40).attr("x", 14).text("\u25B2");
-      enter.append("g").attr("class", "bothways").append("text").attr("y", 40).attr("x", 14).text("\u25B2\u25BC");
-      enter.append("g").attr("class", "backward").append("text").attr("y", 40).attr("x", 14).text("\u25BC");
-      lane = lane.merge(enter);
-      lane.attr("transform", function(d4) {
-        return "translate(" + LANE_WIDTH * d4.index * 1.5 + ", 0)";
-      });
-      lane.select(".forward").style("visibility", function(d4) {
-        return d4.direction === "forward" ? "visible" : "hidden";
-      });
-      lane.select(".bothways").style("visibility", function(d4) {
-        return d4.direction === "bothways" ? "visible" : "hidden";
-      });
-      lane.select(".backward").style("visibility", function(d4) {
-        return d4.direction === "backward" ? "visible" : "hidden";
+  // modules/ui/notice.js
+  function uiNotice(context) {
+    return function(selection2) {
+      var div = selection2.append("div").attr("class", "notice");
+      var button = div.append("button").attr("class", "zoom-to notice fillD").on("click", function() {
+        context.map().zoomEase(context.minEditableZoom());
+      }).on("wheel", function(d3_event) {
+        var e22 = new WheelEvent(d3_event.type, d3_event);
+        context.surface().node().dispatchEvent(e22);
       });
-    }
-    lanes.entityIDs = function(val) {
-      _entityIDs = val;
-    };
-    lanes.tags = function() {
-    };
-    lanes.focus = function() {
-    };
-    lanes.off = function() {
+      button.call(svgIcon("#iD-icon-plus", "pre-text")).append("span").attr("class", "label").call(_t.append("zoom_in_edit"));
+      function disableTooHigh() {
+        var canEdit = context.map().zoom() >= context.minEditableZoom();
+        div.style("display", canEdit ? "none" : "block");
+      }
+      context.map().on("move.notice", debounce_default(disableTooHigh, 500));
+      disableTooHigh();
     };
-    return utilRebind(lanes, dispatch14, "on");
   }
-  uiFieldLanes.supportsMultiselection = false;
 
-  // modules/ui/fields/localized.js
-  var _languagesArray = [];
-  function uiFieldLocalized(field, context) {
-    var dispatch14 = dispatch_default("change", "input");
-    var wikipedia = services.wikipedia;
-    var input = select_default2(null);
-    var localizedInputs = select_default2(null);
-    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
-    var _countryCode;
-    var _tags;
-    _mainFileFetcher.get("languages").then(loadLanguagesArray).catch(function() {
-    });
-    var _territoryLanguages = {};
-    _mainFileFetcher.get("territory_languages").then(function(d2) {
-      _territoryLanguages = d2;
-    }).catch(function() {
-    });
-    var langCombo = uiCombobox(context, "localized-lang").fetcher(fetchLanguages).minItems(0);
-    var _selection = select_default2(null);
-    var _multilingual = [];
-    var _buttonTip = uiTooltip().title(() => _t.append("translate.translate")).placement("left");
-    var _wikiTitles;
-    var _entityIDs = [];
-    function loadLanguagesArray(dataLanguages) {
-      if (_languagesArray.length !== 0)
-        return;
-      var replacements = {
-        sr: "sr-Cyrl",
-        // in OSM, `sr` implies Cyrillic
-        "sr-Cyrl": false
-        // `sr-Cyrl` isn't used in OSM
-      };
-      for (var code in dataLanguages) {
-        if (replacements[code] === false)
-          continue;
-        var metaCode = code;
-        if (replacements[code])
-          metaCode = replacements[code];
-        _languagesArray.push({
-          localName: _mainLocalizer.languageName(metaCode, { localOnly: true }),
-          nativeName: dataLanguages[metaCode].nativeName,
-          code,
-          label: _mainLocalizer.languageName(metaCode)
-        });
+  // modules/ui/photoviewer.js
+  function uiPhotoviewer(context) {
+    var dispatch14 = dispatch_default("resize");
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function photoviewer(selection2) {
+      selection2.append("button").attr("class", "thumb-hide").attr("title", _t("icons.close")).on("click", function() {
+        if (services.streetside) {
+          services.streetside.hideViewer(context);
+        }
+        if (services.mapillary) {
+          services.mapillary.hideViewer(context);
+        }
+        if (services.kartaview) {
+          services.kartaview.hideViewer(context);
+        }
+        if (services.mapilio) {
+          services.mapilio.hideViewer(context);
+        }
+        if (services.panoramax) {
+          services.panoramax.hideViewer(context);
+        }
+        if (services.vegbilder) {
+          services.vegbilder.hideViewer(context);
+        }
+      }).append("div").call(svgIcon("#iD-icon-close"));
+      function preventDefault(d3_event) {
+        d3_event.preventDefault();
       }
-    }
-    function calcLocked() {
-      var isLocked = field.id === "name" && _entityIDs.length && _entityIDs.some(function(entityID) {
-        var entity = context.graph().hasEntity(entityID);
-        if (!entity)
-          return false;
-        if (entity.tags.wikidata)
-          return true;
-        if (entity.tags["name:etymology:wikidata"])
-          return true;
-        var preset = _mainPresetIndex.match(entity, context.graph());
-        if (preset) {
-          var isSuggestion = preset.suggestion;
-          var fields = preset.fields(entity.extent(context.graph()).center());
-          var showsBrandField = fields.some(function(d2) {
-            return d2.id === "brand";
-          });
-          var showsOperatorField = fields.some(function(d2) {
-            return d2.id === "operator";
-          });
-          var setsName = preset.addTags.name;
-          var setsBrandWikidata = preset.addTags["brand:wikidata"];
-          var setsOperatorWikidata = preset.addTags["operator:wikidata"];
-          return isSuggestion && setsName && (setsBrandWikidata && !showsBrandField || setsOperatorWikidata && !showsOperatorField);
+      selection2.append("button").attr("class", "resize-handle-xy").on("touchstart touchdown touchend", preventDefault).on(
+        _pointerPrefix + "down",
+        buildResizeListener(selection2, "resize", dispatch14, { resizeOnX: true, resizeOnY: true })
+      );
+      selection2.append("button").attr("class", "resize-handle-x").on("touchstart touchdown touchend", preventDefault).on(
+        _pointerPrefix + "down",
+        buildResizeListener(selection2, "resize", dispatch14, { resizeOnX: true })
+      );
+      selection2.append("button").attr("class", "resize-handle-y").on("touchstart touchdown touchend", preventDefault).on(
+        _pointerPrefix + "down",
+        buildResizeListener(selection2, "resize", dispatch14, { resizeOnY: true })
+      );
+      context.features().on("change.setPhotoFromViewer", function() {
+        setPhotoFromViewerButton();
+      });
+      context.history().on("change.setPhotoFromViewer", function() {
+        setPhotoFromViewerButton();
+      });
+      function setPhotoFromViewerButton() {
+        if (services.mapillary.isViewerOpen()) {
+          let setMapillaryPhotoId = function() {
+            const service = services.mapillary;
+            const image = service.getActiveImage();
+            const action = (graph) => context.selectedIDs().reduce((graph2, entityID) => {
+              const tags = graph2.entity(entityID).tags;
+              const action2 = actionChangeTags(entityID, { ...tags, mapillary: image.id });
+              return action2(graph2);
+            }, graph);
+            const annotation = _t("operations.change_tags.annotation");
+            context.perform(action, annotation);
+          };
+          if (context.mode().id !== "select" || !(layerStatus("mapillary") && getServiceId() === "mapillary")) {
+            buttonRemove();
+          } else {
+            if (selection2.select(".set-photo-from-viewer").empty()) {
+              const button = buttonCreate();
+              button.on("click", function(e3) {
+                e3.preventDefault();
+                e3.stopPropagation();
+                setMapillaryPhotoId();
+                buttonDisable("already_set");
+              });
+            }
+            buttonShowHide();
+          }
         }
-        return false;
-      });
-      field.locked(isLocked);
-    }
-    function calcMultilingual(tags) {
-      var existingLangsOrdered = _multilingual.map(function(item2) {
-        return item2.lang;
-      });
-      var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
-      for (var k2 in tags) {
-        var m2 = k2.match(/^(.*):([a-z]{2,3}(?:-[A-Z][a-z]{3})?(?:-[A-Z]{2})?)$/);
-        if (m2 && m2[1] === field.key && m2[2]) {
-          var item = { lang: m2[2], value: tags[k2] };
-          if (existingLangs.has(item.lang)) {
-            _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
-            existingLangs.delete(item.lang);
+        function layerStatus(which) {
+          const layers = context.layers();
+          const layer = layers.layer(which);
+          return layer.enabled();
+        }
+        function getServiceId() {
+          const hash = utilStringQs(window.location.hash);
+          let serviceId;
+          if (hash.photo) {
+            let result = hash.photo.split("/");
+            serviceId = result[0];
+          }
+          return serviceId;
+        }
+        function buttonCreate() {
+          const button = selection2.selectAll(".set-photo-from-viewer").data([0]);
+          const buttonEnter = button.enter().append("button").attr("class", "set-photo-from-viewer").call(svgIcon("#iD-icon-plus")).call(
+            uiTooltip().title(() => _t.append("inspector.set_photo_from_viewer")).placement("right")
+          );
+          buttonEnter.select(".tooltip").classed("dark", true).style("width", "300px");
+          return buttonEnter;
+        }
+        function buttonRemove() {
+          const button = selection2.selectAll(".set-photo-from-viewer").data([0]);
+          button.remove();
+        }
+        function buttonShowHide() {
+          const activeImage = services.mapillary.getActiveImage();
+          const graph = context.graph();
+          const entities = context.selectedIDs().map((id2) => graph.entity(id2));
+          if (entities.map((entity) => entity.tags.mapillary).every((value) => value === (activeImage == null ? void 0 : activeImage.id))) {
+            buttonDisable("already_set");
+          } else if (activeImage && entities.map((entity) => entity.extent().center()).every((loc) => geoSphericalDistance(loc, activeImage.loc) > 100)) {
+            buttonDisable("too_far");
           } else {
-            _multilingual.push(item);
+            buttonDisable(false);
           }
         }
-      }
-      _multilingual.forEach(function(item2) {
-        if (item2.lang && existingLangs.has(item2.lang)) {
-          item2.value = "";
+        function buttonDisable(reason) {
+          const disabled = reason !== false;
+          const button = selection2.selectAll(".set-photo-from-viewer").data([0]);
+          button.attr("disabled", disabled ? "true" : null);
+          button.classed("disabled", disabled);
+          button.call(uiTooltip().destroyAny);
+          if (disabled) {
+            button.call(
+              uiTooltip().title(() => _t.append("inspector.set_photo_from_viewer.disable.".concat(reason))).placement("right")
+            );
+          } else {
+            button.call(
+              uiTooltip().title(() => _t.append("inspector.set_photo_from_viewer.enable")).placement("right")
+            );
+          }
+          button.select(".tooltip").classed("dark", true).style("width", "300px");
         }
-      });
-    }
-    function localized(selection2) {
-      _selection = selection2;
-      calcLocked();
-      var isLocked = field.locked();
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      input = wrap2.selectAll(".localized-main").data([0]);
-      input = input.enter().append("input").attr("type", "text").attr("id", field.domId).attr("class", "localized-main").call(utilNoAuto).merge(input);
-      input.classed("disabled", !!isLocked).attr("readonly", isLocked || null).on("input", change(true)).on("blur", change()).on("change", change());
-      wrap2.call(_lengthIndicator);
-      var translateButton = wrap2.selectAll(".localized-add").data([0]);
-      translateButton = translateButton.enter().append("button").attr("class", "localized-add form-field-button").attr("aria-label", _t("icons.plus")).call(svgIcon("#iD-icon-plus")).merge(translateButton);
-      translateButton.classed("disabled", !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on("click", addNew);
-      if (_tags && !_multilingual.length) {
-        calcMultilingual(_tags);
       }
-      localizedInputs = selection2.selectAll(".localized-multilingual").data([0]);
-      localizedInputs = localizedInputs.enter().append("div").attr("class", "localized-multilingual").merge(localizedInputs);
-      localizedInputs.call(renderMultilingual);
-      localizedInputs.selectAll("button, input").classed("disabled", !!isLocked).attr("readonly", isLocked || null);
-      selection2.selectAll(".combobox-caret").classed("nope", true);
-      function addNew(d3_event) {
-        d3_event.preventDefault();
-        if (field.locked())
-          return;
-        var defaultLang = _mainLocalizer.languageCode().toLowerCase();
-        var langExists = _multilingual.find(function(datum2) {
-          return datum2.lang === defaultLang;
-        });
-        var isLangEn = defaultLang.indexOf("en") > -1;
-        if (isLangEn || langExists) {
-          defaultLang = "";
-          langExists = _multilingual.find(function(datum2) {
-            return datum2.lang === defaultLang;
-          });
+      function buildResizeListener(target, eventName, dispatch15, options2) {
+        var resizeOnX = !!options2.resizeOnX;
+        var resizeOnY = !!options2.resizeOnY;
+        var minHeight = options2.minHeight || 240;
+        var minWidth = options2.minWidth || 320;
+        var pointerId;
+        var startX;
+        var startY;
+        var startWidth;
+        var startHeight;
+        function startResize(d3_event) {
+          if (pointerId !== (d3_event.pointerId || "mouse")) return;
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          var mapSize = context.map().dimensions();
+          if (resizeOnX) {
+            var maxWidth = mapSize[0];
+            var newWidth = clamp3(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
+            target.style("width", newWidth + "px");
+          }
+          if (resizeOnY) {
+            var maxHeight = mapSize[1] - 90;
+            var newHeight = clamp3(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
+            target.style("height", newHeight + "px");
+          }
+          dispatch15.call(eventName, target, subtractPadding(utilGetDimensions(target, true), target));
         }
-        if (!langExists) {
-          _multilingual.unshift({ lang: defaultLang, value: "" });
-          localizedInputs.call(renderMultilingual);
+        function clamp3(num, min3, max3) {
+          return Math.max(min3, Math.min(num, max3));
         }
-      }
-      function change(onInput) {
-        return function(d3_event) {
-          if (field.locked()) {
-            d3_event.preventDefault();
-            return;
+        function stopResize(d3_event) {
+          if (pointerId !== (d3_event.pointerId || "mouse")) return;
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          select_default2(window).on("." + eventName, null);
+        }
+        return function initResize(d3_event) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          pointerId = d3_event.pointerId || "mouse";
+          startX = d3_event.clientX;
+          startY = d3_event.clientY;
+          var targetRect = target.node().getBoundingClientRect();
+          startWidth = targetRect.width;
+          startHeight = targetRect.height;
+          select_default2(window).on(_pointerPrefix + "move." + eventName, startResize, false).on(_pointerPrefix + "up." + eventName, stopResize, false);
+          if (_pointerPrefix === "pointer") {
+            select_default2(window).on("pointercancel." + eventName, stopResize, false);
           }
-          var val = utilGetSetValue(select_default2(this));
-          if (!onInput)
-            val = context.cleanTagValue(val);
-          if (!val && Array.isArray(_tags[field.key]))
-            return;
-          var t2 = {};
-          t2[field.key] = val || void 0;
-          dispatch14.call("change", this, t2, onInput);
         };
       }
     }
-    function key(lang) {
-      return field.key + ":" + lang;
+    photoviewer.onMapResize = function() {
+      var photoviewer2 = context.container().select(".photoviewer");
+      var content = context.container().select(".main-content");
+      var mapDimensions = utilGetDimensions(content, true);
+      var photoDimensions = utilGetDimensions(photoviewer2, true);
+      if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
+        var setPhotoDimensions = [
+          Math.min(photoDimensions[0], mapDimensions[0]),
+          Math.min(photoDimensions[1], mapDimensions[1] - 90)
+        ];
+        photoviewer2.style("width", setPhotoDimensions[0] + "px").style("height", setPhotoDimensions[1] + "px");
+        dispatch14.call("resize", photoviewer2, subtractPadding(setPhotoDimensions, photoviewer2));
+      }
+    };
+    function subtractPadding(dimensions, selection2) {
+      return [
+        dimensions[0] - parseFloat(selection2.style("padding-left")) - parseFloat(selection2.style("padding-right")),
+        dimensions[1] - parseFloat(selection2.style("padding-top")) - parseFloat(selection2.style("padding-bottom"))
+      ];
     }
-    function changeLang(d3_event, d2) {
-      var tags = {};
-      var lang = utilGetSetValue(select_default2(this)).toLowerCase();
-      var language = _languagesArray.find(function(d4) {
-        return d4.label.toLowerCase() === lang || d4.localName && d4.localName.toLowerCase() === lang || d4.nativeName && d4.nativeName.toLowerCase() === lang;
+    return utilRebind(photoviewer, dispatch14, "on");
+  }
+
+  // modules/ui/restore.js
+  function uiRestore(context) {
+    return function(selection2) {
+      if (!context.history().hasRestorableChanges()) return;
+      let modalSelection = uiModal(selection2, true);
+      modalSelection.select(".modal").attr("class", "modal fillL");
+      let introModal = modalSelection.select(".content");
+      introModal.append("div").attr("class", "modal-section").append("h3").call(_t.append("restore.heading"));
+      introModal.append("div").attr("class", "modal-section").append("p").call(_t.append("restore.description"));
+      let buttonWrap = introModal.append("div").attr("class", "modal-actions");
+      let restore = buttonWrap.append("button").attr("class", "restore").on("click", () => {
+        context.history().restore();
+        modalSelection.remove();
       });
-      if (language)
-        lang = language.code;
-      if (d2.lang && d2.lang !== lang) {
-        tags[key(d2.lang)] = void 0;
+      restore.append("svg").attr("class", "logo logo-restore").append("use").attr("xlink:href", "#iD-logo-restore");
+      restore.append("div").call(_t.append("restore.restore"));
+      let reset = buttonWrap.append("button").attr("class", "reset").on("click", () => {
+        context.history().clearSaved();
+        modalSelection.remove();
+      });
+      reset.append("svg").attr("class", "logo logo-reset").append("use").attr("xlink:href", "#iD-logo-reset");
+      reset.append("div").call(_t.append("restore.reset"));
+      restore.node().focus();
+    };
+  }
+
+  // modules/ui/scale.js
+  function uiScale(context) {
+    var projection2 = context.projection, isImperial = !_mainLocalizer.usesMetric(), maxLength = 180, tickHeight = 8;
+    function scaleDefs(loc1, loc2) {
+      var lat = (loc2[1] + loc1[1]) / 2, conversion = isImperial ? 3.28084 : 1, dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion, scale = { dist: 0, px: 0, text: "" }, buckets, i3, val, dLon;
+      if (isImperial) {
+        buckets = [528e4, 528e3, 52800, 5280, 500, 50, 5, 1];
+      } else {
+        buckets = [5e6, 5e5, 5e4, 5e3, 500, 50, 5, 1];
       }
-      var newKey = lang && context.cleanTagKey(key(lang));
-      var value = utilGetSetValue(select_default2(this.parentNode).selectAll(".localized-value"));
-      if (newKey && value) {
-        tags[newKey] = value;
-      } else if (newKey && _wikiTitles && _wikiTitles[d2.lang]) {
-        tags[newKey] = _wikiTitles[d2.lang];
+      for (i3 = 0; i3 < buckets.length; i3++) {
+        val = buckets[i3];
+        if (dist >= val) {
+          scale.dist = Math.floor(dist / val) * val;
+          break;
+        } else {
+          scale.dist = +dist.toFixed(2);
+        }
       }
-      d2.lang = lang;
-      dispatch14.call("change", this, tags);
+      dLon = geoMetersToLon(scale.dist / conversion, lat);
+      scale.px = Math.round(projection2([loc1[0] + dLon, loc1[1]])[0]);
+      scale.text = displayLength(scale.dist / conversion, isImperial);
+      return scale;
     }
-    function changeValue(d3_event, d2) {
-      if (!d2.lang)
-        return;
-      var value = context.cleanTagValue(utilGetSetValue(select_default2(this))) || void 0;
-      if (!value && Array.isArray(d2.value))
-        return;
-      var t2 = {};
-      t2[key(d2.lang)] = value;
-      d2.value = value;
-      dispatch14.call("change", this, t2);
+    function update(selection2) {
+      var dims = context.map().dimensions(), loc1 = projection2.invert([0, dims[1]]), loc2 = projection2.invert([maxLength, dims[1]]), scale = scaleDefs(loc1, loc2);
+      selection2.select(".scale-path").attr("d", "M0.5,0.5v" + tickHeight + "h" + scale.px + "v-" + tickHeight);
+      selection2.select(".scale-text").style(_mainLocalizer.textDirection() === "ltr" ? "left" : "right", scale.px + 16 + "px").text(scale.text);
     }
-    function fetchLanguages(value, cb) {
-      var v2 = value.toLowerCase();
-      var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
-      if (_countryCode && _territoryLanguages[_countryCode]) {
-        langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
+    return function(selection2) {
+      function switchUnits() {
+        isImperial = !isImperial;
+        selection2.call(update);
       }
-      var langItems = [];
-      langCodes.forEach(function(code) {
-        var langItem = _languagesArray.find(function(item) {
-          return item.code === code;
-        });
-        if (langItem)
-          langItems.push(langItem);
+      var scalegroup = selection2.append("svg").attr("class", "scale").on("click", switchUnits).append("g").attr("transform", "translate(10,11)");
+      scalegroup.append("path").attr("class", "scale-path");
+      selection2.append("div").attr("class", "scale-text");
+      selection2.call(update);
+      context.map().on("move.scale", function() {
+        update(selection2);
+      });
+    };
+  }
+
+  // modules/ui/shortcuts.js
+  function uiShortcuts(context) {
+    var detected = utilDetect();
+    var _activeTab = 0;
+    var _modalSelection;
+    var _selection = select_default2(null);
+    var _dataShortcuts;
+    function shortcutsModal(_modalSelection2) {
+      _modalSelection2.select(".modal").classed("modal-shortcuts", true);
+      var content = _modalSelection2.select(".content");
+      content.append("div").attr("class", "modal-section header").append("h2").call(_t.append("shortcuts.title"));
+      _mainFileFetcher.get("shortcuts").then(function(data) {
+        _dataShortcuts = data;
+        content.call(render);
+      }).catch(function() {
       });
-      langItems = utilArrayUniq(langItems.concat(_languagesArray));
-      cb(langItems.filter(function(d2) {
-        return d2.label.toLowerCase().indexOf(v2) >= 0 || d2.localName && d2.localName.toLowerCase().indexOf(v2) >= 0 || d2.nativeName && d2.nativeName.toLowerCase().indexOf(v2) >= 0 || d2.code.toLowerCase().indexOf(v2) >= 0;
-      }).map(function(d2) {
-        return { value: d2.label };
-      }));
     }
-    function renderMultilingual(selection2) {
-      var entries = selection2.selectAll("div.entry").data(_multilingual, function(d2) {
-        return d2.lang;
+    function render(selection2) {
+      if (!_dataShortcuts) return;
+      var wrapper = selection2.selectAll(".wrapper").data([0]);
+      var wrapperEnter = wrapper.enter().append("div").attr("class", "wrapper modal-section");
+      var tabsBar = wrapperEnter.append("div").attr("class", "tabs-bar");
+      var shortcutsList = wrapperEnter.append("div").attr("class", "shortcuts-list");
+      wrapper = wrapper.merge(wrapperEnter);
+      var tabs = tabsBar.selectAll(".tab").data(_dataShortcuts);
+      var tabsEnter = tabs.enter().append("a").attr("class", "tab").attr("href", "#").on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        var i3 = _dataShortcuts.indexOf(d2);
+        _activeTab = i3;
+        render(selection2);
       });
-      entries.exit().style("top", "0").style("max-height", "240px").transition().duration(200).style("opacity", "0").style("max-height", "0px").remove();
-      var entriesEnter = entries.enter().append("div").attr("class", "entry").each(function(_2, index) {
-        var wrap2 = select_default2(this);
-        var domId = utilUniqueDomId(index);
-        var label = wrap2.append("label").attr("class", "field-label").attr("for", domId);
-        var text = label.append("span").attr("class", "label-text");
-        text.append("span").attr("class", "label-textvalue").call(_t.append("translate.localized_translation_label"));
-        text.append("span").attr("class", "label-textannotation");
-        label.append("button").attr("class", "remove-icon-multilingual").attr("title", _t("icons.remove")).on("click", function(d3_event, d2) {
-          if (field.locked())
-            return;
-          d3_event.preventDefault();
-          _multilingual.splice(_multilingual.indexOf(d2), 1);
-          var langKey = d2.lang && key(d2.lang);
-          if (langKey && langKey in _tags) {
-            delete _tags[langKey];
-            var t2 = {};
-            t2[langKey] = void 0;
-            dispatch14.call("change", this, t2);
-            return;
-          }
-          renderMultilingual(selection2);
-        }).call(svgIcon("#iD-operation-delete"));
-        wrap2.append("input").attr("class", "localized-lang").attr("id", domId).attr("type", "text").attr("placeholder", _t("translate.localized_translation_language")).on("blur", changeLang).on("change", changeLang).call(langCombo);
-        wrap2.append("input").attr("type", "text").attr("class", "localized-value").on("blur", changeValue).on("change", changeValue);
+      tabsEnter.append("span").html(function(d2) {
+        return _t.html(d2.text);
       });
-      entriesEnter.style("margin-top", "0px").style("max-height", "0px").style("opacity", "0").transition().duration(200).style("margin-top", "10px").style("max-height", "240px").style("opacity", "1").on("end", function() {
-        select_default2(this).style("max-height", "").style("overflow", "visible");
+      wrapper.selectAll(".tab").classed("active", function(d2, i3) {
+        return i3 === _activeTab;
       });
-      entries = entries.merge(entriesEnter);
-      entries.order();
-      entries.classed("present", true);
-      utilGetSetValue(entries.select(".localized-lang"), function(d2) {
-        var langItem = _languagesArray.find(function(item) {
-          return item.code === d2.lang;
-        });
-        if (langItem)
-          return langItem.label;
-        return d2.lang;
+      var shortcuts = shortcutsList.selectAll(".shortcut-tab").data(_dataShortcuts);
+      var shortcutsEnter = shortcuts.enter().append("div").attr("class", function(d2) {
+        return "shortcut-tab shortcut-tab-" + d2.tab;
       });
-      utilGetSetValue(entries.select(".localized-value"), function(d2) {
-        return typeof d2.value === "string" ? d2.value : "";
-      }).attr("title", function(d2) {
-        return Array.isArray(d2.value) ? d2.value.filter(Boolean).join("\n") : null;
-      }).attr("placeholder", function(d2) {
-        return Array.isArray(d2.value) ? _t("inspector.multiple_values") : _t("translate.localized_translation_name");
-      }).classed("mixed", function(d2) {
-        return Array.isArray(d2.value);
+      var columnsEnter = shortcutsEnter.selectAll(".shortcut-column").data(function(d2) {
+        return d2.columns;
+      }).enter().append("table").attr("class", "shortcut-column");
+      var rowsEnter = columnsEnter.selectAll(".shortcut-row").data(function(d2) {
+        return d2.rows;
+      }).enter().append("tr").attr("class", "shortcut-row");
+      var sectionRows = rowsEnter.filter(function(d2) {
+        return !d2.shortcuts;
       });
-    }
-    localized.tags = function(tags) {
-      _tags = tags;
-      if (typeof tags.wikipedia === "string" && !_wikiTitles) {
-        _wikiTitles = {};
-        var wm = tags.wikipedia.match(/([^:]+):(.+)/);
-        if (wm && wm[0] && wm[1]) {
-          wikipedia.translations(wm[1], wm[2], function(err, d2) {
-            if (err || !d2)
-              return;
-            _wikiTitles = d2;
+      sectionRows.append("td");
+      sectionRows.append("td").attr("class", "shortcut-section").append("h3").html(function(d2) {
+        return _t.html(d2.text);
+      });
+      var shortcutRows = rowsEnter.filter(function(d2) {
+        return d2.shortcuts;
+      });
+      var shortcutKeys = shortcutRows.append("td").attr("class", "shortcut-keys");
+      var modifierKeys = shortcutKeys.filter(function(d2) {
+        return d2.modifiers;
+      });
+      modifierKeys.selectAll("kbd.modifier").data(function(d2) {
+        if (detected.os === "win" && d2.text === "shortcuts.editing.commands.redo") {
+          return ["\u2318"];
+        } else if (detected.os !== "mac" && d2.text === "shortcuts.browsing.display_options.fullscreen") {
+          return [];
+        } else {
+          return d2.modifiers;
+        }
+      }).enter().each(function() {
+        var selection3 = select_default2(this);
+        selection3.append("kbd").attr("class", "modifier").text(function(d2) {
+          return uiCmd.display(d2);
+        });
+        selection3.append("span").text("+");
+      });
+      shortcutKeys.selectAll("kbd.shortcut").data(function(d2) {
+        var arr = d2.shortcuts;
+        if (detected.os === "win" && d2.text === "shortcuts.editing.commands.redo") {
+          arr = ["Y"];
+        } else if (detected.os !== "mac" && d2.text === "shortcuts.browsing.display_options.fullscreen") {
+          arr = ["F11"];
+        }
+        arr = arr.map(function(s2) {
+          return uiCmd.display(s2.indexOf(".") !== -1 ? _t(s2) : s2);
+        });
+        return utilArrayUniq(arr).map(function(s2) {
+          return {
+            shortcut: s2,
+            separator: d2.separator,
+            suffix: d2.suffix
+          };
+        });
+      }).enter().each(function(d2, i3, nodes) {
+        var selection3 = select_default2(this);
+        var click = d2.shortcut.toLowerCase().match(/(.*).click/);
+        if (click && click[1]) {
+          selection3.call(svgIcon("#iD-walkthrough-mouse-" + click[1], "operation"));
+        } else if (d2.shortcut.toLowerCase() === "long-press") {
+          selection3.call(svgIcon("#iD-walkthrough-longpress", "longpress operation"));
+        } else if (d2.shortcut.toLowerCase() === "tap") {
+          selection3.call(svgIcon("#iD-walkthrough-tap", "tap operation"));
+        } else {
+          selection3.append("kbd").attr("class", "shortcut").text(function(d4) {
+            return d4.shortcut;
           });
         }
-      }
-      var isMixed = Array.isArray(tags[field.key]);
-      utilGetSetValue(input, typeof tags[field.key] === "string" ? tags[field.key] : "").attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder()).classed("mixed", isMixed);
-      calcMultilingual(tags);
-      _selection.call(localized);
-      if (!isMixed) {
-        _lengthIndicator.update(tags[field.key]);
-      }
-    };
-    localized.focus = function() {
-      input.node().focus();
-    };
-    localized.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      _multilingual = [];
-      loadCountryCode();
-      return localized;
-    };
-    function loadCountryCode() {
-      var extent = combinedEntityExtent();
-      var countryCode = extent && iso1A2Code(extent.center());
-      _countryCode = countryCode && countryCode.toLowerCase();
-    }
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+        if (i3 < nodes.length - 1) {
+          selection3.append("span").html(d2.separator || "\xA0" + _t.html("shortcuts.or") + "\xA0");
+        } else if (i3 === nodes.length - 1 && d2.suffix) {
+          selection3.append("span").text(d2.suffix);
+        }
+      });
+      shortcutKeys.filter(function(d2) {
+        return d2.gesture;
+      }).each(function() {
+        var selection3 = select_default2(this);
+        selection3.append("span").text("+");
+        selection3.append("span").attr("class", "gesture").html(function(d2) {
+          return _t.html(d2.gesture);
+        });
+      });
+      shortcutRows.append("td").attr("class", "shortcut-desc").html(function(d2) {
+        return d2.text ? _t.html(d2.text) : "\xA0";
+      });
+      wrapper.selectAll(".shortcut-tab").style("display", function(d2, i3) {
+        return i3 === _activeTab ? "flex" : "none";
+      });
     }
-    return utilRebind(localized, dispatch14, "on");
+    return function(selection2, show) {
+      _selection = selection2;
+      if (show) {
+        _modalSelection = uiModal(selection2);
+        _modalSelection.call(shortcutsModal);
+      } else {
+        context.keybinding().on([_t("shortcuts.toggle.key"), "?"], function() {
+          if (context.container().selectAll(".modal-shortcuts").size()) {
+            if (_modalSelection) {
+              _modalSelection.close();
+              _modalSelection = null;
+            }
+          } else {
+            _modalSelection = uiModal(_selection);
+            _modalSelection.call(shortcutsModal);
+          }
+        });
+      }
+    };
   }
 
-  // modules/ui/fields/roadheight.js
-  function uiFieldRoadheight(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var primaryUnitInput = select_default2(null);
-    var primaryInput = select_default2(null);
-    var secondaryInput = select_default2(null);
-    var secondaryUnitInput = select_default2(null);
-    var _entityIDs = [];
-    var _tags;
-    var _isImperial;
-    var formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
-    var parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
-    var primaryUnits = [
-      {
-        value: "m",
-        title: _t("inspector.roadheight.meter")
-      },
-      {
-        value: "ft",
-        title: _t("inspector.roadheight.foot")
-      }
-    ];
-    var unitCombo = uiCombobox(context, "roadheight-unit").data(primaryUnits);
-    function roadheight(selection2) {
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      primaryInput = wrap2.selectAll("input.roadheight-number").data([0]);
-      primaryInput = primaryInput.enter().append("input").attr("type", "text").attr("class", "roadheight-number").attr("id", field.domId).call(utilNoAuto).merge(primaryInput);
-      primaryInput.on("change", change).on("blur", change);
-      var loc = combinedEntityExtent().center();
-      _isImperial = roadHeightUnit(loc) === "ft";
-      primaryUnitInput = wrap2.selectAll("input.roadheight-unit").data([0]);
-      primaryUnitInput = primaryUnitInput.enter().append("input").attr("type", "text").attr("class", "roadheight-unit").call(unitCombo).merge(primaryUnitInput);
-      primaryUnitInput.on("blur", changeUnits).on("change", changeUnits);
-      secondaryInput = wrap2.selectAll("input.roadheight-secondary-number").data([0]);
-      secondaryInput = secondaryInput.enter().append("input").attr("type", "text").attr("class", "roadheight-secondary-number").call(utilNoAuto).merge(secondaryInput);
-      secondaryInput.on("change", change).on("blur", change);
-      secondaryUnitInput = wrap2.selectAll("input.roadheight-secondary-unit").data([0]);
-      secondaryUnitInput = secondaryUnitInput.enter().append("input").attr("type", "text").call(utilNoAuto).classed("disabled", true).classed("roadheight-secondary-unit", true).attr("readonly", "readonly").merge(secondaryUnitInput);
-      function changeUnits() {
-        var primaryUnit = utilGetSetValue(primaryUnitInput);
-        if (primaryUnit === "m") {
-          _isImperial = false;
-        } else if (primaryUnit === "ft") {
-          _isImperial = true;
+  // modules/ui/data_header.js
+  function uiDataHeader() {
+    var _datum;
+    function dataHeader(selection2) {
+      var header = selection2.selectAll(".data-header").data(
+        _datum ? [_datum] : [],
+        function(d2) {
+          return d2.__featurehash__;
         }
-        utilGetSetValue(primaryUnitInput, _isImperial ? "ft" : "m");
-        setUnitSuggestions();
-        change();
-      }
-    }
-    function setUnitSuggestions() {
-      utilGetSetValue(primaryUnitInput, _isImperial ? "ft" : "m");
+      );
+      header.exit().remove();
+      var headerEnter = header.enter().append("div").attr("class", "data-header");
+      var iconEnter = headerEnter.append("div").attr("class", "data-header-icon");
+      iconEnter.append("div").attr("class", "preset-icon-28").call(svgIcon("#iD-icon-data", "note-fill"));
+      headerEnter.append("div").attr("class", "data-header-label").call(_t.append("map_data.layers.custom.title"));
     }
-    function change() {
-      var tag2 = {};
-      var primaryValue = utilGetSetValue(primaryInput).trim();
-      var secondaryValue = utilGetSetValue(secondaryInput).trim();
-      if (!primaryValue && !secondaryValue && Array.isArray(_tags[field.key]))
-        return;
-      if (!primaryValue && !secondaryValue) {
-        tag2[field.key] = void 0;
+    dataHeader.datum = function(val) {
+      if (!arguments.length) return _datum;
+      _datum = val;
+      return this;
+    };
+    return dataHeader;
+  }
+
+  // modules/ui/disclosure.js
+  function uiDisclosure(context, key, expandedDefault) {
+    var dispatch14 = dispatch_default("toggled");
+    var _expanded;
+    var _label = utilFunctor("");
+    var _updatePreference = true;
+    var _content = function() {
+    };
+    var disclosure = function(selection2) {
+      if (_expanded === void 0 || _expanded === null) {
+        var preference = corePreferences("disclosure." + key + ".expanded");
+        _expanded = preference === null ? !!expandedDefault : preference === "true";
+      }
+      var hideToggle = selection2.selectAll(".hide-toggle-" + key).data([0]);
+      var hideToggleEnter = hideToggle.enter().append("h3").append("a").attr("role", "button").attr("href", "#").attr("class", "hide-toggle hide-toggle-" + key).call(svgIcon("", "pre-text", "hide-toggle-icon"));
+      hideToggleEnter.append("span").attr("class", "hide-toggle-text");
+      hideToggle = hideToggleEnter.merge(hideToggle);
+      hideToggle.on("click", toggle).attr("title", _t("icons.".concat(_expanded ? "collapse" : "expand"))).attr("aria-expanded", _expanded).classed("expanded", _expanded);
+      const label = _label();
+      const labelSelection = hideToggle.selectAll(".hide-toggle-text");
+      if (typeof label !== "function") {
+        labelSelection.text(_label());
       } else {
-        var rawPrimaryValue = likelyRawNumberFormat.test(primaryValue) ? parseFloat(primaryValue) : parseLocaleFloat(primaryValue);
-        if (isNaN(rawPrimaryValue))
-          rawPrimaryValue = primaryValue;
-        var rawSecondaryValue = likelyRawNumberFormat.test(secondaryValue) ? parseFloat(secondaryValue) : parseLocaleFloat(secondaryValue);
-        if (isNaN(rawSecondaryValue))
-          rawSecondaryValue = secondaryValue;
-        if (isNaN(rawPrimaryValue) || isNaN(rawSecondaryValue) || !_isImperial) {
-          tag2[field.key] = context.cleanTagValue(rawPrimaryValue);
-        } else {
-          if (rawPrimaryValue !== "") {
-            rawPrimaryValue = rawPrimaryValue + "'";
-          }
-          if (rawSecondaryValue !== "") {
-            rawSecondaryValue = rawSecondaryValue + '"';
-          }
-          tag2[field.key] = context.cleanTagValue(rawPrimaryValue + rawSecondaryValue);
-        }
+        labelSelection.text("").call(label);
       }
-      dispatch14.call("change", this, tag2);
-    }
-    roadheight.tags = function(tags) {
-      _tags = tags;
-      var primaryValue = tags[field.key];
-      var secondaryValue;
-      var isMixed = Array.isArray(primaryValue);
-      if (!isMixed) {
-        if (primaryValue && (primaryValue.indexOf("'") >= 0 || primaryValue.indexOf('"') >= 0)) {
-          secondaryValue = primaryValue.match(/(-?[\d.]+)"/);
-          if (secondaryValue !== null) {
-            secondaryValue = formatFloat(parseFloat(secondaryValue[1]));
-          }
-          primaryValue = primaryValue.match(/(-?[\d.]+)'/);
-          if (primaryValue !== null) {
-            primaryValue = formatFloat(parseFloat(primaryValue[1]));
-          }
-          _isImperial = true;
-        } else if (primaryValue) {
-          var rawValue = primaryValue;
-          primaryValue = parseFloat(rawValue);
-          if (isNaN(primaryValue)) {
-            primaryValue = rawValue;
-          } else {
-            primaryValue = formatFloat(primaryValue);
-          }
-          _isImperial = false;
+      hideToggle.selectAll(".hide-toggle-icon").attr(
+        "xlink:href",
+        _expanded ? "#iD-icon-down" : _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward"
+      );
+      var wrap2 = selection2.selectAll(".disclosure-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "disclosure-wrap disclosure-wrap-" + key).merge(wrap2).classed("hide", !_expanded);
+      if (_expanded) {
+        wrap2.call(_content);
+      }
+      function toggle(d3_event) {
+        d3_event.preventDefault();
+        _expanded = !_expanded;
+        if (_updatePreference) {
+          corePreferences("disclosure." + key + ".expanded", _expanded);
+        }
+        hideToggle.classed("expanded", _expanded).attr("aria-expanded", _expanded).attr("title", _t("icons.".concat(_expanded ? "collapse" : "expand")));
+        hideToggle.selectAll(".hide-toggle-icon").attr(
+          "xlink:href",
+          _expanded ? "#iD-icon-down" : _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward"
+        );
+        wrap2.call(uiToggle(_expanded));
+        if (_expanded) {
+          wrap2.call(_content);
         }
+        dispatch14.call("toggled", this, _expanded);
       }
-      setUnitSuggestions();
-      var inchesPlaceholder = formatFloat(0);
-      utilGetSetValue(primaryInput, typeof primaryValue === "string" ? primaryValue : "").attr("title", isMixed ? primaryValue.filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : _t("inspector.unknown")).classed("mixed", isMixed);
-      utilGetSetValue(secondaryInput, typeof secondaryValue === "string" ? secondaryValue : "").attr("placeholder", isMixed ? _t("inspector.multiple_values") : _isImperial ? inchesPlaceholder : null).classed("mixed", isMixed).classed("disabled", !_isImperial).attr("readonly", _isImperial ? null : "readonly");
-      secondaryUnitInput.attr("value", _isImperial ? _t("inspector.roadheight.inch") : null);
     };
-    roadheight.focus = function() {
-      primaryInput.node().focus();
+    disclosure.label = function(val) {
+      if (!arguments.length) return _label;
+      _label = utilFunctor(val);
+      return disclosure;
     };
-    roadheight.entityIDs = function(val) {
-      _entityIDs = val;
+    disclosure.expanded = function(val) {
+      if (!arguments.length) return _expanded;
+      _expanded = val;
+      return disclosure;
     };
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
-    }
-    return utilRebind(roadheight, dispatch14, "on");
+    disclosure.updatePreference = function(val) {
+      if (!arguments.length) return _updatePreference;
+      _updatePreference = val;
+      return disclosure;
+    };
+    disclosure.content = function(val) {
+      if (!arguments.length) return _content;
+      _content = val;
+      return disclosure;
+    };
+    return utilRebind(disclosure, dispatch14, "on");
   }
 
-  // modules/ui/fields/roadspeed.js
-  function uiFieldRoadspeed(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var unitInput = select_default2(null);
-    var input = select_default2(null);
-    var _entityIDs = [];
-    var _tags;
-    var _isImperial;
-    var formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
-    var parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
-    var speedCombo = uiCombobox(context, "roadspeed");
-    var unitCombo = uiCombobox(context, "roadspeed-unit").data(["km/h", "mph"].map(comboValues));
-    var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
-    var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
-    function roadspeed(selection2) {
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      input = wrap2.selectAll("input.roadspeed-number").data([0]);
-      input = input.enter().append("input").attr("type", "text").attr("class", "roadspeed-number").attr("id", field.domId).call(utilNoAuto).call(speedCombo).merge(input);
-      input.on("change", change).on("blur", change);
-      var loc = combinedEntityExtent().center();
-      _isImperial = roadSpeedUnit(loc) === "mph";
-      unitInput = wrap2.selectAll("input.roadspeed-unit").data([0]);
-      unitInput = unitInput.enter().append("input").attr("type", "text").attr("class", "roadspeed-unit").attr("aria-label", _t("inspector.speed_unit")).call(unitCombo).merge(unitInput);
-      unitInput.on("blur", changeUnits).on("change", changeUnits);
-      function changeUnits() {
-        var unit2 = utilGetSetValue(unitInput);
-        if (unit2 === "km/h") {
-          _isImperial = false;
-        } else if (unit2 === "mph") {
-          _isImperial = true;
+  // modules/ui/section.js
+  function uiSection(id2, context) {
+    var _classes = utilFunctor("");
+    var _shouldDisplay;
+    var _content;
+    var _disclosure;
+    var _label;
+    var _expandedByDefault = utilFunctor(true);
+    var _disclosureContent;
+    var _disclosureExpanded;
+    var _containerSelection = select_default2(null);
+    var section = {
+      id: id2
+    };
+    section.classes = function(val) {
+      if (!arguments.length) return _classes;
+      _classes = utilFunctor(val);
+      return section;
+    };
+    section.label = function(val) {
+      if (!arguments.length) return _label;
+      _label = utilFunctor(val);
+      return section;
+    };
+    section.expandedByDefault = function(val) {
+      if (!arguments.length) return _expandedByDefault;
+      _expandedByDefault = utilFunctor(val);
+      return section;
+    };
+    section.shouldDisplay = function(val) {
+      if (!arguments.length) return _shouldDisplay;
+      _shouldDisplay = utilFunctor(val);
+      return section;
+    };
+    section.content = function(val) {
+      if (!arguments.length) return _content;
+      _content = val;
+      return section;
+    };
+    section.disclosureContent = function(val) {
+      if (!arguments.length) return _disclosureContent;
+      _disclosureContent = val;
+      return section;
+    };
+    section.disclosureExpanded = function(val) {
+      if (!arguments.length) return _disclosureExpanded;
+      _disclosureExpanded = val;
+      return section;
+    };
+    section.render = function(selection2) {
+      _containerSelection = selection2.selectAll(".section-" + id2).data([0]);
+      var sectionEnter = _containerSelection.enter().append("div").attr("class", "section section-" + id2 + " " + (_classes && _classes() || ""));
+      _containerSelection = sectionEnter.merge(_containerSelection);
+      _containerSelection.call(renderContent);
+    };
+    section.reRender = function() {
+      _containerSelection.call(renderContent);
+    };
+    section.selection = function() {
+      return _containerSelection;
+    };
+    section.disclosure = function() {
+      return _disclosure;
+    };
+    function renderContent(selection2) {
+      if (_shouldDisplay) {
+        var shouldDisplay = _shouldDisplay();
+        selection2.classed("hide", !shouldDisplay);
+        if (!shouldDisplay) {
+          selection2.html("");
+          return;
         }
-        utilGetSetValue(unitInput, _isImperial ? "mph" : "km/h");
-        setUnitSuggestions();
-        change();
+      }
+      if (_disclosureContent) {
+        if (!_disclosure) {
+          _disclosure = uiDisclosure(context, id2.replace(/-/g, "_"), _expandedByDefault()).label(_label || "").content(_disclosureContent);
+        }
+        if (_disclosureExpanded !== void 0) {
+          _disclosure.expanded(_disclosureExpanded);
+          _disclosureExpanded = void 0;
+        }
+        selection2.call(_disclosure);
+        return;
+      }
+      if (_content) {
+        selection2.call(_content);
       }
     }
-    function setUnitSuggestions() {
-      speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
-      utilGetSetValue(unitInput, _isImperial ? "mph" : "km/h");
-    }
-    function comboValues(d2) {
-      return {
-        value: formatFloat(d2),
-        title: formatFloat(d2)
-      };
+    return section;
+  }
+
+  // modules/ui/tag_reference.js
+  function uiTagReference(what) {
+    var wikibase = what.qid ? services.wikidata : services.osmWikibase;
+    var tagReference = {};
+    var _button = select_default2(null);
+    var _body = select_default2(null);
+    var _loaded;
+    var _showing;
+    function load() {
+      if (!wikibase) return;
+      _button.classed("tag-reference-loading", true);
+      wikibase.getDocs(what, gotDocs);
     }
-    function change() {
-      var tag2 = {};
-      var value = utilGetSetValue(input).trim();
-      if (!value && Array.isArray(_tags[field.key]))
+    function gotDocs(err, docs) {
+      _body.html("");
+      if (!docs || !docs.title) {
+        _body.append("p").attr("class", "tag-reference-description").call(_t.append("inspector.no_documentation_key"));
+        done();
         return;
-      if (!value) {
-        tag2[field.key] = void 0;
+      }
+      if (docs.imageURL) {
+        _body.append("img").attr("class", "tag-reference-wiki-image").attr("alt", docs.description).attr("src", docs.imageURL).on("load", function() {
+          done();
+        }).on("error", function() {
+          select_default2(this).remove();
+          done();
+        });
       } else {
-        var rawValue = likelyRawNumberFormat.test(value) ? parseFloat(value) : parseLocaleFloat(value);
-        if (isNaN(rawValue))
-          rawValue = value;
-        if (isNaN(rawValue) || !_isImperial) {
-          tag2[field.key] = context.cleanTagValue(rawValue);
-        } else {
-          tag2[field.key] = context.cleanTagValue(rawValue + " mph");
-        }
+        done();
+      }
+      var tagReferenceDescription = _body.append("p").attr("class", "tag-reference-description").append("span");
+      if (docs.description) {
+        tagReferenceDescription = tagReferenceDescription.attr("class", "localized-text").attr("lang", docs.descriptionLocaleCode || "und").text(docs.description);
+      } else {
+        tagReferenceDescription = tagReferenceDescription.call(_t.append("inspector.no_documentation_key"));
+      }
+      tagReferenceDescription.append("a").attr("class", "tag-reference-edit").attr("target", "_blank").attr("title", _t("inspector.edit_reference")).attr("href", docs.editURL).call(svgIcon("#iD-icon-edit", "inline"));
+      if (docs.wiki) {
+        _body.append("a").attr("class", "tag-reference-link").attr("target", "_blank").attr("href", docs.wiki.url).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append(docs.wiki.text));
+      }
+      if (what.key === "comment") {
+        _body.append("a").attr("class", "tag-reference-comment-link").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", _t("commit.about_changeset_comments_link")).append("span").call(_t.append("commit.about_changeset_comments"));
       }
-      dispatch14.call("change", this, tag2);
     }
-    roadspeed.tags = function(tags) {
-      _tags = tags;
-      var rawValue = tags[field.key];
-      var value = rawValue;
-      var isMixed = Array.isArray(value);
-      if (!isMixed) {
-        if (rawValue && rawValue.indexOf("mph") >= 0) {
-          _isImperial = true;
-        } else if (rawValue) {
-          _isImperial = false;
+    function done() {
+      _loaded = true;
+      _button.classed("tag-reference-loading", false);
+      _body.classed("expanded", true).transition().duration(200).style("max-height", "200px").style("opacity", "1");
+      _showing = true;
+      _button.selectAll("svg.icon use").each(function() {
+        var iconUse = select_default2(this);
+        if (iconUse.attr("href") === "#iD-icon-info") {
+          iconUse.attr("href", "#iD-icon-info-filled");
         }
-        value = parseInt(value, 10);
-        if (isNaN(value)) {
-          value = rawValue;
+      });
+    }
+    function hide() {
+      _body.transition().duration(200).style("max-height", "0px").style("opacity", "0").on("end", function() {
+        _body.classed("expanded", false);
+      });
+      _showing = false;
+      _button.selectAll("svg.icon use").each(function() {
+        var iconUse = select_default2(this);
+        if (iconUse.attr("href") === "#iD-icon-info-filled") {
+          iconUse.attr("href", "#iD-icon-info");
+        }
+      });
+    }
+    tagReference.button = function(selection2, klass, iconName) {
+      _button = selection2.selectAll(".tag-reference-button").data([0]);
+      _button = _button.enter().append("button").attr("class", "tag-reference-button " + (klass || "")).attr("title", _t("icons.information")).call(svgIcon("#iD-icon-" + (iconName || "inspect"))).merge(_button);
+      _button.on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        this.blur();
+        if (_showing) {
+          hide();
+        } else if (_loaded) {
+          done();
         } else {
-          value = formatFloat(value);
+          load();
         }
-      }
-      setUnitSuggestions();
-      utilGetSetValue(input, typeof value === "string" ? value : "").attr("title", isMixed ? value.filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder()).classed("mixed", isMixed);
+      });
     };
-    roadspeed.focus = function() {
-      input.node().focus();
+    tagReference.body = function(selection2) {
+      var itemID = what.qid || what.key + "-" + (what.value || "");
+      _body = selection2.selectAll(".tag-reference-body").data([itemID], function(d2) {
+        return d2;
+      });
+      _body.exit().remove();
+      _body = _body.enter().append("div").attr("class", "tag-reference-body").style("max-height", "0").style("opacity", "0").merge(_body);
+      if (_showing === false) {
+        hide();
+      }
     };
-    roadspeed.entityIDs = function(val) {
-      _entityIDs = val;
+    tagReference.showing = function(val) {
+      if (!arguments.length) return _showing;
+      _showing = val;
+      return tagReference;
     };
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
-    }
-    return utilRebind(roadspeed, dispatch14, "on");
+    return tagReference;
   }
 
-  // modules/ui/fields/radio.js
-  function uiFieldRadio(field, context) {
+  // modules/ui/sections/raw_tag_editor.js
+  function uiSectionRawTagEditor(id2, context) {
+    var section = uiSection(id2, context).classes("raw-tag-editor").label(function() {
+      var count = Object.keys(_tags).filter(function(d2) {
+        return d2;
+      }).length;
+      return _t.append("inspector.title_count", { title: _t("inspector.tags"), count });
+    }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
+    var taginfo = services.taginfo;
     var dispatch14 = dispatch_default("change");
-    var placeholder = select_default2(null);
-    var wrap2 = select_default2(null);
-    var labels = select_default2(null);
-    var radios = select_default2(null);
-    var radioData = (field.options || field.keys).slice();
-    var typeField;
-    var layerField;
-    var _oldType = {};
-    var _entityIDs = [];
-    function selectedKey() {
-      var node = wrap2.selectAll(".form-field-input-radio label.active input");
-      return !node.empty() && node.datum();
+    var availableViews = [
+      { id: "list", icon: "#fas-th-list" },
+      { id: "text", icon: "#fas-i-cursor" }
+    ];
+    let _discardTags = {};
+    _mainFileFetcher.get("discarded").then((d2) => {
+      _discardTags = d2;
+    }).catch(() => {
+    });
+    var _tagView = corePreferences("raw-tag-editor-view") || "list";
+    var _readOnlyTags = [];
+    var _orderedKeys = [];
+    var _showBlank = false;
+    var _pendingChange = null;
+    var _state;
+    var _presets;
+    var _tags;
+    var _entityIDs;
+    var _didInteract = false;
+    function interacted() {
+      _didInteract = true;
     }
-    function radio(selection2) {
-      selection2.classed("preset-radio", true);
-      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      var enter = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-radio");
-      enter.append("span").attr("class", "placeholder");
-      wrap2 = wrap2.merge(enter);
-      placeholder = wrap2.selectAll(".placeholder");
-      labels = wrap2.selectAll("label").data(radioData);
-      enter = labels.enter().append("label");
-      var stringsField = field.resolveReference("stringsCrossReference");
-      enter.append("input").attr("type", "radio").attr("name", field.id).attr("value", function(d2) {
-        return stringsField.t("options." + d2, { "default": d2 });
-      }).attr("checked", false);
-      enter.append("span").each(function(d2) {
-        stringsField.t.append("options." + d2, { "default": d2 })(select_default2(this));
+    function renderDisclosureContent(wrap2) {
+      _orderedKeys = _orderedKeys.filter(function(key) {
+        return _tags[key] !== void 0;
       });
-      labels = labels.merge(enter);
-      radios = labels.selectAll("input").on("change", changeRadio);
-    }
-    function structureExtras(selection2, tags) {
-      var selected = selectedKey() || tags.layer !== void 0;
-      var type2 = _mainPresetIndex.field(selected);
-      var layer = _mainPresetIndex.field("layer");
-      var showLayer = selected === "bridge" || selected === "tunnel" || tags.layer !== void 0;
-      var extrasWrap = selection2.selectAll(".structure-extras-wrap").data(selected ? [0] : []);
-      extrasWrap.exit().remove();
-      extrasWrap = extrasWrap.enter().append("div").attr("class", "structure-extras-wrap").merge(extrasWrap);
-      var list2 = extrasWrap.selectAll("ul").data([0]);
-      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
-      if (type2) {
-        if (!typeField || typeField.id !== selected) {
-          typeField = uiField(context, type2, _entityIDs, { wrap: false }).on("change", changeType);
-        }
-        typeField.tags(tags);
-      } else {
-        typeField = null;
+      var all = Object.keys(_tags).sort();
+      var missingKeys = utilArrayDifference(all, _orderedKeys);
+      for (var i3 in missingKeys) {
+        _orderedKeys.push(missingKeys[i3]);
       }
-      var typeItem = list2.selectAll(".structure-type-item").data(typeField ? [typeField] : [], function(d2) {
-        return d2.id;
+      var rowData = _orderedKeys.map(function(key, i4) {
+        return { index: i4, key, value: _tags[key] };
       });
-      typeItem.exit().remove();
-      var typeEnter = typeItem.enter().insert("li", ":first-child").attr("class", "labeled-input structure-type-item");
-      typeEnter.append("div").attr("class", "label structure-label-type").attr("for", "preset-input-" + selected).call(_t.append("inspector.radio.structure.type"));
-      typeEnter.append("div").attr("class", "structure-input-type-wrap");
-      typeItem = typeItem.merge(typeEnter);
-      if (typeField) {
-        typeItem.selectAll(".structure-input-type-wrap").call(typeField.render);
+      if (!rowData.length || _showBlank) {
+        _showBlank = false;
+        rowData.push({ index: rowData.length, key: "", value: "" });
       }
-      if (layer && showLayer) {
-        if (!layerField) {
-          layerField = uiField(context, layer, _entityIDs, { wrap: false }).on("change", changeLayer);
+      var options2 = wrap2.selectAll(".raw-tag-options").data([0]);
+      options2.exit().remove();
+      var optionsEnter = options2.enter().insert("div", ":first-child").attr("class", "raw-tag-options").attr("role", "tablist");
+      var optionEnter = optionsEnter.selectAll(".raw-tag-option").data(availableViews, function(d2) {
+        return d2.id;
+      }).enter();
+      optionEnter.append("button").attr("class", function(d2) {
+        return "raw-tag-option raw-tag-option-" + d2.id + (_tagView === d2.id ? " selected" : "");
+      }).attr("aria-selected", function(d2) {
+        return _tagView === d2.id;
+      }).attr("role", "tab").attr("title", function(d2) {
+        return _t("icons." + d2.id);
+      }).on("click", function(d3_event, d2) {
+        _tagView = d2.id;
+        corePreferences("raw-tag-editor-view", d2.id);
+        wrap2.selectAll(".raw-tag-option").classed("selected", function(datum2) {
+          return datum2 === d2;
+        }).attr("aria-selected", function(datum2) {
+          return datum2 === d2;
+        });
+        wrap2.selectAll(".tag-text").classed("hide", d2.id !== "text").each(setTextareaHeight);
+        wrap2.selectAll(".tag-list, .add-row").classed("hide", d2.id !== "list");
+      }).each(function(d2) {
+        select_default2(this).call(svgIcon(d2.icon));
+      });
+      var textData = rowsToText(rowData);
+      var textarea = wrap2.selectAll(".tag-text").data([0]);
+      textarea = textarea.enter().append("textarea").attr("class", "tag-text" + (_tagView !== "text" ? " hide" : "")).call(utilNoAuto).attr("placeholder", _t("inspector.key_value")).attr("spellcheck", "false").merge(textarea);
+      textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on("input", setTextareaHeight).on("focus", interacted).on("blur", textChanged).on("change", textChanged);
+      var list2 = wrap2.selectAll(".tag-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "tag-list" + (_tagView !== "list" ? " hide" : "")).merge(list2);
+      var addRowEnter = wrap2.selectAll(".add-row").data([0]).enter().append("div").attr("class", "add-row" + (_tagView !== "list" ? " hide" : ""));
+      addRowEnter.append("button").attr("class", "add-tag").attr("aria-label", _t("inspector.add_to_tag")).call(svgIcon("#iD-icon-plus", "light")).call(uiTooltip().title(() => _t.append("inspector.add_to_tag")).placement(_mainLocalizer.textDirection() === "ltr" ? "right" : "left")).on("click", addTag);
+      addRowEnter.append("div").attr("class", "space-value");
+      addRowEnter.append("div").attr("class", "space-buttons");
+      var items = list2.selectAll(".tag-row").data(rowData, function(d2) {
+        return d2.key;
+      });
+      items.exit().each(unbind).remove();
+      var itemsEnter = items.enter().append("li").attr("class", "tag-row").classed("readonly", isReadOnly);
+      var innerWrap = itemsEnter.append("div").attr("class", "inner-wrap");
+      innerWrap.append("div").attr("class", "key-wrap").append("input").property("type", "text").attr("class", "key").call(utilNoAuto).on("focus", interacted).on("blur", keyChange).on("change", keyChange);
+      innerWrap.append("div").attr("class", "value-wrap").append("input").property("type", "text").attr("class", "value").call(utilNoAuto).on("focus", interacted).on("blur", valueChange).on("change", valueChange).on("keydown.push-more", pushMore);
+      innerWrap.append("button").attr("class", "form-field-button remove").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
+      items = items.merge(itemsEnter).sort(function(a2, b2) {
+        return a2.index - b2.index;
+      });
+      items.each(function(d2) {
+        var row = select_default2(this);
+        var key = row.select("input.key");
+        var value = row.select("input.value");
+        if (_entityIDs && taginfo && _state !== "hover") {
+          bindTypeahead(key, value);
         }
-        layerField.tags(tags);
-        field.keys = utilArrayUnion(field.keys, ["layer"]);
+        var referenceOptions = { key: d2.key };
+        if (typeof d2.value === "string") {
+          referenceOptions.value = d2.value;
+        }
+        var reference = uiTagReference(referenceOptions, context);
+        if (_state === "hover") {
+          reference.showing(false);
+        }
+        row.select(".inner-wrap").call(reference.button);
+        row.call(reference.body);
+        row.select("button.remove");
+      });
+      items.selectAll("input.key").attr("title", function(d2) {
+        return d2.key;
+      }).call(utilGetSetValue, function(d2) {
+        return d2.key;
+      }).attr("readonly", function(d2) {
+        return isReadOnly(d2) || null;
+      });
+      items.selectAll("input.value").attr("title", function(d2) {
+        return Array.isArray(d2.value) ? d2.value.filter(Boolean).join("\n") : d2.value;
+      }).classed("mixed", function(d2) {
+        return Array.isArray(d2.value);
+      }).attr("placeholder", function(d2) {
+        return typeof d2.value === "string" ? null : _t("inspector.multiple_values");
+      }).call(utilGetSetValue, function(d2) {
+        return typeof d2.value === "string" ? d2.value : "";
+      }).attr("readonly", function(d2) {
+        return isReadOnly(d2) || null;
+      });
+      items.selectAll("button.remove").on(
+        ("PointerEvent" in window ? "pointer" : "mouse") + "down",
+        // 'click' fires too late - #5878
+        (d3_event, d2) => {
+          if (d3_event.button !== 0) return;
+          removeTag(d3_event, d2);
+        }
+      );
+    }
+    function isReadOnly(d2) {
+      for (var i3 = 0; i3 < _readOnlyTags.length; i3++) {
+        if (d2.key.match(_readOnlyTags[i3]) !== null) {
+          return true;
+        }
+      }
+      return false;
+    }
+    function setTextareaHeight() {
+      if (_tagView !== "text") return;
+      var selection2 = select_default2(this);
+      var matches = selection2.node().value.match(/\n/g);
+      var lineCount = 2 + Number(matches && matches.length);
+      var lineHeight = 20;
+      selection2.style("height", lineCount * lineHeight + "px");
+    }
+    function stringify3(s2) {
+      const stringified = JSON.stringify(s2).slice(1, -1);
+      if (stringified !== s2) {
+        return '"'.concat(stringified, '"');
       } else {
-        layerField = null;
-        field.keys = field.keys.filter(function(k2) {
-          return k2 !== "layer";
-        });
+        return s2;
       }
-      var layerItem = list2.selectAll(".structure-layer-item").data(layerField ? [layerField] : []);
-      layerItem.exit().remove();
-      var layerEnter = layerItem.enter().append("li").attr("class", "labeled-input structure-layer-item");
-      layerEnter.append("div").attr("class", "label structure-label-layer").attr("for", "preset-input-layer").call(_t.append("inspector.radio.structure.layer"));
-      layerEnter.append("div").attr("class", "structure-input-layer-wrap");
-      layerItem = layerItem.merge(layerEnter);
-      if (layerField) {
-        layerItem.selectAll(".structure-input-layer-wrap").call(layerField.render);
+    }
+    function unstringify(s2) {
+      const isQuoted = s2.length > 1 && s2.charAt(0) === '"' && s2.charAt(s2.length - 1) === '"';
+      if (isQuoted) {
+        try {
+          return JSON.parse(s2);
+        } catch {
+          return s2;
+        }
+      } else {
+        return s2;
       }
     }
-    function changeType(t2, onInput) {
-      var key = selectedKey();
-      if (!key)
-        return;
-      var val = t2[key];
-      if (val !== "no") {
-        _oldType[key] = val;
+    function rowsToText(rows) {
+      var str = rows.filter(function(row) {
+        return row.key && row.key.trim() !== "";
+      }).map(function(row) {
+        var rawVal = row.value;
+        if (typeof rawVal !== "string") rawVal = "*";
+        var val = rawVal ? stringify3(rawVal) : "";
+        return stringify3(row.key) + "=" + val;
+      }).join("\n");
+      if (_state !== "hover" && str.length) {
+        return str + "\n";
       }
-      if (field.type === "structureRadio") {
-        if (val === "no" || key !== "bridge" && key !== "tunnel" || key === "tunnel" && val === "building_passage") {
-          t2.layer = void 0;
+      return str;
+    }
+    function textChanged() {
+      var newText = this.value.trim();
+      var newTags = {};
+      newText.split("\n").forEach(function(row) {
+        var m2 = row.match(/^\s*([^=]+)=(.*)$/);
+        if (m2 !== null) {
+          var k2 = context.cleanTagKey(unstringify(m2[1].trim()));
+          var v2 = context.cleanTagValue(unstringify(m2[2].trim()));
+          newTags[k2] = v2;
         }
-        if (t2.layer === void 0) {
-          if (key === "bridge" && val !== "no") {
-            t2.layer = "1";
-          }
-          if (key === "tunnel" && val !== "no" && val !== "building_passage") {
-            t2.layer = "-1";
-          }
+      });
+      var tagDiff = utilTagDiff(_tags, newTags);
+      if (!tagDiff.length) return;
+      _pendingChange = _pendingChange || {};
+      tagDiff.forEach(function(change) {
+        if (isReadOnly({ key: change.key })) return;
+        if (change.newVal === "*" && typeof change.oldVal !== "string") return;
+        if (change.type === "-") {
+          _pendingChange[change.key] = void 0;
+        } else if (change.type === "+") {
+          _pendingChange[change.key] = change.newVal || "";
         }
+      });
+      if (Object.keys(_pendingChange).length === 0) {
+        _pendingChange = null;
+        return;
       }
-      dispatch14.call("change", this, t2, onInput);
+      scheduleChange();
     }
-    function changeLayer(t2, onInput) {
-      if (t2.layer === "0") {
-        t2.layer = void 0;
+    function pushMore(d3_event) {
+      if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll(".tag-list li:last-child input.value").node() === this && utilGetSetValue(select_default2(this))) {
+        addTag();
       }
-      dispatch14.call("change", this, t2, onInput);
     }
-    function changeRadio() {
-      var t2 = {};
-      var activeKey;
-      if (field.key) {
-        t2[field.key] = void 0;
+    function bindTypeahead(key, value) {
+      if (isReadOnly(key.datum())) return;
+      if (Array.isArray(value.datum().value)) {
+        value.call(uiCombobox(context, "tag-value").minItems(1).fetcher(function(value2, callback) {
+          var keyString = utilGetSetValue(key);
+          if (!_tags[keyString]) return;
+          var data = _tags[keyString].map(function(tagValue) {
+            if (!tagValue) {
+              return {
+                value: " ",
+                title: _t("inspector.empty"),
+                display: (selection2) => selection2.text("").classed("virtual-option", true).call(_t.append("inspector.empty"))
+              };
+            }
+            return {
+              value: tagValue,
+              title: tagValue
+            };
+          });
+          callback(data);
+        }));
+        return;
       }
-      radios.each(function(d2) {
-        var active = select_default2(this).property("checked");
-        if (active)
-          activeKey = d2;
-        if (field.key) {
-          if (active)
-            t2[field.key] = d2;
-        } else {
-          var val = _oldType[activeKey] || "yes";
-          t2[d2] = active ? val : void 0;
-        }
-      });
-      if (field.type === "structureRadio") {
-        if (activeKey === "bridge") {
-          t2.layer = "1";
-        } else if (activeKey === "tunnel" && t2.tunnel !== "building_passage") {
-          t2.layer = "-1";
-        } else {
-          t2.layer = void 0;
+      var geometry = context.graph().geometry(_entityIDs[0]);
+      key.call(uiCombobox(context, "tag-key").fetcher(function(value2, callback) {
+        taginfo.keys({
+          debounce: true,
+          geometry,
+          query: value2
+        }, function(err, data) {
+          if (!err) {
+            const filtered = data.filter((d2) => _tags[d2.value] === void 0).filter((d2) => !(d2.value in _discardTags)).filter((d2) => !/_\d$/.test(d2)).filter((d2) => d2.value.toLowerCase().includes(value2.toLowerCase()));
+            callback(sort(value2, filtered));
+          }
+        });
+      }));
+      value.call(uiCombobox(context, "tag-value").fetcher(function(value2, callback) {
+        taginfo.values({
+          debounce: true,
+          key: utilGetSetValue(key),
+          geometry,
+          query: value2
+        }, function(err, data) {
+          if (!err) {
+            const filtered = data.filter((d2) => d2.value.toLowerCase().includes(value2.toLowerCase()));
+            callback(sort(value2, filtered));
+          }
+        });
+      }).caseSensitive(allowUpperCaseTagValues.test(utilGetSetValue(key))));
+      function sort(value2, data) {
+        var sameletter = [];
+        var other = [];
+        for (var i3 = 0; i3 < data.length; i3++) {
+          if (data[i3].value.substring(0, value2.length) === value2) {
+            sameletter.push(data[i3]);
+          } else {
+            other.push(data[i3]);
+          }
         }
+        return sameletter.concat(other);
       }
-      dispatch14.call("change", this, t2);
     }
-    radio.tags = function(tags) {
-      function isOptionChecked(d2) {
-        if (field.key) {
-          return tags[field.key] === d2;
-        }
-        return !!(typeof tags[d2] === "string" && tags[d2].toLowerCase() !== "no");
+    function unbind() {
+      var row = select_default2(this);
+      row.selectAll("input.key").call(uiCombobox.off, context);
+      row.selectAll("input.value").call(uiCombobox.off, context);
+    }
+    function keyChange(d3_event, d2) {
+      if (select_default2(this).attr("readonly")) return;
+      var kOld = d2.key;
+      if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === void 0) return;
+      var kNew = context.cleanTagKey(this.value.trim());
+      if (isReadOnly({ key: kNew })) {
+        this.value = kOld;
+        return;
       }
-      function isMixed(d2) {
-        if (field.key) {
-          return Array.isArray(tags[field.key]) && tags[field.key].includes(d2);
-        }
-        return Array.isArray(tags[d2]);
+      if (kNew && kNew !== kOld && _tags[kNew] !== void 0) {
+        this.value = kOld;
+        section.selection().selectAll(".tag-list input.value").each(function(d4) {
+          if (d4.key === kNew) {
+            var input = select_default2(this).node();
+            input.focus();
+            input.select();
+          }
+        });
+        return;
       }
-      radios.property("checked", function(d2) {
-        return isOptionChecked(d2) && (field.key || field.options.filter(isOptionChecked).length === 1);
-      });
-      labels.classed("active", function(d2) {
-        if (field.key) {
-          return Array.isArray(tags[field.key]) && tags[field.key].includes(d2) || tags[field.key] === d2;
-        }
-        return Array.isArray(tags[d2]) && tags[d2].some((v2) => typeof v2 === "string" && v2.toLowerCase() !== "no") || !!(typeof tags[d2] === "string" && tags[d2].toLowerCase() !== "no");
-      }).classed("mixed", isMixed).attr("title", function(d2) {
-        return isMixed(d2) ? _t("inspector.unshared_value_tooltip") : null;
-      });
-      var selection2 = radios.filter(function() {
-        return this.checked;
-      });
-      if (selection2.empty()) {
-        placeholder.text("");
-        placeholder.call(_t.append("inspector.none"));
+      _pendingChange = _pendingChange || {};
+      if (kOld) {
+        if (kOld === kNew) return;
+        _pendingChange[kNew] = _pendingChange[kOld] || { oldKey: kOld };
+        _pendingChange[kOld] = void 0;
       } else {
-        placeholder.text(selection2.attr("value"));
-        _oldType[selection2.datum()] = tags[selection2.datum()];
+        let row = this.parentNode.parentNode;
+        let inputVal = select_default2(row).selectAll("input.value");
+        let vNew = context.cleanTagValue(utilGetSetValue(inputVal));
+        _pendingChange[kNew] = vNew;
+        utilGetSetValue(inputVal, vNew);
       }
-      if (field.type === "structureRadio") {
-        if (!!tags.waterway && !_oldType.tunnel) {
-          _oldType.tunnel = "culvert";
-        }
-        wrap2.call(structureExtras, tags);
+      var existingKeyIndex = _orderedKeys.indexOf(kOld);
+      if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
+      d2.key = kNew;
+      this.value = kNew;
+      scheduleChange();
+    }
+    function valueChange(d3_event, d2) {
+      if (isReadOnly(d2)) return;
+      if (typeof d2.value !== "string" && !this.value) return;
+      if (_pendingChange && _pendingChange.hasOwnProperty(d2.key) && _pendingChange[d2.key] === void 0) return;
+      _pendingChange = _pendingChange || {};
+      _pendingChange[d2.key] = context.cleanTagValue(this.value);
+      scheduleChange();
+    }
+    function removeTag(d3_event, d2) {
+      if (isReadOnly(d2)) return;
+      if (d2.key === "") {
+        _showBlank = false;
+        section.reRender();
+      } else {
+        _orderedKeys = _orderedKeys.filter(function(key) {
+          return key !== d2.key;
+        });
+        _pendingChange = _pendingChange || {};
+        _pendingChange[d2.key] = void 0;
+        scheduleChange();
+      }
+    }
+    function addTag() {
+      window.setTimeout(function() {
+        _showBlank = true;
+        section.reRender();
+        section.selection().selectAll(".tag-list li:last-child input.key").node().focus();
+      }, 20);
+    }
+    function scheduleChange() {
+      var entityIDs = _entityIDs;
+      window.setTimeout(function() {
+        if (!_pendingChange) return;
+        dispatch14.call("change", this, entityIDs, _pendingChange);
+        _pendingChange = null;
+      }, 10);
+    }
+    section.state = function(val) {
+      if (!arguments.length) return _state;
+      if (_state !== val) {
+        _orderedKeys = [];
+        _state = val;
       }
+      return section;
     };
-    radio.focus = function() {
-      radios.node().focus();
+    section.presets = function(val) {
+      if (!arguments.length) return _presets;
+      _presets = val;
+      if (_presets && _presets.length && _presets[0].isFallback()) {
+        section.disclosureExpanded(true);
+      } else if (!_didInteract) {
+        section.disclosureExpanded(null);
+      }
+      return section;
     };
-    radio.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      _oldType = {};
-      return radio;
+    section.tags = function(val) {
+      if (!arguments.length) return _tags;
+      _tags = val;
+      return section;
     };
-    radio.isAllowed = function() {
-      return _entityIDs.length === 1;
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
+        _entityIDs = val;
+        _orderedKeys = [];
+      }
+      return section;
     };
-    return utilRebind(radio, dispatch14, "on");
+    section.readOnlyTags = function(val) {
+      if (!arguments.length) return _readOnlyTags;
+      _readOnlyTags = val;
+      return section;
+    };
+    return utilRebind(section, dispatch14, "on");
   }
 
-  // modules/ui/fields/restrictions.js
-  function uiFieldRestrictions(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var breathe = behaviorBreathe(context);
-    corePreferences("turn-restriction-via-way", null);
-    var storedViaWay = corePreferences("turn-restriction-via-way0");
-    var storedDistance = corePreferences("turn-restriction-distance");
-    var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
-    var _maxDistance = storedDistance ? +storedDistance : 30;
-    var _initialized3 = false;
-    var _parent = select_default2(null);
-    var _container = select_default2(null);
-    var _oldTurns;
-    var _graph;
-    var _vertexID;
-    var _intersection;
-    var _fromWayID;
-    var _lastXPos;
-    function restrictions(selection2) {
-      _parent = selection2;
-      if (_vertexID && (context.graph() !== _graph || !_intersection)) {
-        _graph = context.graph();
-        _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
-      }
-      var isOK = _intersection && _intersection.vertices.length && // has vertices
-      _intersection.vertices.filter(function(vertex) {
-        return vertex.id === _vertexID;
-      }).length && _intersection.ways.length > 2;
-      select_default2(selection2.node().parentNode).classed("hide", !isOK);
-      if (!isOK || !context.container().select(".inspector-wrap.inspector-hidden").empty() || !selection2.node().parentNode || !selection2.node().parentNode.parentNode) {
-        selection2.call(restrictions.off);
-        return;
-      }
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var container = wrap2.selectAll(".restriction-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "restriction-container");
-      containerEnter.append("div").attr("class", "restriction-help");
-      _container = containerEnter.merge(container).call(renderViewer);
-      var controls = wrap2.selectAll(".restriction-controls").data([0]);
-      controls.enter().append("div").attr("class", "restriction-controls-container").append("div").attr("class", "restriction-controls").merge(controls).call(renderControls);
-    }
-    function renderControls(selection2) {
-      var distControl = selection2.selectAll(".restriction-distance").data([0]);
-      distControl.exit().remove();
-      var distControlEnter = distControl.enter().append("div").attr("class", "restriction-control restriction-distance");
-      distControlEnter.append("span").attr("class", "restriction-control-label restriction-distance-label").call(_t.append("restriction.controls.distance", { suffix: ":" }));
-      distControlEnter.append("input").attr("class", "restriction-distance-input").attr("type", "range").attr("min", "20").attr("max", "50").attr("step", "5");
-      distControlEnter.append("span").attr("class", "restriction-distance-text");
-      selection2.selectAll(".restriction-distance-input").property("value", _maxDistance).on("input", function() {
-        var val = select_default2(this).property("value");
-        _maxDistance = +val;
-        _intersection = null;
-        _container.selectAll(".layer-osm .layer-turns *").remove();
-        corePreferences("turn-restriction-distance", _maxDistance);
-        _parent.call(restrictions);
-      });
-      selection2.selectAll(".restriction-distance-text").call(displayMaxDistance(_maxDistance));
-      var viaControl = selection2.selectAll(".restriction-via-way").data([0]);
-      viaControl.exit().remove();
-      var viaControlEnter = viaControl.enter().append("div").attr("class", "restriction-control restriction-via-way");
-      viaControlEnter.append("span").attr("class", "restriction-control-label restriction-via-way-label").call(_t.append("restriction.controls.via", { suffix: ":" }));
-      viaControlEnter.append("input").attr("class", "restriction-via-way-input").attr("type", "range").attr("min", "0").attr("max", "2").attr("step", "1");
-      viaControlEnter.append("span").attr("class", "restriction-via-way-text");
-      selection2.selectAll(".restriction-via-way-input").property("value", _maxViaWay).on("input", function() {
-        var val = select_default2(this).property("value");
-        _maxViaWay = +val;
-        _container.selectAll(".layer-osm .layer-turns *").remove();
-        corePreferences("turn-restriction-via-way0", _maxViaWay);
-        _parent.call(restrictions);
-      });
-      selection2.selectAll(".restriction-via-way-text").call(displayMaxVia(_maxViaWay));
+  // modules/ui/data_editor.js
+  function uiDataEditor(context) {
+    var dataHeader = uiDataHeader();
+    var rawTagEditor = uiSectionRawTagEditor("custom-data-tag-editor", context).expandedByDefault(true).readOnlyTags([/./]);
+    var _datum;
+    function dataEditor(selection2) {
+      var header = selection2.selectAll(".header").data([0]);
+      var headerEnter = header.enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
+        context.enter(modeBrowse(context));
+      }).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("map_data.title"));
+      var body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      var editor = body.selectAll(".data-editor").data([0]);
+      editor.enter().append("div").attr("class", "modal-section data-editor").merge(editor).call(dataHeader.datum(_datum));
+      var rte = body.selectAll(".raw-tag-editor").data([0]);
+      rte.enter().append("div").attr("class", "raw-tag-editor data-editor").merge(rte).call(
+        rawTagEditor.tags(_datum && _datum.properties || {}).state("hover").render
+      ).selectAll("textarea.tag-text").attr("readonly", true).classed("readonly", true);
     }
-    function renderViewer(selection2) {
-      if (!_intersection)
-        return;
-      var vgraph = _intersection.graph;
-      var filter2 = utilFunctor(true);
-      var projection2 = geoRawMercator();
-      var sdims = utilGetDimensions(context.container().select(".sidebar"));
-      var d2 = [sdims[0] - 50, 370];
-      var c2 = geoVecScale(d2, 0.5);
-      var z2 = 22;
-      projection2.scale(geoZoomToScale(z2));
-      var extent = geoExtent();
-      for (var i3 = 0; i3 < _intersection.vertices.length; i3++) {
-        extent._extend(_intersection.vertices[i3].extent());
+    dataEditor.datum = function(val) {
+      if (!arguments.length) return _datum;
+      _datum = val;
+      return this;
+    };
+    return dataEditor;
+  }
+
+  // modules/ui/feature_list.js
+  var sexagesimal = __toESM(require_sexagesimal());
+  function uiFeatureList(context) {
+    var _geocodeResults;
+    function featureList(selection2) {
+      var header = selection2.append("div").attr("class", "header fillL");
+      header.append("h2").call(_t.append("inspector.feature_list"));
+      var searchWrap = selection2.append("div").attr("class", "search-header");
+      searchWrap.call(svgIcon("#iD-icon-search", "pre-text"));
+      var search = searchWrap.append("input").attr("placeholder", _t("inspector.search")).attr("type", "search").call(utilNoAuto).on("keypress", keypress).on("keydown", keydown).on("input", inputevent);
+      var listWrap = selection2.append("div").attr("class", "inspector-body");
+      var list2 = listWrap.append("div").attr("class", "feature-list");
+      context.on("exit.feature-list", clearSearch);
+      context.map().on("drawn.feature-list", mapDrawn);
+      context.keybinding().on(uiCmd("\u2318F"), focusSearch);
+      function focusSearch(d3_event) {
+        var mode = context.mode() && context.mode().id;
+        if (mode !== "browse") return;
+        d3_event.preventDefault();
+        search.node().focus();
       }
-      var padTop = 35;
-      if (_intersection.vertices.length > 1) {
-        var hPadding = Math.min(160, Math.max(110, d2[0] * 0.4));
-        var vPadding = 160;
-        var tl = projection2([extent[0][0], extent[1][1]]);
-        var br2 = projection2([extent[1][0], extent[0][1]]);
-        var hFactor = (br2[0] - tl[0]) / (d2[0] - hPadding);
-        var vFactor = (br2[1] - tl[1]) / (d2[1] - vPadding - padTop);
-        var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
-        var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
-        z2 = z2 - Math.max(hZoomDiff, vZoomDiff);
-        projection2.scale(geoZoomToScale(z2));
+      function keydown(d3_event) {
+        if (d3_event.keyCode === 27) {
+          search.node().blur();
+        }
       }
-      var extentCenter = projection2(extent.center());
-      extentCenter[1] = extentCenter[1] - padTop / 2;
-      projection2.translate(geoVecSubtract(c2, extentCenter)).clipExtent([[0, 0], d2]);
-      var drawLayers = svgLayers(projection2, context).only(["osm", "touch"]).dimensions(d2);
-      var drawVertices = svgVertices(projection2, context);
-      var drawLines = svgLines(projection2, context);
-      var drawTurns = svgTurns(projection2, context);
-      var firstTime = selection2.selectAll(".surface").empty();
-      selection2.call(drawLayers);
-      var surface = selection2.selectAll(".surface").classed("tr", true);
-      if (firstTime) {
-        _initialized3 = true;
-        surface.call(breathe);
+      function keypress(d3_event) {
+        var q2 = search.property("value"), items = list2.selectAll(".feature-list-item");
+        if (d3_event.keyCode === 13 && // ↩ Return
+        q2.length && items.size()) {
+          click(d3_event, items.datum());
+        }
       }
-      if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
-        _fromWayID = null;
-        _oldTurns = null;
+      function inputevent() {
+        _geocodeResults = void 0;
+        drawList();
       }
-      surface.call(utilSetDimensions, d2).call(drawVertices, vgraph, _intersection.vertices, filter2, extent, z2).call(drawLines, vgraph, _intersection.ways, filter2).call(drawTurns, vgraph, _intersection.turns(_fromWayID, _maxViaWay));
-      surface.on("click.restrictions", click).on("mouseover.restrictions", mouseover);
-      surface.selectAll(".selected").classed("selected", false);
-      surface.selectAll(".related").classed("related", false);
-      var way;
-      if (_fromWayID) {
-        way = vgraph.entity(_fromWayID);
-        surface.selectAll("." + _fromWayID).classed("selected", true).classed("related", true);
+      function clearSearch() {
+        search.property("value", "");
+        drawList();
       }
-      document.addEventListener("resizeWindow", function() {
-        utilSetDimensions(_container, null);
-        redraw(1);
-      }, false);
-      updateHints(null);
-      function click(d3_event) {
-        surface.call(breathe.off).call(breathe);
-        var datum2 = d3_event.target.__data__;
-        var entity = datum2 && datum2.properties && datum2.properties.entity;
-        if (entity) {
-          datum2 = entity;
-        }
-        if (datum2 instanceof osmWay && (datum2.__from || datum2.__via)) {
-          _fromWayID = datum2.id;
-          _oldTurns = null;
-          redraw();
-        } else if (datum2 instanceof osmTurn) {
-          var actions, extraActions, turns, i4;
-          var restrictionType = osmInferRestriction(vgraph, datum2, projection2);
-          if (datum2.restrictionID && !datum2.direct) {
-            return;
-          } else if (datum2.restrictionID && !datum2.only) {
-            var seen = {};
-            var datumOnly = JSON.parse(JSON.stringify(datum2));
-            datumOnly.only = true;
-            restrictionType = restrictionType.replace(/^no/, "only");
-            turns = _intersection.turns(_fromWayID, 2);
-            extraActions = [];
-            _oldTurns = [];
-            for (i4 = 0; i4 < turns.length; i4++) {
-              var turn = turns[i4];
-              if (seen[turn.restrictionID])
-                continue;
-              if (turn.direct && turn.path[1] === datum2.path[1]) {
-                seen[turns[i4].restrictionID] = true;
-                turn.restrictionType = osmInferRestriction(vgraph, turn, projection2);
-                _oldTurns.push(turn);
-                extraActions.push(actionUnrestrictTurn(turn));
-              }
-            }
-            actions = _intersection.actions.concat(extraActions, [
-              actionRestrictTurn(datumOnly, restrictionType),
-              _t("operations.restriction.annotation.create")
-            ]);
-          } else if (datum2.restrictionID) {
-            turns = _oldTurns || [];
-            extraActions = [];
-            for (i4 = 0; i4 < turns.length; i4++) {
-              if (turns[i4].key !== datum2.key) {
-                extraActions.push(actionRestrictTurn(turns[i4], turns[i4].restrictionType));
-              }
-            }
-            _oldTurns = null;
-            actions = _intersection.actions.concat(extraActions, [
-              actionUnrestrictTurn(datum2),
-              _t("operations.restriction.annotation.delete")
-            ]);
-          } else {
-            actions = _intersection.actions.concat([
-              actionRestrictTurn(datum2, restrictionType),
-              _t("operations.restriction.annotation.create")
-            ]);
-          }
-          context.perform.apply(context, actions);
-          var s2 = surface.selectAll("." + datum2.key);
-          datum2 = s2.empty() ? null : s2.datum();
-          updateHints(datum2);
-        } else {
-          _fromWayID = null;
-          _oldTurns = null;
-          redraw();
+      function mapDrawn(e3) {
+        if (e3.full) {
+          drawList();
         }
       }
-      function mouseover(d3_event) {
-        var datum2 = d3_event.target.__data__;
-        updateHints(datum2);
-      }
-      _lastXPos = _lastXPos || sdims[0];
-      function redraw(minChange) {
-        var xPos = -1;
-        if (minChange) {
-          xPos = utilGetDimensions(context.container().select(".sidebar"))[0];
+      function features() {
+        var result = [];
+        var graph = context.graph();
+        var visibleCenter = context.map().extent().center();
+        var q2 = search.property("value").toLowerCase();
+        if (!q2) return result;
+        var locationMatch = sexagesimal.pair(q2.toUpperCase()) || dmsMatcher(q2);
+        if (locationMatch) {
+          var loc = [Number(locationMatch[0]), Number(locationMatch[1])];
+          result.push({
+            id: -1,
+            geometry: "point",
+            type: _t("inspector.location"),
+            name: dmsCoordinatePair([loc[1], loc[0]]),
+            location: loc
+          });
         }
-        if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
-          if (context.hasEntity(_vertexID)) {
-            _lastXPos = xPos;
-            _container.call(renderViewer);
-          }
+        var idMatch = !locationMatch && q2.match(/(?:^|\W)(node|way|relation|note|[nwr])\W{0,2}0*([1-9]\d*)(?:\W|$)/i);
+        if (idMatch) {
+          var elemType = idMatch[1] === "note" ? idMatch[1] : idMatch[1].charAt(0);
+          var elemId = idMatch[2];
+          result.push({
+            id: elemType + elemId,
+            geometry: elemType === "n" ? "point" : elemType === "w" ? "line" : elemType === "note" ? "note" : "relation",
+            type: elemType === "n" ? _t("inspector.node") : elemType === "w" ? _t("inspector.way") : elemType === "note" ? _t("note.note") : _t("inspector.relation"),
+            name: elemId
+          });
         }
-      }
-      function highlightPathsFrom(wayID) {
-        surface.selectAll(".related").classed("related", false).classed("allow", false).classed("restrict", false).classed("only", false);
-        surface.selectAll("." + wayID).classed("related", true);
-        if (wayID) {
-          var turns = _intersection.turns(wayID, _maxViaWay);
-          for (var i4 = 0; i4 < turns.length; i4++) {
-            var turn = turns[i4];
-            var ids = [turn.to.way];
-            var klass = turn.no ? "restrict" : turn.only ? "only" : "allow";
-            if (turn.only || turns.length === 1) {
-              if (turn.via.ways) {
-                ids = ids.concat(turn.via.ways);
-              }
-            } else if (turn.to.way === wayID) {
-              continue;
+        var allEntities = graph.entities;
+        var localResults = [];
+        for (var id2 in allEntities) {
+          var entity = allEntities[id2];
+          if (!entity) continue;
+          var name = utilDisplayName(entity) || "";
+          if (name.toLowerCase().indexOf(q2) < 0) continue;
+          var matched = _mainPresetIndex.match(entity, graph);
+          var type2 = matched && matched.name() || utilDisplayType(entity.id);
+          var extent = entity.extent(graph);
+          var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
+          localResults.push({
+            id: entity.id,
+            entity,
+            geometry: entity.geometry(graph),
+            type: type2,
+            name,
+            distance
+          });
+          if (localResults.length > 100) break;
+        }
+        localResults = localResults.sort(function byDistance(a2, b2) {
+          return a2.distance - b2.distance;
+        });
+        result = result.concat(localResults);
+        (_geocodeResults || []).forEach(function(d2) {
+          if (d2.osm_type && d2.osm_id) {
+            var id3 = osmEntity.id.fromOSM(d2.osm_type, d2.osm_id);
+            var tags = {};
+            tags[d2.class] = d2.type;
+            var attrs = { id: id3, type: d2.osm_type, tags };
+            if (d2.osm_type === "way") {
+              attrs.nodes = ["a", "a"];
             }
-            surface.selectAll(utilEntitySelector(ids)).classed("related", true).classed("allow", klass === "allow").classed("restrict", klass === "restrict").classed("only", klass === "only");
+            var tempEntity = osmEntity(attrs);
+            var tempGraph = coreGraph([tempEntity]);
+            var matched2 = _mainPresetIndex.match(tempEntity, tempGraph);
+            var type3 = matched2 && matched2.name() || utilDisplayType(id3);
+            result.push({
+              id: tempEntity.id,
+              geometry: tempEntity.geometry(tempGraph),
+              type: type3,
+              name: d2.display_name,
+              extent: new geoExtent(
+                [Number(d2.boundingbox[3]), Number(d2.boundingbox[0])],
+                [Number(d2.boundingbox[2]), Number(d2.boundingbox[1])]
+              )
+            });
           }
-        }
-      }
-      function updateHints(datum2) {
-        var help = _container.selectAll(".restriction-help").html("");
-        var placeholders = {};
-        ["from", "via", "to"].forEach(function(k2) {
-          placeholders[k2] = { html: '<span class="qualifier">' + _t("restriction.help." + k2) + "</span>" };
         });
-        var entity = datum2 && datum2.properties && datum2.properties.entity;
-        if (entity) {
-          datum2 = entity;
+        if (q2.match(/^[0-9]+$/)) {
+          result.push({
+            id: "n" + q2,
+            geometry: "point",
+            type: _t("inspector.node"),
+            name: q2
+          });
+          result.push({
+            id: "w" + q2,
+            geometry: "line",
+            type: _t("inspector.way"),
+            name: q2
+          });
+          result.push({
+            id: "r" + q2,
+            geometry: "relation",
+            type: _t("inspector.relation"),
+            name: q2
+          });
+          result.push({
+            id: "note" + q2,
+            geometry: "note",
+            type: _t("note.note"),
+            name: q2
+          });
         }
-        if (_fromWayID) {
-          way = vgraph.entity(_fromWayID);
-          surface.selectAll("." + _fromWayID).classed("selected", true).classed("related", true);
+        return result;
+      }
+      function drawList() {
+        var value = search.property("value");
+        var results = features();
+        list2.classed("filtered", value.length);
+        var resultsIndicator = list2.selectAll(".no-results-item").data([0]).enter().append("button").property("disabled", true).attr("class", "no-results-item").call(svgIcon("#iD-icon-alert", "pre-text"));
+        resultsIndicator.append("span").attr("class", "entity-name");
+        list2.selectAll(".no-results-item .entity-name").html("").call(_t.append("geocoder.no_results_worldwide"));
+        if (services.geocoder) {
+          list2.selectAll(".geocode-item").data([0]).enter().append("button").attr("class", "geocode-item secondary-action").on("click", geocoderSearch).append("div").attr("class", "label").append("span").attr("class", "entity-name").call(_t.append("geocoder.search"));
         }
-        if (datum2 instanceof osmWay && datum2.__from) {
-          way = datum2;
-          highlightPathsFrom(_fromWayID ? null : way.id);
-          surface.selectAll("." + way.id).classed("related", true);
-          var clickSelect = !_fromWayID || _fromWayID !== way.id;
-          help.append("div").html(_t.html("restriction.help." + (clickSelect ? "select_from_name" : "from_name"), {
-            from: placeholders.from,
-            fromName: displayName(way.id, vgraph)
-          }));
-        } else if (datum2 instanceof osmTurn) {
-          var restrictionType = osmInferRestriction(vgraph, datum2, projection2);
-          var turnType = restrictionType.replace(/^(only|no)\_/, "");
-          var indirect = datum2.direct === false ? _t.html("restriction.help.indirect") : "";
-          var klass, turnText, nextText;
-          if (datum2.no) {
-            klass = "restrict";
-            turnText = _t.html("restriction.help.turn.no_" + turnType, { indirect: { html: indirect } });
-            nextText = _t.html("restriction.help.turn.only_" + turnType, { indirect: "" });
-          } else if (datum2.only) {
-            klass = "only";
-            turnText = _t.html("restriction.help.turn.only_" + turnType, { indirect: { html: indirect } });
-            nextText = _t.html("restriction.help.turn.allowed_" + turnType, { indirect: "" });
-          } else {
-            klass = "allow";
-            turnText = _t.html("restriction.help.turn.allowed_" + turnType, { indirect: { html: indirect } });
-            nextText = _t.html("restriction.help.turn.no_" + turnType, { indirect: "" });
-          }
-          help.append("div").attr("class", "qualifier " + klass).html(turnText);
-          help.append("div").html(_t.html("restriction.help.from_name_to_name", {
-            from: placeholders.from,
-            fromName: displayName(datum2.from.way, vgraph),
-            to: placeholders.to,
-            toName: displayName(datum2.to.way, vgraph)
-          }));
-          if (datum2.via.ways && datum2.via.ways.length) {
-            var names = [];
-            for (var i4 = 0; i4 < datum2.via.ways.length; i4++) {
-              var prev = names[names.length - 1];
-              var curr = displayName(datum2.via.ways[i4], vgraph);
-              if (!prev || curr !== prev) {
-                names.push(curr);
-              }
-            }
-            help.append("div").html(_t.html("restriction.help.via_names", {
-              via: placeholders.via,
-              viaNames: names.join(", ")
-            }));
-          }
-          if (!indirect) {
-            help.append("div").html(_t.html("restriction.help.toggle", { turn: { html: nextText.trim() } }));
-          }
-          highlightPathsFrom(null);
-          var alongIDs = datum2.path.slice();
-          surface.selectAll(utilEntitySelector(alongIDs)).classed("related", true).classed("allow", klass === "allow").classed("restrict", klass === "restrict").classed("only", klass === "only");
+        list2.selectAll(".no-results-item").style("display", value.length && !results.length ? "block" : "none");
+        list2.selectAll(".geocode-item").style("display", value && _geocodeResults === void 0 ? "block" : "none");
+        list2.selectAll(".feature-list-item").data([-1]).remove();
+        var items = list2.selectAll(".feature-list-item").data(results, function(d2) {
+          return d2.id;
+        });
+        var enter = items.enter().insert("button", ".geocode-item").attr("class", "feature-list-item").on("mouseover", mouseover).on("mouseout", mouseout).on("click", click);
+        var label = enter.append("div").attr("class", "label");
+        label.each(function(d2) {
+          select_default2(this).call(svgIcon("#iD-icon-" + d2.geometry, "pre-text"));
+        });
+        label.append("span").attr("class", "entity-type").text(function(d2) {
+          return d2.type;
+        });
+        label.append("span").attr("class", "entity-name").classed("has-colour", (d2) => d2.entity && d2.entity.type === "relation" && d2.entity.tags.colour && isColourValid(d2.entity.tags.colour)).style("border-color", (d2) => d2.entity && d2.entity.type === "relation" && d2.entity.tags.colour).text(function(d2) {
+          return d2.name;
+        });
+        enter.style("opacity", 0).transition().style("opacity", 1);
+        items.order();
+        items.exit().remove();
+      }
+      function mouseover(d3_event, d2) {
+        if (d2.id === -1) return;
+        utilHighlightEntities([d2.id], true, context);
+      }
+      function mouseout(d3_event, d2) {
+        if (d2.id === -1) return;
+        utilHighlightEntities([d2.id], false, context);
+      }
+      function click(d3_event, d2) {
+        d3_event.preventDefault();
+        if (d2.location) {
+          context.map().centerZoomEase([d2.location[1], d2.location[0]], 19);
+        } else if (d2.entity) {
+          utilHighlightEntities([d2.id], false, context);
+          context.enter(modeSelect(context, [d2.entity.id]));
+          context.map().zoomToEase(d2.entity);
+        } else if (d2.geometry === "note") {
+          const noteId = d2.id.replace(/\D/g, "");
+          context.zoomToNote(noteId);
         } else {
-          highlightPathsFrom(null);
-          if (_fromWayID) {
-            help.append("div").html(_t.html("restriction.help.from_name", {
-              from: placeholders.from,
-              fromName: displayName(_fromWayID, vgraph)
-            }));
-          } else {
-            help.append("div").html(_t.html("restriction.help.select_from", {
-              from: placeholders.from
-            }));
-          }
+          context.zoomToEntity(d2.id);
         }
       }
+      function geocoderSearch() {
+        services.geocoder.search(search.property("value"), function(err, resp) {
+          _geocodeResults = resp || [];
+          drawList();
+        });
+      }
     }
-    function displayMaxDistance(maxDist) {
-      return (selection2) => {
-        var isImperial = !_mainLocalizer.usesMetric();
-        var opts;
-        if (isImperial) {
-          var distToFeet = {
-            // imprecise conversion for prettier display
-            20: 70,
-            25: 85,
-            30: 100,
-            35: 115,
-            40: 130,
-            45: 145,
-            50: 160
-          }[maxDist];
-          opts = { distance: _t("units.feet", { quantity: distToFeet }) };
-        } else {
-          opts = { distance: _t("units.meters", { quantity: maxDist }) };
-        }
-        return selection2.html("").call(_t.append("restriction.controls.distance_up_to", opts));
-      };
-    }
-    function displayMaxVia(maxVia) {
-      return (selection2) => {
-        selection2 = selection2.html("");
-        return maxVia === 0 ? selection2.call(_t.append("restriction.controls.via_node_only")) : maxVia === 1 ? selection2.call(_t.append("restriction.controls.via_up_to_one")) : selection2.call(_t.append("restriction.controls.via_up_to_two"));
-      };
-    }
-    function displayName(entityID, graph) {
-      var entity = graph.entity(entityID);
-      var name = utilDisplayName(entity) || "";
-      var matched = _mainPresetIndex.match(entity, graph);
-      var type2 = matched && matched.name() || utilDisplayType(entity.id);
-      return name || type2;
-    }
-    restrictions.entityIDs = function(val) {
-      _intersection = null;
-      _fromWayID = null;
-      _oldTurns = null;
-      _vertexID = val[0];
-    };
-    restrictions.tags = function() {
-    };
-    restrictions.focus = function() {
-    };
-    restrictions.off = function(selection2) {
-      if (!_initialized3)
-        return;
-      selection2.selectAll(".surface").call(breathe.off).on("click.restrictions", null).on("mouseover.restrictions", null);
-      select_default2(window).on("resize.restrictions", null);
-    };
-    return utilRebind(restrictions, dispatch14, "on");
+    return featureList;
   }
-  uiFieldRestrictions.supportsMultiselection = false;
 
-  // modules/ui/fields/textarea.js
-  function uiFieldTextarea(field, context) {
-    var dispatch14 = dispatch_default("change");
-    var input = select_default2(null);
-    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue()).silent(field.usage === "changeset" && field.key === "comment");
-    var _tags;
-    function textarea(selection2) {
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).style("position", "relative").merge(wrap2);
-      input = wrap2.selectAll("textarea").data([0]);
-      input = input.enter().append("textarea").attr("id", field.domId).call(utilNoAuto).on("input", change(true)).on("blur", change()).on("change", change()).merge(input);
-      wrap2.call(_lengthIndicator);
-      function change(onInput) {
-        return function() {
-          var val = utilGetSetValue(input);
-          if (!onInput)
-            val = context.cleanTagValue(val);
-          if (!val && Array.isArray(_tags[field.key]))
-            return;
-          var t2 = {};
-          t2[field.key] = val || void 0;
-          dispatch14.call("change", this, t2, onInput);
-        };
-      }
-    }
-    textarea.tags = function(tags) {
-      _tags = tags;
-      var isMixed = Array.isArray(tags[field.key]);
-      utilGetSetValue(input, !isMixed && tags[field.key] ? tags[field.key] : "").attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder() || _t("inspector.unknown")).classed("mixed", isMixed);
-      if (!isMixed) {
-        _lengthIndicator.update(tags[field.key]);
-      }
-    };
-    textarea.focus = function() {
-      input.node().focus();
-    };
-    return utilRebind(textarea, dispatch14, "on");
-  }
+  // modules/ui/entity_editor.js
+  var import_fast_deep_equal9 = __toESM(require_fast_deep_equal());
 
-  // modules/ui/fields/wikidata.js
-  function uiFieldWikidata(field, context) {
-    var wikidata = services.wikidata;
-    var dispatch14 = dispatch_default("change");
-    var _selection = select_default2(null);
-    var _searchInput = select_default2(null);
-    var _qid = null;
-    var _wikidataEntity = null;
-    var _wikiURL = "";
+  // modules/ui/sections/entity_issues.js
+  function uiSectionEntityIssues(context) {
+    var preference = corePreferences("entity-issues.reference.expanded");
+    var _expanded = preference === null ? true : preference === "true";
     var _entityIDs = [];
-    var _wikipediaKey = field.keys && field.keys.find(function(key) {
-      return key.includes("wikipedia");
+    var _issues = [];
+    var _activeIssueID;
+    var section = uiSection("entity-issues", context).shouldDisplay(function() {
+      return _issues.length > 0;
+    }).label(function() {
+      return _t.append("inspector.title_count", { title: _t("issues.list_title"), count: _issues.length });
+    }).disclosureContent(renderDisclosureContent);
+    context.validator().on("validated.entity_issues", function() {
+      reloadIssues();
+      section.reRender();
+    }).on("focusedIssue.entity_issues", function(issue) {
+      makeActiveIssue(issue.id);
     });
-    var _hintKey = field.key === "wikidata" ? "name" : field.key.split(":")[0];
-    var combobox = uiCombobox(context, "combo-" + field.safeid).caseSensitive(true).minItems(1);
-    function wiki(selection2) {
-      _selection = selection2;
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var list2 = wrap2.selectAll("ul").data([0]);
-      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
-      var searchRow = list2.selectAll("li.wikidata-search").data([0]);
-      var searchRowEnter = searchRow.enter().append("li").attr("class", "wikidata-search");
-      searchRowEnter.append("input").attr("type", "text").attr("id", field.domId).style("flex", "1").call(utilNoAuto).on("focus", function() {
-        var node = select_default2(this).node();
-        node.setSelectionRange(0, node.value.length);
-      }).on("blur", function() {
-        setLabelForEntity();
-      }).call(combobox.fetcher(fetchWikidataItems));
-      combobox.on("accept", function(d2) {
-        if (d2) {
-          _qid = d2.id;
-          change();
-        }
-      }).on("cancel", function() {
-        setLabelForEntity();
+    function reloadIssues() {
+      _issues = context.validator().getSharedEntityIssues(_entityIDs, { includeDisabledRules: true });
+    }
+    function makeActiveIssue(issueID) {
+      _activeIssueID = issueID;
+      section.selection().selectAll(".issue-container").classed("active", function(d2) {
+        return d2.id === _activeIssueID;
       });
-      searchRowEnter.append("button").attr("class", "form-field-button wiki-link").attr("title", _t("icons.view_on", { domain: "wikidata.org" })).call(svgIcon("#iD-icon-out-link")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        if (_wikiURL)
-          window.open(_wikiURL, "_blank");
+    }
+    function renderDisclosureContent(selection2) {
+      selection2.classed("grouped-items-area", true);
+      _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
+      var containers = selection2.selectAll(".issue-container").data(_issues, function(d2) {
+        return d2.key;
       });
-      searchRow = searchRow.merge(searchRowEnter);
-      _searchInput = searchRow.select("input");
-      var wikidataProperties = ["description", "identifier"];
-      var items = list2.selectAll("li.labeled-input").data(wikidataProperties);
-      var enter = items.enter().append("li").attr("class", function(d2) {
-        return "labeled-input preset-wikidata-" + d2;
+      containers.exit().remove();
+      var containersEnter = containers.enter().append("div").attr("class", "issue-container");
+      var itemsEnter = containersEnter.append("div").attr("class", function(d2) {
+        return "issue severity-" + d2.severity;
+      }).on("mouseover.highlight", function(d3_event, d2) {
+        var ids = d2.entityIds.filter(function(e3) {
+          return _entityIDs.indexOf(e3) === -1;
+        });
+        utilHighlightEntities(ids, true, context);
+      }).on("mouseout.highlight", function(d3_event, d2) {
+        var ids = d2.entityIds.filter(function(e3) {
+          return _entityIDs.indexOf(e3) === -1;
+        });
+        utilHighlightEntities(ids, false, context);
       });
-      enter.append("div").attr("class", "label").html(function(d2) {
-        return _t.html("wikidata." + d2);
+      var labelsEnter = itemsEnter.append("div").attr("class", "issue-label");
+      var textEnter = labelsEnter.append("button").attr("class", "issue-text").on("click", function(d3_event, d2) {
+        makeActiveIssue(d2.id);
+        var extent = d2.extent(context.graph());
+        if (extent) {
+          var setZoom = Math.max(context.map().zoom(), 19);
+          context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
+        }
       });
-      enter.append("input").attr("type", "text").call(utilNoAuto).classed("disabled", "true").attr("readonly", "true");
-      enter.append("button").attr("class", "form-field-button").attr("title", _t("icons.copy")).call(svgIcon("#iD-operation-copy")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        select_default2(this.parentNode).select("input").node().select();
-        document.execCommand("copy");
+      textEnter.each(function(d2) {
+        var iconName = "#iD-icon-" + (d2.severity === "warning" ? "alert" : "error");
+        select_default2(this).call(svgIcon(iconName, "issue-icon"));
       });
-    }
-    function fetchWikidataItems(q2, callback) {
-      if (!q2 && _hintKey) {
-        for (var i3 in _entityIDs) {
-          var entity = context.hasEntity(_entityIDs[i3]);
-          if (entity.tags[_hintKey]) {
-            q2 = entity.tags[_hintKey];
-            break;
-          }
+      textEnter.append("span").attr("class", "issue-message");
+      var infoButton = labelsEnter.append("button").attr("class", "issue-info-button").attr("title", _t("icons.information")).call(svgIcon("#iD-icon-inspect"));
+      infoButton.on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        this.blur();
+        var container = select_default2(this.parentNode.parentNode.parentNode);
+        var info = container.selectAll(".issue-info");
+        var isExpanded = info.classed("expanded");
+        _expanded = !isExpanded;
+        corePreferences("entity-issues.reference.expanded", _expanded);
+        if (isExpanded) {
+          info.transition().duration(200).style("max-height", "0px").style("opacity", "0").on("end", function() {
+            info.classed("expanded", false);
+          });
+        } else {
+          info.classed("expanded", true).transition().duration(200).style("max-height", "200px").style("opacity", "1").on("end", function() {
+            info.style("max-height", null);
+          });
         }
-      }
-      wikidata.itemsForSearchQuery(q2, function(err, data) {
-        if (err) {
-          if (err !== "No query")
-            console.error(err);
-          return;
+      });
+      itemsEnter.append("ul").attr("class", "issue-fix-list");
+      containersEnter.append("div").attr("class", "issue-info" + (_expanded ? " expanded" : "")).style("max-height", _expanded ? null : "0").style("opacity", _expanded ? "1" : "0").each(function(d2) {
+        if (typeof d2.reference === "function") {
+          select_default2(this).call(d2.reference);
+        } else {
+          select_default2(this).call(_t.append("inspector.no_documentation_key"));
         }
-        var result = data.map(function(item) {
-          return {
-            id: item.id,
-            value: item.display.label.value + " (" + item.id + ")",
-            display: (selection2) => selection2.append("span").attr("class", "localized-text").attr("lang", item.display.label.language).text(item.display.label.value),
-            title: item.display.description && item.display.description.value,
-            terms: item.aliases
-          };
-        });
-        if (callback)
-          callback(result);
       });
-    }
-    function change() {
-      var syncTags = {};
-      syncTags[field.key] = _qid;
-      dispatch14.call("change", this, syncTags);
-      var initGraph = context.graph();
-      var initEntityIDs = _entityIDs;
-      wikidata.entityByQID(_qid, function(err, entity) {
-        if (err)
-          return;
-        if (context.graph() !== initGraph)
-          return;
-        if (!entity.sitelinks)
-          return;
-        var langs = wikidata.languagesToQuery();
-        ["labels", "descriptions"].forEach(function(key) {
-          if (!entity[key])
-            return;
-          var valueLangs = Object.keys(entity[key]);
-          if (valueLangs.length === 0)
-            return;
-          var valueLang = valueLangs[0];
-          if (langs.indexOf(valueLang) === -1) {
-            langs.push(valueLang);
+      containers = containers.merge(containersEnter).classed("active", function(d2) {
+        return d2.id === _activeIssueID;
+      });
+      containers.selectAll(".issue-message").text("").each(function(d2) {
+        return d2.message(context)(select_default2(this));
+      });
+      var fixLists = containers.selectAll(".issue-fix-list");
+      var fixes = fixLists.selectAll(".issue-fix-item").data(function(d2) {
+        return d2.fixes ? d2.fixes(context) : [];
+      }, function(fix) {
+        return fix.id;
+      });
+      fixes.exit().remove();
+      var fixesEnter = fixes.enter().append("li").attr("class", "issue-fix-item");
+      var buttons = fixesEnter.append("button").on("click", function(d3_event, d2) {
+        if (select_default2(this).attr("disabled") || !d2.onClick) return;
+        if (d2.issue.dateLastRanFix && /* @__PURE__ */ new Date() - d2.issue.dateLastRanFix < 1e3) return;
+        d2.issue.dateLastRanFix = /* @__PURE__ */ new Date();
+        utilHighlightEntities(d2.issue.entityIds.concat(d2.entityIds), false, context);
+        new Promise(function(resolve, reject) {
+          d2.onClick(context, resolve, reject);
+          if (d2.onClick.length <= 1) {
+            resolve();
           }
+        }).then(function() {
+          context.validator().validate();
         });
-        var newWikipediaValue;
-        if (_wikipediaKey) {
-          var foundPreferred;
-          for (var i3 in langs) {
-            var lang = langs[i3];
-            var siteID = lang.replace("-", "_") + "wiki";
-            if (entity.sitelinks[siteID]) {
-              foundPreferred = true;
-              newWikipediaValue = lang + ":" + entity.sitelinks[siteID].title;
-              break;
-            }
-          }
-          if (!foundPreferred) {
-            var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function(site) {
-              return site.endsWith("wiki");
-            });
-            if (wikiSiteKeys.length === 0) {
-              newWikipediaValue = null;
-            } else {
-              var wikiLang = wikiSiteKeys[0].slice(0, -4).replace("_", "-");
-              var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
-              newWikipediaValue = wikiLang + ":" + wikiTitle;
-            }
-          }
-        }
-        if (newWikipediaValue) {
-          newWikipediaValue = context.cleanTagValue(newWikipediaValue);
-        }
-        if (typeof newWikipediaValue === "undefined")
-          return;
-        var actions = initEntityIDs.map(function(entityID) {
-          var entity2 = context.hasEntity(entityID);
-          if (!entity2)
-            return null;
-          var currTags = Object.assign({}, entity2.tags);
-          if (newWikipediaValue === null) {
-            if (!currTags[_wikipediaKey])
-              return null;
-            delete currTags[_wikipediaKey];
-          } else {
-            currTags[_wikipediaKey] = newWikipediaValue;
-          }
-          return actionChangeTags(entityID, currTags);
-        }).filter(Boolean);
-        if (!actions.length)
-          return;
-        context.overwrite(
-          function actionUpdateWikipediaTags(graph) {
-            actions.forEach(function(action) {
-              graph = action(graph);
-            });
-            return graph;
-          },
-          context.history().undoAnnotation()
-        );
+      }).on("mouseover.highlight", function(d3_event, d2) {
+        utilHighlightEntities(d2.entityIds, true, context);
+      }).on("mouseout.highlight", function(d3_event, d2) {
+        utilHighlightEntities(d2.entityIds, false, context);
       });
-    }
-    function setLabelForEntity() {
-      var label = "";
-      if (_wikidataEntity) {
-        label = entityPropertyForDisplay(_wikidataEntity, "labels");
-        if (label.length === 0) {
-          label = _wikidataEntity.id.toString();
-        }
-      }
-      utilGetSetValue(_searchInput, label);
-    }
-    wiki.tags = function(tags) {
-      var isMixed = Array.isArray(tags[field.key]);
-      _searchInput.attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : "").classed("mixed", isMixed);
-      _qid = typeof tags[field.key] === "string" && tags[field.key] || "";
-      if (!/^Q[0-9]*$/.test(_qid)) {
-        unrecognized();
-        return;
-      }
-      _wikiURL = "https://wikidata.org/wiki/" + _qid;
-      wikidata.entityByQID(_qid, function(err, entity) {
-        if (err) {
-          unrecognized();
-          return;
+      buttons.each(function(d2) {
+        var iconName = d2.icon || "iD-icon-wrench";
+        if (iconName.startsWith("maki")) {
+          iconName += "-15";
         }
-        _wikidataEntity = entity;
-        setLabelForEntity();
-        var description = entityPropertyForDisplay(entity, "descriptions");
-        _selection.select("button.wiki-link").classed("disabled", false);
-        _selection.select(".preset-wikidata-description").style("display", function() {
-          return description.length > 0 ? "flex" : "none";
-        }).select("input").attr("value", description);
-        _selection.select(".preset-wikidata-identifier").style("display", function() {
-          return entity.id ? "flex" : "none";
-        }).select("input").attr("value", entity.id);
+        select_default2(this).call(svgIcon("#" + iconName, "fix-icon"));
       });
-      function unrecognized() {
-        _wikidataEntity = null;
-        setLabelForEntity();
-        _selection.select(".preset-wikidata-description").style("display", "none");
-        _selection.select(".preset-wikidata-identifier").style("display", "none");
-        _selection.select("button.wiki-link").classed("disabled", true);
-        if (_qid && _qid !== "") {
-          _wikiURL = "https://wikidata.org/wiki/Special:Search?search=" + _qid;
-        } else {
-          _wikiURL = "";
+      buttons.append("span").attr("class", "fix-message").each(function(d2) {
+        return d2.title(select_default2(this));
+      });
+      fixesEnter.merge(fixes).selectAll("button").classed("actionable", function(d2) {
+        return d2.onClick;
+      }).attr("disabled", function(d2) {
+        return d2.onClick ? null : "true";
+      }).attr("title", function(d2) {
+        if (d2.disabledReason) {
+          return d2.disabledReason;
         }
-      }
-    };
-    function entityPropertyForDisplay(wikidataEntity, propKey) {
-      if (!wikidataEntity[propKey])
-        return "";
-      var propObj = wikidataEntity[propKey];
-      var langKeys = Object.keys(propObj);
-      if (langKeys.length === 0)
-        return "";
-      var langs = wikidata.languagesToQuery();
-      for (var i3 in langs) {
-        var lang = langs[i3];
-        var valueObj = propObj[lang];
-        if (valueObj && valueObj.value && valueObj.value.length > 0)
-          return valueObj.value;
-      }
-      return propObj[langKeys[0]].value;
+        return null;
+      });
     }
-    wiki.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return wiki;
-    };
-    wiki.focus = function() {
-      _searchInput.node().focus();
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
+        _entityIDs = val;
+        _activeIssueID = null;
+        reloadIssues();
+      }
+      return section;
     };
-    return utilRebind(wiki, dispatch14, "on");
+    return section;
   }
 
-  // modules/ui/fields/wikipedia.js
-  function uiFieldWikipedia(field, context) {
-    const scheme = "https://";
-    const domain = "wikipedia.org";
-    const dispatch14 = dispatch_default("change");
-    const wikipedia = services.wikipedia;
-    const wikidata = services.wikidata;
-    let _langInput = select_default2(null);
-    let _titleInput = select_default2(null);
-    let _wikiURL = "";
-    let _entityIDs;
-    let _tags;
-    let _dataWikipedia = [];
-    _mainFileFetcher.get("wmf_sitematrix").then((d2) => {
-      _dataWikipedia = d2;
-      if (_tags)
-        updateForTags(_tags);
-    }).catch(() => {
-    });
-    const langCombo = uiCombobox(context, "wikipedia-lang").fetcher((value, callback) => {
-      const v2 = value.toLowerCase();
-      callback(
-        _dataWikipedia.filter((d2) => {
-          return d2[0].toLowerCase().indexOf(v2) >= 0 || d2[1].toLowerCase().indexOf(v2) >= 0 || d2[2].toLowerCase().indexOf(v2) >= 0;
-        }).map((d2) => ({ value: d2[1] }))
-      );
-    });
-    const titleCombo = uiCombobox(context, "wikipedia-title").fetcher((value, callback) => {
-      if (!value) {
-        value = "";
-        for (let i3 in _entityIDs) {
-          let entity = context.hasEntity(_entityIDs[i3]);
-          if (entity.tags.name) {
-            value = entity.tags.name;
-            break;
-          }
-        }
-      }
-      const searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
-      searchfn(language()[2], value, (query, data) => {
-        callback(data.map((d2) => ({ value: d2 })));
-      });
-    });
-    function wiki(selection2) {
-      let wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap2);
-      let langContainer = wrap2.selectAll(".wiki-lang-container").data([0]);
-      langContainer = langContainer.enter().append("div").attr("class", "wiki-lang-container").merge(langContainer);
-      _langInput = langContainer.selectAll("input.wiki-lang").data([0]);
-      _langInput = _langInput.enter().append("input").attr("type", "text").attr("class", "wiki-lang").attr("placeholder", _t("translate.localized_translation_language")).call(utilNoAuto).call(langCombo).merge(_langInput);
-      _langInput.on("blur", changeLang).on("change", changeLang);
-      let titleContainer = wrap2.selectAll(".wiki-title-container").data([0]);
-      titleContainer = titleContainer.enter().append("div").attr("class", "wiki-title-container").merge(titleContainer);
-      _titleInput = titleContainer.selectAll("input.wiki-title").data([0]);
-      _titleInput = _titleInput.enter().append("input").attr("type", "text").attr("class", "wiki-title").attr("id", field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
-      _titleInput.on("blur", function() {
-        change(true);
-      }).on("change", function() {
-        change(false);
-      });
-      let link3 = titleContainer.selectAll(".wiki-link").data([0]);
-      link3 = link3.enter().append("button").attr("class", "form-field-button wiki-link").attr("title", _t("icons.view_on", { domain })).call(svgIcon("#iD-icon-out-link")).merge(link3);
-      link3.on("click", (d3_event) => {
-        d3_event.preventDefault();
-        if (_wikiURL)
-          window.open(_wikiURL, "_blank");
-      });
+  // modules/ui/preset_icon.js
+  function uiPresetIcon() {
+    let _preset;
+    let _geometry;
+    function presetIcon(selection2) {
+      selection2.each(render);
     }
-    function defaultLanguageInfo(skipEnglishFallback) {
-      const langCode = _mainLocalizer.languageCode().toLowerCase();
-      for (let i3 in _dataWikipedia) {
-        let d2 = _dataWikipedia[i3];
-        if (d2[2] === langCode)
-          return d2;
-      }
-      return skipEnglishFallback ? ["", "", ""] : ["English", "English", "en"];
+    function getIcon(p2, geom) {
+      if (p2.isFallback && p2.isFallback()) return geom === "vertex" ? "" : "iD-icon-" + p2.id;
+      if (p2.icon) return p2.icon;
+      if (geom === "line") return "iD-other-line";
+      if (geom === "vertex") return "temaki-vertex";
+      return "maki-marker-stroked";
     }
-    function language(skipEnglishFallback) {
-      const value = utilGetSetValue(_langInput).toLowerCase();
-      for (let i3 in _dataWikipedia) {
-        let d2 = _dataWikipedia[i3];
-        if (d2[0].toLowerCase() === value || d2[1].toLowerCase() === value || d2[2] === value)
-          return d2;
+    function renderPointBorder(container, drawPoint) {
+      let pointBorder = container.selectAll(".preset-icon-point-border").data(drawPoint ? [0] : []);
+      pointBorder.exit().remove();
+      let pointBorderEnter = pointBorder.enter();
+      const w2 = 40;
+      const h2 = 40;
+      pointBorderEnter.append("svg").attr("class", "preset-icon-fill preset-icon-point-border").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2)).append("path").attr("transform", "translate(11.5, 8)").attr("d", "M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z");
+      pointBorder = pointBorderEnter.merge(pointBorder);
+    }
+    function renderCategoryBorder(container, category) {
+      let categoryBorder = container.selectAll(".preset-icon-category-border").data(category ? [0] : []);
+      categoryBorder.exit().remove();
+      let categoryBorderEnter = categoryBorder.enter();
+      const d2 = 60;
+      let svgEnter = categoryBorderEnter.append("svg").attr("class", "preset-icon-fill preset-icon-category-border").attr("width", d2).attr("height", d2).attr("viewBox", "0 0 ".concat(d2, " ").concat(d2));
+      svgEnter.append("path").attr("class", "area").attr("d", "M9.5,7.5 L25.5,7.5 L28.5,12.5 L49.5,12.5 C51.709139,12.5 53.5,14.290861 53.5,16.5 L53.5,43.5 C53.5,45.709139 51.709139,47.5 49.5,47.5 L10.5,47.5 C8.290861,47.5 6.5,45.709139 6.5,43.5 L6.5,12.5 L9.5,7.5 Z");
+      categoryBorder = categoryBorderEnter.merge(categoryBorder);
+      if (category) {
+        categoryBorder.selectAll("path").attr("class", "area ".concat(category.id));
       }
-      return defaultLanguageInfo(skipEnglishFallback);
     }
-    function changeLang() {
-      utilGetSetValue(_langInput, language()[1]);
-      change(true);
+    function renderCircleFill(container, drawVertex) {
+      let vertexFill = container.selectAll(".preset-icon-fill-vertex").data(drawVertex ? [0] : []);
+      vertexFill.exit().remove();
+      let vertexFillEnter = vertexFill.enter();
+      const w2 = 60;
+      const h2 = 60;
+      const d2 = 40;
+      vertexFillEnter.append("svg").attr("class", "preset-icon-fill preset-icon-fill-vertex").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2)).append("circle").attr("cx", w2 / 2).attr("cy", h2 / 2).attr("r", d2 / 2);
+      vertexFill = vertexFillEnter.merge(vertexFill);
     }
-    function change(skipWikidata) {
-      let value = utilGetSetValue(_titleInput);
-      const m2 = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
-      const langInfo = m2 && _dataWikipedia.find((d2) => m2[1] === d2[2]);
-      let syncTags = {};
-      if (langInfo) {
-        const nativeLangName = langInfo[1];
-        value = decodeURIComponent(m2[2]).replace(/_/g, " ");
-        if (m2[3]) {
-          let anchor;
-          anchor = decodeURIComponent(m2[3]);
-          value += "#" + anchor.replace(/_/g, " ");
+    function renderSquareFill(container, drawArea, tagClasses) {
+      let fill = container.selectAll(".preset-icon-fill-area").data(drawArea ? [0] : []);
+      fill.exit().remove();
+      let fillEnter = fill.enter();
+      const d2 = 60;
+      const w2 = d2;
+      const h2 = d2;
+      const l2 = d2 * 2 / 3;
+      const c1 = (w2 - l2) / 2;
+      const c2 = c1 + l2;
+      fillEnter = fillEnter.append("svg").attr("class", "preset-icon-fill preset-icon-fill-area").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
+      ["fill", "stroke"].forEach((klass) => {
+        fillEnter.append("path").attr("d", "M".concat(c1, " ").concat(c1, " L").concat(c1, " ").concat(c2, " L").concat(c2, " ").concat(c2, " L").concat(c2, " ").concat(c1, " Z")).attr("class", "area ".concat(klass));
+      });
+      const rVertex = 2.5;
+      [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach((point) => {
+        fillEnter.append("circle").attr("class", "vertex").attr("cx", point[0]).attr("cy", point[1]).attr("r", rVertex);
+      });
+      const rMidpoint = 1.25;
+      [[c1, w2 / 2], [c2, w2 / 2], [h2 / 2, c1], [h2 / 2, c2]].forEach((point) => {
+        fillEnter.append("circle").attr("class", "midpoint").attr("cx", point[0]).attr("cy", point[1]).attr("r", rMidpoint);
+      });
+      fill = fillEnter.merge(fill);
+      fill.selectAll("path.stroke").attr("class", "area stroke ".concat(tagClasses));
+      fill.selectAll("path.fill").attr("class", "area fill ".concat(tagClasses));
+    }
+    function renderLine(container, drawLine, tagClasses) {
+      let line = container.selectAll(".preset-icon-line").data(drawLine ? [0] : []);
+      line.exit().remove();
+      let lineEnter = line.enter();
+      const d2 = 60;
+      const w2 = d2;
+      const h2 = d2;
+      const y2 = Math.round(d2 * 0.72);
+      const l2 = Math.round(d2 * 0.6);
+      const r2 = 2.5;
+      const x12 = (w2 - l2) / 2;
+      const x2 = x12 + l2;
+      lineEnter = lineEnter.append("svg").attr("class", "preset-icon-line").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
+      ["casing", "stroke"].forEach((klass) => {
+        lineEnter.append("path").attr("d", "M".concat(x12, " ").concat(y2, " L").concat(x2, " ").concat(y2)).attr("class", "line ".concat(klass));
+      });
+      [[x12 - 1, y2], [x2 + 1, y2]].forEach((point) => {
+        lineEnter.append("circle").attr("class", "vertex").attr("cx", point[0]).attr("cy", point[1]).attr("r", r2);
+      });
+      line = lineEnter.merge(line);
+      line.selectAll("path.stroke").attr("class", "line stroke ".concat(tagClasses));
+      line.selectAll("path.casing").attr("class", "line casing ".concat(tagClasses));
+    }
+    function renderRoute(container, drawRoute, p2) {
+      let route = container.selectAll(".preset-icon-route").data(drawRoute ? [0] : []);
+      route.exit().remove();
+      let routeEnter = route.enter();
+      const d2 = 60;
+      const w2 = d2;
+      const h2 = d2;
+      const y12 = Math.round(d2 * 0.8);
+      const y2 = Math.round(d2 * 0.68);
+      const l2 = Math.round(d2 * 0.6);
+      const r2 = 2;
+      const x12 = (w2 - l2) / 2;
+      const x2 = x12 + l2 / 3;
+      const x3 = x2 + l2 / 3;
+      const x4 = x3 + l2 / 3;
+      routeEnter = routeEnter.append("svg").attr("class", "preset-icon-route").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
+      ["casing", "stroke"].forEach((klass) => {
+        routeEnter.append("path").attr("d", "M".concat(x12, " ").concat(y12, " L").concat(x2, " ").concat(y2)).attr("class", "segment0 line ".concat(klass));
+        routeEnter.append("path").attr("d", "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y12)).attr("class", "segment1 line ".concat(klass));
+        routeEnter.append("path").attr("d", "M".concat(x3, " ").concat(y12, " L").concat(x4, " ").concat(y2)).attr("class", "segment2 line ".concat(klass));
+      });
+      [[x12, y12], [x2, y2], [x3, y12], [x4, y2]].forEach((point) => {
+        routeEnter.append("circle").attr("class", "vertex").attr("cx", point[0]).attr("cy", point[1]).attr("r", r2);
+      });
+      route = routeEnter.merge(route);
+      if (drawRoute) {
+        let routeType = p2.tags.type === "waterway" ? "waterway" : p2.tags.route;
+        const segmentPresetIDs = routeSegments[routeType];
+        for (let i3 in segmentPresetIDs) {
+          const segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i3]);
+          const segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, "");
+          route.selectAll("path.stroke.segment".concat(i3)).attr("class", "segment".concat(i3, " line stroke ").concat(segmentTagClasses));
+          route.selectAll("path.casing.segment".concat(i3)).attr("class", "segment".concat(i3, " line casing ").concat(segmentTagClasses));
         }
-        value = value.slice(0, 1).toUpperCase() + value.slice(1);
-        utilGetSetValue(_langInput, nativeLangName);
-        utilGetSetValue(_titleInput, value);
-      }
-      if (value) {
-        syncTags.wikipedia = context.cleanTagValue(language()[2] + ":" + value);
-      } else {
-        syncTags.wikipedia = void 0;
       }
-      dispatch14.call("change", this, syncTags);
-      if (skipWikidata || !value || !language()[2])
-        return;
-      const initGraph = context.graph();
-      const initEntityIDs = _entityIDs;
-      wikidata.itemsByTitle(language()[2], value, (err, data) => {
-        if (err || !data || !Object.keys(data).length)
-          return;
-        if (context.graph() !== initGraph)
-          return;
-        const qids = Object.keys(data);
-        const value2 = qids && qids.find((id2) => id2.match(/^Q\d+$/));
-        let actions = initEntityIDs.map((entityID) => {
-          let entity = context.entity(entityID).tags;
-          let currTags = Object.assign({}, entity);
-          if (currTags.wikidata !== value2) {
-            currTags.wikidata = value2;
-            return actionChangeTags(entityID, currTags);
-          }
-          return null;
-        }).filter(Boolean);
-        if (!actions.length)
-          return;
-        context.overwrite(
-          function actionUpdateWikidataTags(graph) {
-            actions.forEach(function(action) {
-              graph = action(graph);
-            });
-            return graph;
-          },
-          context.history().undoAnnotation()
-        );
-      });
     }
-    wiki.tags = (tags) => {
-      _tags = tags;
-      updateForTags(tags);
+    function renderSvgIcon(container, picon, geom, isFramed, category, tagClasses) {
+      const isMaki = picon && /^maki-/.test(picon);
+      const isTemaki = picon && /^temaki-/.test(picon);
+      const isFa = picon && /^fa[srb]-/.test(picon);
+      const isR\u00F6ntgen = picon && /^roentgen-/.test(picon);
+      const isiDIcon = picon && !(isMaki || isTemaki || isFa || isR\u00F6ntgen);
+      let icon2 = container.selectAll(".preset-icon").data(picon ? [0] : []);
+      icon2.exit().remove();
+      icon2 = icon2.enter().append("div").attr("class", "preset-icon").call(svgIcon("")).merge(icon2);
+      icon2.attr("class", "preset-icon " + (geom ? geom + "-geom" : "")).classed("category", category).classed("framed", isFramed).classed("preset-icon-iD", isiDIcon);
+      icon2.selectAll("svg").attr("class", "icon " + picon + " " + (!isiDIcon && geom !== "line" ? "" : tagClasses));
+      icon2.selectAll("use").attr("href", "#" + picon);
+    }
+    function renderImageIcon(container, imageURL) {
+      let imageIcon = container.selectAll("img.image-icon").data(imageURL ? [0] : []);
+      imageIcon.exit().remove();
+      imageIcon = imageIcon.enter().append("img").attr("class", "image-icon").on("load", () => container.classed("showing-img", true)).on("error", () => container.classed("showing-img", false)).merge(imageIcon);
+      imageIcon.attr("src", imageURL);
+    }
+    const routeSegments = {
+      bicycle: ["highway/cycleway", "highway/cycleway", "highway/cycleway"],
+      bus: ["highway/unclassified", "highway/secondary", "highway/primary"],
+      trolleybus: ["highway/unclassified", "highway/secondary", "highway/primary"],
+      detour: ["highway/tertiary", "highway/residential", "highway/unclassified"],
+      ferry: ["route/ferry", "route/ferry", "route/ferry"],
+      foot: ["highway/footway", "highway/footway", "highway/footway"],
+      hiking: ["highway/path", "highway/path", "highway/path"],
+      horse: ["highway/bridleway", "highway/bridleway", "highway/bridleway"],
+      light_rail: ["railway/light_rail", "railway/light_rail", "railway/light_rail"],
+      monorail: ["railway/monorail", "railway/monorail", "railway/monorail"],
+      mtb: ["highway/path", "highway/track", "highway/bridleway"],
+      pipeline: ["man_made/pipeline", "man_made/pipeline", "man_made/pipeline"],
+      piste: ["piste/downhill", "piste/hike", "piste/nordic"],
+      power: ["power/line", "power/line", "power/line"],
+      road: ["highway/secondary", "highway/primary", "highway/trunk"],
+      subway: ["railway/subway", "railway/subway", "railway/subway"],
+      train: ["railway/rail", "railway/rail", "railway/rail"],
+      tram: ["railway/tram", "railway/tram", "railway/tram"],
+      railway: ["railway/rail", "railway/rail", "railway/rail"],
+      waterway: ["waterway/stream", "waterway/stream", "waterway/stream"]
     };
-    function updateForTags(tags) {
-      const value = typeof tags[field.key] === "string" ? tags[field.key] : "";
-      const m2 = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
-      const tagLang = m2 && m2[1];
-      const tagArticleTitle = m2 && m2[2];
-      let anchor = m2 && m2[3];
-      const tagLangInfo = tagLang && _dataWikipedia.find((d2) => tagLang === d2[2]);
-      if (tagLangInfo) {
-        const nativeLangName = tagLangInfo[1];
-        utilGetSetValue(_langInput, nativeLangName);
-        utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? "#" + anchor : ""));
-        _wikiURL = "".concat(scheme).concat(tagLang, ".").concat(domain, "/wiki/").concat(wiki.encodePath(tagArticleTitle, anchor));
-      } else {
-        utilGetSetValue(_titleInput, value);
-        if (value && value !== "") {
-          utilGetSetValue(_langInput, "");
-          const defaultLangInfo = defaultLanguageInfo();
-          _wikiURL = "".concat(scheme).concat(defaultLangInfo[2], ".").concat(domain, "/w/index.php?fulltext=1&search=").concat(value);
-        } else {
-          const shownOrDefaultLangInfo = language(
-            true
-            /* skipEnglishFallback */
-          );
-          utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
-          _wikiURL = "";
+    function render() {
+      let p2 = _preset.apply(this, arguments);
+      let geom = _geometry ? _geometry.apply(this, arguments) : null;
+      if (geom === "relation" && p2.tags && (p2.tags.type === "route" && p2.tags.route && routeSegments[p2.tags.route] || p2.tags.type === "waterway")) {
+        geom = "route";
+      }
+      const showThirdPartyIcons = corePreferences("preferences.privacy.thirdpartyicons") || "true";
+      const isFallback = p2.isFallback && p2.isFallback();
+      const imageURL = showThirdPartyIcons === "true" && p2.imageURL;
+      const picon = getIcon(p2, geom);
+      const isCategory = !p2.setTags;
+      const drawPoint = false;
+      const drawVertex = picon !== null && geom === "vertex";
+      const drawLine = picon && geom === "line" && !isFallback && !isCategory;
+      const drawArea = picon && geom === "area" && !isFallback && !isCategory;
+      const drawRoute = picon && geom === "route";
+      const isFramed = drawVertex || drawArea || drawLine || drawRoute || isCategory;
+      let tags = !isCategory ? p2.setTags({}, geom) : {};
+      for (let k2 in tags) {
+        if (tags[k2] === "*") {
+          tags[k2] = "yes";
         }
       }
+      let tagClasses = svgTagClasses().getClassesString(tags, "");
+      let selection2 = select_default2(this);
+      let container = selection2.selectAll(".preset-icon-container").data([0]);
+      container = container.enter().append("div").attr("class", "preset-icon-container").merge(container);
+      container.classed("showing-img", !!imageURL).classed("fallback", isFallback);
+      renderCategoryBorder(container, isCategory && p2);
+      renderPointBorder(container, drawPoint);
+      renderCircleFill(container, drawVertex);
+      renderSquareFill(container, drawArea, tagClasses);
+      renderLine(container, drawLine, tagClasses);
+      renderRoute(container, drawRoute, p2);
+      renderSvgIcon(container, picon, geom, isFramed, isCategory, tagClasses);
+      renderImageIcon(container, imageURL);
     }
-    wiki.encodePath = (tagArticleTitle, anchor) => {
-      const underscoredTitle = tagArticleTitle.replace(/ /g, "_");
-      const uriEncodedUnderscoredTitle = encodeURIComponent(underscoredTitle);
-      const uriEncodedAnchorFragment = wiki.encodeURIAnchorFragment(anchor);
-      return "".concat(uriEncodedUnderscoredTitle).concat(uriEncodedAnchorFragment);
-    };
-    wiki.encodeURIAnchorFragment = (anchor) => {
-      if (!anchor)
-        return "";
-      const underscoredAnchor = anchor.replace(/ /g, "_");
-      return "#" + encodeURIComponent(underscoredAnchor);
-    };
-    wiki.entityIDs = (val) => {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return wiki;
+    presetIcon.preset = function(val) {
+      if (!arguments.length) return _preset;
+      _preset = utilFunctor(val);
+      return presetIcon;
     };
-    wiki.focus = () => {
-      _titleInput.node().focus();
+    presetIcon.geometry = function(val) {
+      if (!arguments.length) return _geometry;
+      _geometry = utilFunctor(val);
+      return presetIcon;
     };
-    return utilRebind(wiki, dispatch14, "on");
+    return presetIcon;
   }
-  uiFieldWikipedia.supportsMultiselection = false;
-
-  // modules/ui/fields/index.js
-  var uiFields = {
-    access: uiFieldAccess,
-    address: uiFieldAddress,
-    check: uiFieldCheck,
-    colour: uiFieldText,
-    combo: uiFieldCombo,
-    cycleway: uiFieldDirectionalCombo,
-    date: uiFieldText,
-    defaultCheck: uiFieldCheck,
-    directionalCombo: uiFieldDirectionalCombo,
-    email: uiFieldText,
-    identifier: uiFieldText,
-    lanes: uiFieldLanes,
-    localized: uiFieldLocalized,
-    roadheight: uiFieldRoadheight,
-    roadspeed: uiFieldRoadspeed,
-    manyCombo: uiFieldCombo,
-    multiCombo: uiFieldCombo,
-    networkCombo: uiFieldCombo,
-    number: uiFieldText,
-    onewayCheck: uiFieldCheck,
-    radio: uiFieldRadio,
-    restrictions: uiFieldRestrictions,
-    semiCombo: uiFieldCombo,
-    structureRadio: uiFieldRadio,
-    tel: uiFieldText,
-    text: uiFieldText,
-    textarea: uiFieldTextarea,
-    typeCombo: uiFieldCombo,
-    url: uiFieldText,
-    wikidata: uiFieldWikidata,
-    wikipedia: uiFieldWikipedia
-  };
 
-  // modules/ui/field.js
-  function uiField(context, presetField2, entityIDs, options2) {
-    options2 = Object.assign({
-      show: true,
-      wrap: true,
-      remove: true,
-      revert: true,
-      info: true
-    }, options2);
-    var dispatch14 = dispatch_default("change", "revert");
-    var field = Object.assign({}, presetField2);
-    field.domId = utilUniqueDomId("form-field-" + field.safeid);
-    var _show = options2.show;
-    var _state = "";
-    var _tags = {};
-    var _entityExtent;
-    if (entityIDs && entityIDs.length) {
-      _entityExtent = entityIDs.reduce(function(extent, entityID) {
-        var entity = context.graph().entity(entityID);
-        return extent.extend(entity.extent(context.graph()));
-      }, geoExtent());
-    }
-    var _locked = false;
-    var _lockedTip = uiTooltip().title(() => _t.append("inspector.lock.suggestion", { label: field.title })).placement("bottom");
-    if (_show && !field.impl) {
-      createField();
-    }
-    function createField() {
-      field.impl = uiFields[field.type](field, context).on("change", function(t2, onInput) {
-        dispatch14.call("change", field, t2, onInput);
-      });
-      if (entityIDs) {
-        field.entityIDs = entityIDs;
-        if (field.impl.entityIDs) {
-          field.impl.entityIDs(entityIDs);
-        }
-      }
-    }
-    function allKeys() {
-      let keys2 = field.keys || [field.key];
-      if (field.type === "directionalCombo" && field.key) {
-        keys2 = keys2.concat(field.key);
+  // modules/ui/sections/feature_type.js
+  function uiSectionFeatureType(context) {
+    var dispatch14 = dispatch_default("choose");
+    var _entityIDs = [];
+    var _presets = [];
+    var _tagReference;
+    var section = uiSection("feature-type", context).label(() => _t.append("inspector.feature_type")).disclosureContent(renderDisclosureContent);
+    function renderDisclosureContent(selection2) {
+      selection2.classed("preset-list-item", true);
+      selection2.classed("mixed-types", _presets.length > 1);
+      var presetButtonWrap = selection2.selectAll(".preset-list-button-wrap").data([0]).enter().append("div").attr("class", "preset-list-button-wrap");
+      var presetButton = presetButtonWrap.append("button").attr("class", "preset-list-button preset-reset").call(
+        uiTooltip().title(() => _t.append("inspector.back_tooltip")).placement("bottom")
+      );
+      presetButton.append("div").attr("class", "preset-icon-container");
+      presetButton.append("div").attr("class", "label").append("div").attr("class", "label-inner");
+      presetButtonWrap.append("div").attr("class", "accessory-buttons");
+      var tagReferenceBodyWrap = selection2.selectAll(".tag-reference-body-wrap").data([0]);
+      tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append("div").attr("class", "tag-reference-body-wrap").merge(tagReferenceBodyWrap);
+      if (_tagReference) {
+        selection2.selectAll(".preset-list-button-wrap .accessory-buttons").style("display", _presets.length === 1 ? null : "none").call(_tagReference.button);
+        tagReferenceBodyWrap.style("display", _presets.length === 1 ? null : "none").call(_tagReference.body);
       }
-      return keys2;
-    }
-    function isModified() {
-      if (!entityIDs || !entityIDs.length)
-        return false;
-      return entityIDs.some(function(entityID) {
-        var original = context.graph().base().entities[entityID];
-        var latest = context.graph().entity(entityID);
-        return allKeys().some(function(key) {
-          return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
-        });
-      });
-    }
-    function tagsContainFieldKey() {
-      return allKeys().some(function(key) {
-        if (field.type === "multiCombo") {
-          for (var tagKey in _tags) {
-            if (tagKey.indexOf(key) === 0) {
-              return true;
-            }
-          }
-          return false;
-        }
-        return _tags[key] !== void 0;
+      selection2.selectAll(".preset-reset").on("click", function() {
+        dispatch14.call("choose", this, _presets);
+      }).on("pointerdown pointerup mousedown mouseup", function(d3_event) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
       });
-    }
-    function revert(d3_event, d2) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
-      if (!entityIDs || _locked)
-        return;
-      dispatch14.call("revert", d2, allKeys());
-    }
-    function remove2(d3_event, d2) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
-      if (_locked)
-        return;
-      var t2 = {};
-      allKeys().forEach(function(key) {
-        t2[key] = void 0;
+      var geometries = entityGeometries();
+      selection2.select(".preset-list-item button").call(
+        uiPresetIcon().geometry(_presets.length === 1 ? geometries.length === 1 && geometries[0] : null).preset(_presets.length === 1 ? _presets[0] : _mainPresetIndex.item("point"))
+      );
+      var names = _presets.length === 1 ? [
+        _presets[0].nameLabel(),
+        _presets[0].subtitleLabel()
+      ].filter(Boolean) : [_t.append("inspector.multiple_types")];
+      var label = selection2.select(".label-inner");
+      var nameparts = label.selectAll(".namepart").data(names, (d2) => d2.stringId);
+      nameparts.exit().remove();
+      nameparts.enter().append("div").attr("class", "namepart").text("").each(function(d2) {
+        d2(select_default2(this));
       });
-      dispatch14.call("change", d2, t2);
     }
-    field.render = function(selection2) {
-      var container = selection2.selectAll(".form-field").data([field]);
-      var enter = container.enter().append("div").attr("class", function(d2) {
-        return "form-field form-field-" + d2.safeid;
-      }).classed("nowrap", !options2.wrap);
-      if (options2.wrap) {
-        var labelEnter = enter.append("label").attr("class", "field-label").attr("for", function(d2) {
-          return d2.domId;
-        });
-        var textEnter = labelEnter.append("span").attr("class", "label-text");
-        textEnter.append("span").attr("class", "label-textvalue").each(function(d2) {
-          d2.label()(select_default2(this));
-        });
-        textEnter.append("span").attr("class", "label-textannotation");
-        if (options2.remove) {
-          labelEnter.append("button").attr("class", "remove-icon").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
-        }
-        if (options2.revert) {
-          labelEnter.append("button").attr("class", "modified-icon").attr("title", _t("icons.undo")).call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-redo" : "#iD-icon-undo"));
-        }
-      }
-      container = container.merge(enter);
-      container.select(".field-label > .remove-icon").on("click", remove2);
-      container.select(".field-label > .modified-icon").on("click", revert);
-      container.each(function(d2) {
-        var selection3 = select_default2(this);
-        if (!d2.impl) {
-          createField();
-        }
-        var reference, help;
-        if (options2.wrap && field.type === "restrictions") {
-          help = uiFieldHelp(context, "restrictions");
-        }
-        if (options2.wrap && options2.info) {
-          var referenceKey = d2.key || "";
-          if (d2.type === "multiCombo") {
-            referenceKey = referenceKey.replace(/:$/, "");
-          }
-          var referenceOptions = d2.reference || {
-            key: referenceKey,
-            value: _tags[referenceKey]
-          };
-          reference = uiTagReference(referenceOptions, context);
-          if (_state === "hover") {
-            reference.showing(false);
-          }
-        }
-        selection3.call(d2.impl);
-        if (help) {
-          selection3.call(help.body).select(".field-label").call(help.button);
-        }
-        if (reference) {
-          selection3.call(reference.body).select(".field-label").call(reference.button);
-        }
-        d2.impl.tags(_tags);
-      });
-      container.classed("locked", _locked).classed("modified", isModified()).classed("present", tagsContainFieldKey());
-      var annotation = container.selectAll(".field-label .label-textannotation");
-      var icon2 = annotation.selectAll(".icon").data(_locked ? [0] : []);
-      icon2.exit().remove();
-      icon2.enter().append("svg").attr("class", "icon").append("use").attr("xlink:href", "#fas-lock");
-      container.call(_locked ? _lockedTip : _lockedTip.destroy);
-    };
-    field.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      _state = val;
-      return field;
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return section;
     };
-    field.tags = function(val) {
-      if (!arguments.length)
-        return _tags;
-      _tags = val;
-      if (tagsContainFieldKey() && !_show) {
-        _show = true;
-        if (!field.impl) {
-          createField();
+    section.presets = function(val) {
+      if (!arguments.length) return _presets;
+      if (!utilArrayIdentical(val, _presets)) {
+        _presets = val;
+        if (_presets.length === 1) {
+          _tagReference = uiTagReference(_presets[0].reference(), context).showing(false);
         }
       }
-      return field;
-    };
-    field.locked = function(val) {
-      if (!arguments.length)
-        return _locked;
-      _locked = val;
-      return field;
+      return section;
     };
-    field.show = function() {
-      _show = true;
-      if (!field.impl) {
-        createField();
+    function entityGeometries() {
+      var counts = {};
+      for (var i3 in _entityIDs) {
+        var geometry = context.graph().geometry(_entityIDs[i3]);
+        if (!counts[geometry]) counts[geometry] = 0;
+        counts[geometry] += 1;
       }
-      if (field.default && field.key && _tags[field.key] !== field.default) {
-        var t2 = {};
-        t2[field.key] = field.default;
-        dispatch14.call("change", this, t2);
-      }
-    };
-    field.isShown = function() {
-      return _show;
-    };
-    field.isAllowed = function() {
-      if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false)
-        return false;
-      if (field.geometry && !entityIDs.every(function(entityID) {
-        return field.matchGeometry(context.graph().geometry(entityID));
-      }))
-        return false;
-      if (entityIDs && _entityExtent && field.locationSetID) {
-        var validHere = _sharedLocationManager.locationSetsAt(_entityExtent.center());
-        if (!validHere[field.locationSetID])
-          return false;
-      }
-      var prerequisiteTag = field.prerequisiteTag;
-      if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
-      prerequisiteTag) {
-        if (!entityIDs.every(function(entityID) {
-          var entity = context.graph().entity(entityID);
-          if (prerequisiteTag.key) {
-            var value = entity.tags[prerequisiteTag.key];
-            if (!value)
-              return false;
-            if (prerequisiteTag.valueNot) {
-              return prerequisiteTag.valueNot !== value;
-            }
-            if (prerequisiteTag.value) {
-              return prerequisiteTag.value === value;
-            }
-          } else if (prerequisiteTag.keyNot) {
-            if (entity.tags[prerequisiteTag.keyNot])
-              return false;
-          }
-          return true;
-        }))
-          return false;
-      }
-      return true;
-    };
-    field.focus = function() {
-      if (field.impl) {
-        field.impl.focus();
-      }
-    };
-    return utilRebind(field, dispatch14, "on");
+      return Object.keys(counts).sort(function(geom1, geom2) {
+        return counts[geom2] - counts[geom1];
+      });
+    }
+    return utilRebind(section, dispatch14, "on");
   }
 
   // modules/ui/form_fields.js
       });
       var notShown = allowedFields.filter(function(field) {
         return !field.isShown();
+      }).sort(function(a2, b2) {
+        return a2.universal === b2.universal ? 0 : a2.universal ? 1 : -1;
       });
       var container = selection2.selectAll(".form-fields-container").data([0]);
       container = container.enter().append("div").attr("class", "form-fields-container " + (_klass || "")).merge(container);
         var title = field.title();
         titles.push(title);
         var terms = field.terms();
-        if (field.key)
-          terms.push(field.key);
-        if (field.keys)
-          terms = terms.concat(field.keys);
+        if (field.key) terms.push(field.key);
+        if (field.keys) terms = terms.concat(field.keys);
         return {
           display: field.label(),
           value: title,
       input = input.enter().append("input").attr("class", "value").attr("type", "text").attr("placeholder", placeholder).call(utilNoAuto).merge(input);
       input.call(utilGetSetValue, "").call(
         moreCombo.data(moreFields).on("accept", function(d2) {
-          if (!d2)
-            return;
+          if (!d2) return;
           var field = d2.field;
           field.show();
           selection2.call(formFields);
       }
     }
     formFields.fieldsArr = function(val) {
-      if (!arguments.length)
-        return _fieldsArr;
+      if (!arguments.length) return _fieldsArr;
       _fieldsArr = val || [];
       return formFields;
     };
     formFields.state = function(val) {
-      if (!arguments.length)
-        return _state;
+      if (!arguments.length) return _state;
       _state = val;
       return formFields;
     };
     formFields.klass = function(val) {
-      if (!arguments.length)
-        return _klass;
+      if (!arguments.length) return _klass;
       _klass = val;
       return formFields;
     };
     return formFields;
   }
 
-  // modules/ui/changeset_editor.js
-  function uiChangesetEditor(context) {
-    var dispatch14 = dispatch_default("change");
+  // modules/ui/sections/preset_fields.js
+  function uiSectionPresetFields(context) {
+    var section = uiSection("preset-fields", context).label(() => _t.append("inspector.fields")).disclosureContent(renderDisclosureContent);
+    var dispatch14 = dispatch_default("change", "revert");
     var formFields = uiFormFields(context);
-    var commentCombo = uiCombobox(context, "comment").caseSensitive(true);
+    var _state;
     var _fieldsArr;
+    var _presets = [];
     var _tags;
-    var _changesetID;
-    function changesetEditor(selection2) {
-      render(selection2);
-    }
-    function render(selection2) {
-      var initial = false;
+    var _entityIDs;
+    function renderDisclosureContent(selection2) {
       if (!_fieldsArr) {
-        initial = true;
-        var presets = _mainPresetIndex;
-        _fieldsArr = [
-          uiField(context, presets.field("comment"), null, { show: true, revert: false }),
-          uiField(context, presets.field("source"), null, { show: true, revert: false }),
-          uiField(context, presets.field("hashtags"), null, { show: false, revert: false })
-        ];
-        _fieldsArr.forEach(function(field) {
-          field.on("change", function(t2, onInput) {
-            dispatch14.call("change", field, void 0, t2, onInput);
-          });
+        var graph = context.graph();
+        var geometries = Object.keys(_entityIDs.reduce(function(geoms, entityID) {
+          geoms[graph.entity(entityID).geometry(graph)] = true;
+          return geoms;
+        }, {}));
+        const loc = _entityIDs.reduce(function(extent, entityID) {
+          var entity = context.graph().entity(entityID);
+          return extent.extend(entity.extent(context.graph()));
+        }, geoExtent()).center();
+        var presetsManager = _mainPresetIndex;
+        var allFields = [];
+        var allMoreFields = [];
+        var sharedTotalFields;
+        _presets.forEach(function(preset) {
+          var fields = preset.fields(loc);
+          var moreFields = preset.moreFields(loc);
+          allFields = utilArrayUnion(allFields, fields);
+          allMoreFields = utilArrayUnion(allMoreFields, moreFields);
+          if (!sharedTotalFields) {
+            sharedTotalFields = utilArrayUnion(fields, moreFields);
+          } else {
+            sharedTotalFields = sharedTotalFields.filter(function(field) {
+              return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
+            });
+          }
         });
-      }
-      _fieldsArr.forEach(function(field) {
-        field.tags(_tags);
-      });
-      selection2.call(formFields.fieldsArr(_fieldsArr));
-      if (initial) {
-        var commentField = selection2.select(".form-field-comment textarea");
-        var commentNode = commentField.node();
-        if (commentNode) {
-          commentNode.focus();
-          commentNode.select();
-        }
-        utilTriggerEvent(commentField, "blur");
-        var osm = context.connection();
-        if (osm) {
-          osm.userChangesets(function(err, changesets) {
-            if (err)
-              return;
-            var comments = changesets.map(function(changeset) {
-              var comment = changeset.tags.comment;
-              return comment ? { title: comment, value: comment } : null;
-            }).filter(Boolean);
-            commentField.call(
-              commentCombo.data(utilArrayUniqBy(comments, "title"))
+        var sharedFields = allFields.filter(function(field) {
+          return sharedTotalFields.indexOf(field) !== -1;
+        });
+        var sharedMoreFields = allMoreFields.filter(function(field) {
+          return sharedTotalFields.indexOf(field) !== -1;
+        });
+        _fieldsArr = [];
+        sharedFields.forEach(function(field) {
+          if (field.matchAllGeometry(geometries)) {
+            _fieldsArr.push(
+              uiField(context, field, _entityIDs)
             );
-          });
+          }
+        });
+        var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
+        if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field("restrictions")) {
+          _fieldsArr.push(
+            uiField(context, presetsManager.field("restrictions"), _entityIDs)
+          );
         }
-      }
-      const warnings = [];
-      if (_tags.comment.match(/google/i)) {
-        warnings.push({
-          id: 'contains "google"',
-          msg: _t.append("commit.google_warning"),
-          link: _t("commit.google_warning_link")
+        var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
+        additionalFields.sort(function(field1, field2) {
+          return field1.title().localeCompare(field2.title(), _mainLocalizer.localeCode());
         });
-      }
-      const maxChars = context.maxCharsForTagValue();
-      const strLen = utilUnicodeCharsCount(utilCleanOsmString(_tags.comment, Number.POSITIVE_INFINITY));
-      if (strLen > maxChars || false) {
-        warnings.push({
-          id: "message too long",
-          msg: _t.append("commit.changeset_comment_length_warning", { maxChars })
+        additionalFields.forEach(function(field) {
+          if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
+            _fieldsArr.push(
+              uiField(context, field, _entityIDs, { show: false })
+            );
+          }
+        });
+        _fieldsArr.forEach(function(field) {
+          field.on("change", function(t2, onInput) {
+            dispatch14.call("change", field, _entityIDs, t2, onInput);
+          }).on("revert", function(keys2) {
+            dispatch14.call("revert", field, keys2);
+          });
         });
       }
-      var commentWarning = selection2.select(".form-field-comment").selectAll(".comment-warning").data(warnings, (d2) => d2.id);
-      commentWarning.exit().transition().duration(200).style("opacity", 0).remove();
-      var commentEnter = commentWarning.enter().insert("div", ".comment-warning").attr("class", "comment-warning field-warning").style("opacity", 0);
-      commentEnter.call(svgIcon("#iD-icon-alert", "inline")).append("span");
-      commentEnter.transition().duration(200).style("opacity", 1);
-      commentWarning.merge(commentEnter).selectAll("div > span").text("").each(function(d2) {
-        let selection3 = select_default2(this);
-        if (d2.link) {
-          selection3 = selection3.append("a").attr("target", "_blank").attr("href", d2.link);
-        }
-        selection3.call(d2.msg);
+      _fieldsArr.forEach(function(field) {
+        field.state(_state).tags(_tags);
       });
+      selection2.call(
+        formFields.fieldsArr(_fieldsArr).state(_state).klass("grouped-items-area")
+      );
     }
-    changesetEditor.tags = function(_2) {
-      if (!arguments.length)
-        return _tags;
-      _tags = _2;
-      return changesetEditor;
+    section.presets = function(val) {
+      if (!arguments.length) return _presets;
+      if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
+        _presets = val;
+        _fieldsArr = null;
+      }
+      return section;
     };
-    changesetEditor.changesetID = function(_2) {
-      if (!arguments.length)
-        return _changesetID;
-      if (_changesetID === _2)
-        return changesetEditor;
-      _changesetID = _2;
-      _fieldsArr = null;
-      return changesetEditor;
+    section.state = function(val) {
+      if (!arguments.length) return _state;
+      _state = val;
+      return section;
     };
-    return utilRebind(changesetEditor, dispatch14, "on");
+    section.tags = function(val) {
+      if (!arguments.length) return _tags;
+      _tags = val;
+      return section;
+    };
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
+        _entityIDs = val;
+        _fieldsArr = null;
+      }
+      return section;
+    };
+    return utilRebind(section, dispatch14, "on");
   }
 
-  // modules/ui/commit.js
-  var import_fast_deep_equal9 = __toESM(require_fast_deep_equal());
-
-  // modules/util/jxon.js
-  var JXON = new function() {
-    var sValueProp = "keyValue", sAttributesProp = "keyAttributes", sAttrPref = "@", aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
-    function parseText(sValue) {
-      if (rIsNull.test(sValue)) {
-        return null;
-      }
-      if (rIsBool.test(sValue)) {
-        return sValue.toLowerCase() === "true";
-      }
-      if (isFinite(sValue)) {
-        return parseFloat(sValue);
-      }
-      if (isFinite(Date.parse(sValue))) {
-        return new Date(sValue);
-      }
-      return sValue;
-    }
-    function EmptyTree() {
+  // modules/ui/sections/raw_member_editor.js
+  function uiSectionRawMemberEditor(context) {
+    var section = uiSection("raw-member-editor", context).shouldDisplay(function() {
+      if (!_entityIDs || _entityIDs.length !== 1) return false;
+      var entity = context.hasEntity(_entityIDs[0]);
+      return entity && entity.type === "relation";
+    }).label(function() {
+      var entity = context.hasEntity(_entityIDs[0]);
+      if (!entity) return "";
+      var gt2 = entity.members.length > _maxMembers ? ">" : "";
+      var count = gt2 + entity.members.slice(0, _maxMembers).length;
+      return _t.append("inspector.title_count", { title: _t("inspector.members"), count });
+    }).disclosureContent(renderDisclosureContent);
+    var taginfo = services.taginfo;
+    var _entityIDs;
+    var _maxMembers = 1e3;
+    function downloadMember(d3_event, d2) {
+      d3_event.preventDefault();
+      select_default2(this).classed("loading", true);
+      context.loadEntity(d2.id, function() {
+        section.reRender();
+      });
     }
-    EmptyTree.prototype.toString = function() {
-      return "null";
-    };
-    EmptyTree.prototype.valueOf = function() {
-      return null;
-    };
-    function objectify(vValue) {
-      return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
+    function zoomToMember(d3_event, d2) {
+      d3_event.preventDefault();
+      var entity = context.entity(d2.id);
+      context.map().zoomToEase(entity);
+      utilHighlightEntities([d2.id], true, context);
     }
-    function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
-      var nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(), bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
-      var sProp, vContent, nLength = 0, sCollectedTxt = "", vResult = bHighVerb ? {} : (
-        /* put here the default value for empty nodes: */
-        true
-      );
-      if (bChildren) {
-        for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
-          oNode = oParentNode.childNodes.item(nItem);
-          if (oNode.nodeType === 4) {
-            sCollectedTxt += oNode.nodeValue;
-          } else if (oNode.nodeType === 3) {
-            sCollectedTxt += oNode.nodeValue.trim();
-          } else if (oNode.nodeType === 1 && !oNode.prefix) {
-            aCache.push(oNode);
-          }
-        }
-      }
-      var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
-      if (!bHighVerb && (bChildren || bAttributes)) {
-        vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
-      }
-      for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
-        sProp = aCache[nElId].nodeName.toLowerCase();
-        vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
-        if (vResult.hasOwnProperty(sProp)) {
-          if (vResult[sProp].constructor !== Array) {
-            vResult[sProp] = [vResult[sProp]];
-          }
-          vResult[sProp].push(vContent);
-        } else {
-          vResult[sProp] = vContent;
-          nLength++;
-        }
-      }
-      if (bAttributes) {
-        var nAttrLen = oParentNode.attributes.length, sAPrefix = bNesteAttr ? "" : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
-        for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
-          oAttrib = oParentNode.attributes.item(nAttrib);
-          oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
-        }
-        if (bNesteAttr) {
-          if (bFreeze) {
-            Object.freeze(oAttrParent);
-          }
-          vResult[sAttributesProp] = oAttrParent;
-          nLength -= nAttrLen - 1;
-        }
-      }
-      if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
-        vResult[sValueProp] = vBuiltVal;
-      } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
-        vResult = vBuiltVal;
-      }
-      if (bFreeze && (bHighVerb || nLength > 0)) {
-        Object.freeze(vResult);
+    function selectMember(d3_event, d2) {
+      d3_event.preventDefault();
+      utilHighlightEntities([d2.id], false, context);
+      var entity = context.entity(d2.id);
+      var mapExtent = context.map().extent();
+      if (!entity.intersects(mapExtent, context.graph())) {
+        context.map().zoomToEase(entity);
       }
-      aCache.length = nLevelStart;
-      return vResult;
+      context.enter(modeSelect(context, [d2.id]));
     }
-    function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
-      var vValue, oChild;
-      if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
-        oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
-      } else if (oParentObj.constructor === Date) {
-        oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
-      }
-      for (var sName in oParentObj) {
-        vValue = oParentObj[sName];
-        if (isFinite(sName) || vValue instanceof Function) {
-          continue;
-        }
-        if (sName === sValueProp) {
-          if (vValue !== null && vValue !== true) {
-            oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
-          }
-        } else if (sName === sAttributesProp) {
-          for (var sAttrib in vValue) {
-            oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
-          }
-        } else if (sName.charAt(0) === sAttrPref) {
-          oParentEl.setAttribute(sName.slice(1), vValue);
-        } else if (vValue.constructor === Array) {
-          for (var nItem = 0; nItem < vValue.length; nItem++) {
-            oChild = oXMLDoc.createElement(sName);
-            loadObjTree(oXMLDoc, oChild, vValue[nItem]);
-            oParentEl.appendChild(oChild);
-          }
-        } else {
-          oChild = oXMLDoc.createElement(sName);
-          if (vValue instanceof Object) {
-            loadObjTree(oXMLDoc, oChild, vValue);
-          } else if (vValue !== null && vValue !== true) {
-            oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
-          }
-          oParentEl.appendChild(oChild);
-        }
+    function changeRole(d3_event, d2) {
+      var oldRole = d2.role;
+      var newRole = context.cleanRelationRole(select_default2(this).property("value"));
+      if (oldRole !== newRole) {
+        var member = { id: d2.id, type: d2.type, role: newRole };
+        context.perform(
+          actionChangeMember(d2.relation.id, member, d2.index),
+          _t("operations.change_role.annotation", {
+            n: 1
+          })
+        );
+        context.validator().validate();
       }
     }
-    this.build = function(oXMLParent, nVerbosity, bFreeze, bNesteAttributes) {
-      var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : (
-        /* put here the default verbosity level: */
-        1
+    function deleteMember(d3_event, d2) {
+      utilHighlightEntities([d2.id], false, context);
+      context.perform(
+        actionDeleteMember(d2.relation.id, d2.index),
+        _t("operations.delete_member.annotation", {
+          n: 1
+        })
       );
-      return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
-    };
-    this.unbuild = function(oObjTree) {
-      var oNewDoc = document.implementation.createDocument("", "", null);
-      loadObjTree(oNewDoc, oNewDoc, oObjTree);
-      return oNewDoc;
-    };
-    this.stringify = function(oObjTree) {
-      return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
-    };
-  }();
-
-  // modules/ui/sections/changes.js
-  function uiSectionChanges(context) {
-    var _discardTags = {};
-    _mainFileFetcher.get("discarded").then(function(d2) {
-      _discardTags = d2;
-    }).catch(function() {
-    });
-    var section = uiSection("changes-list", context).label(function() {
-      var history = context.history();
-      var summary = history.difference().summary();
-      return _t.append("inspector.title_count", { title: _t("commit.changes"), count: summary.length });
-    }).disclosureContent(renderDisclosureContent);
+      if (!context.hasEntity(d2.relation.id)) {
+        context.enter(modeBrowse(context));
+      } else {
+        context.validator().validate();
+      }
+    }
     function renderDisclosureContent(selection2) {
-      var history = context.history();
-      var summary = history.difference().summary();
-      var container = selection2.selectAll(".commit-section").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "commit-section");
-      containerEnter.append("ul").attr("class", "changeset-list");
-      container = containerEnter.merge(container);
-      var items = container.select("ul").selectAll("li").data(summary);
-      var itemsEnter = items.enter().append("li").attr("class", "change-item");
-      var buttons = itemsEnter.append("button").on("mouseover", mouseover).on("mouseout", mouseout).on("click", click);
-      buttons.each(function(d2) {
-        select_default2(this).call(svgIcon("#iD-icon-" + d2.entity.geometry(d2.graph), "pre-text " + d2.changeType));
+      var entityID = _entityIDs[0];
+      var memberships = [];
+      var entity = context.entity(entityID);
+      entity.members.slice(0, _maxMembers).forEach(function(member, index) {
+        memberships.push({
+          index,
+          id: member.id,
+          type: member.type,
+          role: member.role,
+          relation: entity,
+          member: context.hasEntity(member.id),
+          domId: utilUniqueDomId(entityID + "-member-" + index)
+        });
       });
-      buttons.append("span").attr("class", "change-type").html(function(d2) {
-        return _t.html("commit." + d2.changeType) + " ";
+      var list2 = selection2.selectAll(".member-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "member-list").merge(list2);
+      var items = list2.selectAll("li").data(memberships, function(d2) {
+        return osmEntity.key(d2.relation) + "," + d2.index + "," + (d2.member ? osmEntity.key(d2.member) : "incomplete");
       });
-      buttons.append("strong").attr("class", "entity-type").text(function(d2) {
-        var matched = _mainPresetIndex.match(d2.entity, d2.graph);
-        return matched && matched.name() || utilDisplayType(d2.entity.id);
+      items.exit().each(unbind).remove();
+      var itemsEnter = items.enter().append("li").attr("class", "member-row form-field").classed("member-incomplete", function(d2) {
+        return !d2.member;
       });
-      buttons.append("span").attr("class", "entity-name").text(function(d2) {
-        var name = utilDisplayName(d2.entity) || "", string = "";
-        if (name !== "") {
-          string += ":";
+      itemsEnter.each(function(d2) {
+        var item = select_default2(this);
+        var label = item.append("label").attr("class", "field-label").attr("for", d2.domId);
+        if (d2.member) {
+          item.on("mouseover", function() {
+            utilHighlightEntities([d2.id], true, context);
+          }).on("mouseout", function() {
+            utilHighlightEntities([d2.id], false, context);
+          });
+          var labelLink = label.append("span").attr("class", "label-text").append("a").attr("href", "#").on("click", selectMember);
+          labelLink.append("span").attr("class", "member-entity-type").text(function(d4) {
+            var matched = _mainPresetIndex.match(d4.member, context.graph());
+            return matched && matched.name() || utilDisplayType(d4.member.id);
+          });
+          labelLink.append("span").attr("class", "member-entity-name").classed("has-colour", (d4) => d4.member.type === "relation" && d4.member.tags.colour && isColourValid(d4.member.tags.colour)).style("border-color", (d4) => d4.member.type === "relation" && d4.member.tags.colour).text(function(d4) {
+            return utilDisplayName(d4.member);
+          });
+          label.append("button").attr("title", _t("icons.remove")).attr("class", "remove member-delete").call(svgIcon("#iD-operation-delete"));
+          label.append("button").attr("class", "member-zoom").attr("title", _t("icons.zoom_to")).call(svgIcon("#iD-icon-framed-dot", "monochrome")).on("click", zoomToMember);
+        } else {
+          var labelText = label.append("span").attr("class", "label-text");
+          labelText.append("span").attr("class", "member-entity-type").call(_t.append("inspector." + d2.type, { id: d2.id }));
+          labelText.append("span").attr("class", "member-entity-name").call(_t.append("inspector.incomplete", { id: d2.id }));
+          label.append("button").attr("class", "member-download").attr("title", _t("icons.download")).call(svgIcon("#iD-icon-load")).on("click", downloadMember);
         }
-        return string += " " + name;
       });
-      items = itemsEnter.merge(items);
-      var changeset = new osmChangeset().update({ id: void 0 });
-      var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
-      delete changeset.id;
-      var data = JXON.stringify(changeset.osmChangeJXON(changes));
-      var blob = new Blob([data], { type: "text/xml;charset=utf-8;" });
-      var fileName = "changes.osc";
-      var linkEnter = container.selectAll(".download-changes").data([0]).enter().append("a").attr("class", "download-changes");
-      linkEnter.attr("href", window.URL.createObjectURL(blob)).attr("download", fileName);
-      linkEnter.call(svgIcon("#iD-icon-load", "inline")).append("span").call(_t.append("commit.download_changes"));
-      function mouseover(d2) {
-        if (d2.entity) {
-          context.surface().selectAll(
-            utilEntityOrMemberSelector([d2.entity.id], context.graph())
-          ).classed("hover", true);
-        }
-      }
-      function mouseout() {
-        context.surface().selectAll(".hover").classed("hover", false);
+      var wrapEnter = itemsEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
+      wrapEnter.append("input").attr("class", "member-role").attr("id", function(d2) {
+        return d2.domId;
+      }).property("type", "text").attr("placeholder", _t("inspector.role")).call(utilNoAuto);
+      if (taginfo) {
+        wrapEnter.each(bindTypeahead);
       }
-      function click(d3_event, change) {
-        if (change.changeType !== "deleted") {
-          var entity = change.entity;
-          context.map().zoomToEase(entity);
-          context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed("hover", true);
+      items = items.merge(itemsEnter).order();
+      items.select("input.member-role").property("value", function(d2) {
+        return d2.role;
+      }).on("blur", changeRole).on("change", changeRole);
+      items.select("button.member-delete").on("click", deleteMember);
+      var dragOrigin, targetIndex;
+      items.call(
+        drag_default().on("start", function(d3_event) {
+          dragOrigin = {
+            x: d3_event.x,
+            y: d3_event.y
+          };
+          targetIndex = null;
+        }).on("drag", function(d3_event) {
+          var x2 = d3_event.x - dragOrigin.x, y2 = d3_event.y - dragOrigin.y;
+          if (!select_default2(this).classed("dragging") && // don't display drag until dragging beyond a distance threshold
+          Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2)) <= 5) return;
+          var index = items.nodes().indexOf(this);
+          select_default2(this).classed("dragging", true);
+          targetIndex = null;
+          selection2.selectAll("li.member-row").style("transform", function(d2, index2) {
+            var node = select_default2(this).node();
+            if (index === index2) {
+              return "translate(" + x2 + "px, " + y2 + "px)";
+            } else if (index2 > index && d3_event.y > node.offsetTop) {
+              if (targetIndex === null || index2 > targetIndex) {
+                targetIndex = index2;
+              }
+              return "translateY(-100%)";
+            } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
+              if (targetIndex === null || index2 < targetIndex) {
+                targetIndex = index2;
+              }
+              return "translateY(100%)";
+            }
+            return null;
+          });
+        }).on("end", function(d3_event, d2) {
+          if (!select_default2(this).classed("dragging")) return;
+          var index = items.nodes().indexOf(this);
+          select_default2(this).classed("dragging", false);
+          selection2.selectAll("li.member-row").style("transform", null);
+          if (targetIndex !== null) {
+            context.perform(
+              actionMoveMember(d2.relation.id, index, targetIndex),
+              _t("operations.reorder_members.annotation")
+            );
+            context.validator().validate();
+          }
+        })
+      );
+      function bindTypeahead(d2) {
+        var row = select_default2(this);
+        var role = row.selectAll("input.member-role");
+        var origValue = role.property("value");
+        function sort(value, data) {
+          var sameletter = [];
+          var other = [];
+          for (var i3 = 0; i3 < data.length; i3++) {
+            if (data[i3].value.substring(0, value.length) === value) {
+              sameletter.push(data[i3]);
+            } else {
+              other.push(data[i3]);
+            }
+          }
+          return sameletter.concat(other);
         }
+        role.call(
+          uiCombobox(context, "member-role").fetcher(function(role2, callback) {
+            var geometry;
+            if (d2.member) {
+              geometry = context.graph().geometry(d2.member.id);
+            } else if (d2.type === "relation") {
+              geometry = "relation";
+            } else if (d2.type === "way") {
+              geometry = "line";
+            } else {
+              geometry = "point";
+            }
+            var rtype = entity.tags.type;
+            taginfo.roles({
+              debounce: true,
+              rtype: rtype || "",
+              geometry,
+              query: role2
+            }, function(err, data) {
+              if (!err) callback(sort(role2, data));
+            });
+          }).on("cancel", function() {
+            role.property("value", origValue);
+          })
+        );
+      }
+      function unbind() {
+        var row = select_default2(this);
+        row.selectAll("input.member-role").call(uiCombobox.off, context);
       }
     }
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return section;
+    };
     return section;
   }
 
-  // modules/ui/commit_warnings.js
-  function uiCommitWarnings(context) {
-    function commitWarnings(selection2) {
-      var issuesBySeverity = context.validator().getIssuesBySeverity({ what: "edited", where: "all", includeDisabledRules: true });
-      for (var severity in issuesBySeverity) {
-        var issues = issuesBySeverity[severity];
-        if (severity !== "error") {
-          issues = issues.filter(function(issue) {
-            return issue.type !== "help_request";
-          });
-        }
-        var section = severity + "-section";
-        var issueItem = severity + "-item";
-        var container = selection2.selectAll("." + section).data(issues.length ? [0] : []);
-        container.exit().remove();
-        var containerEnter = container.enter().append("div").attr("class", "modal-section " + section + " fillL2");
-        containerEnter.append("h3").call(severity === "warning" ? _t.append("commit.warnings") : _t.append("commit.errors"));
-        containerEnter.append("ul").attr("class", "changeset-list");
-        container = containerEnter.merge(container);
-        var items = container.select("ul").selectAll("li").data(issues, function(d2) {
-          return d2.key;
-        });
-        items.exit().remove();
-        var itemsEnter = items.enter().append("li").attr("class", issueItem);
-        var buttons = itemsEnter.append("button").on("mouseover", function(d3_event, d2) {
-          if (d2.entityIds) {
-            context.surface().selectAll(
-              utilEntityOrMemberSelector(
-                d2.entityIds,
-                context.graph()
-              )
-            ).classed("hover", true);
-          }
-        }).on("mouseout", function() {
-          context.surface().selectAll(".hover").classed("hover", false);
-        }).on("click", function(d3_event, d2) {
-          context.validator().focusIssue(d2);
-        });
-        buttons.call(svgIcon("#iD-icon-alert", "pre-text"));
-        buttons.append("strong").attr("class", "issue-message");
-        buttons.filter(function(d2) {
-          return d2.tooltip;
-        }).call(
-          uiTooltip().title(function(d2) {
-            return d2.tooltip;
-          }).placement("top")
-        );
-        items = itemsEnter.merge(items);
-        items.selectAll(".issue-message").text("").each(function(d2) {
-          return d2.message(context)(select_default2(this));
-        });
+  // modules/actions/delete_members.js
+  function actionDeleteMembers(relationId, memberIndexes) {
+    return function(graph) {
+      memberIndexes.sort((a2, b2) => b2 - a2);
+      for (var i3 in memberIndexes) {
+        graph = actionDeleteMember(relationId, memberIndexes[i3])(graph);
       }
-    }
-    return commitWarnings;
+      return graph;
+    };
   }
 
-  // modules/ui/commit.js
-  var readOnlyTags = [
-    /^changesets_count$/,
-    /^created_by$/,
-    /^ideditor:/,
-    /^imagery_used$/,
-    /^host$/,
-    /^locale$/,
-    /^warnings:/,
-    /^resolved:/,
-    /^closed:note$/,
-    /^closed:keepright$/,
-    /^closed:improveosm:/,
-    /^closed:osmose:/
-  ];
-  var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
-  function uiCommit(context) {
-    var dispatch14 = dispatch_default("cancel");
-    var _userDetails2;
-    var _selection;
-    var changesetEditor = uiChangesetEditor(context).on("change", changeTags);
-    var rawTagEditor = uiSectionRawTagEditor("changeset-tag-editor", context).on("change", changeTags).readOnlyTags(readOnlyTags);
-    var commitChanges = uiSectionChanges(context);
-    var commitWarnings = uiCommitWarnings(context);
-    function commit(selection2) {
-      _selection = selection2;
-      if (!context.changeset)
-        initChangeset();
-      loadDerivedChangesetTags();
-      selection2.call(render);
-    }
-    function initChangeset() {
-      var commentDate = +corePreferences("commentDate") || 0;
-      var currDate = Date.now();
-      var cutoff = 2 * 86400 * 1e3;
-      if (commentDate > currDate || currDate - commentDate > cutoff) {
-        corePreferences("comment", null);
-        corePreferences("hashtags", null);
-        corePreferences("source", null);
-      }
-      if (context.defaultChangesetComment()) {
-        corePreferences("comment", context.defaultChangesetComment());
-        corePreferences("commentDate", Date.now());
-      }
-      if (context.defaultChangesetSource()) {
-        corePreferences("source", context.defaultChangesetSource());
-        corePreferences("commentDate", Date.now());
-      }
-      if (context.defaultChangesetHashtags()) {
-        corePreferences("hashtags", context.defaultChangesetHashtags());
-        corePreferences("commentDate", Date.now());
-      }
-      var detected = utilDetect();
-      var tags = {
-        comment: corePreferences("comment") || "",
-        created_by: context.cleanTagValue("iD " + context.version),
-        host: context.cleanTagValue(detected.host),
-        locale: context.cleanTagValue(_mainLocalizer.localeCode())
-      };
-      findHashtags(tags, true);
-      var hashtags = corePreferences("hashtags");
-      if (hashtags) {
-        tags.hashtags = hashtags;
-      }
-      var source = corePreferences("source");
-      if (source) {
-        tags.source = source;
-      }
-      var photoOverlaysUsed = context.history().photoOverlaysUsed();
-      if (photoOverlaysUsed.length) {
-        var sources = (tags.source || "").split(";");
-        if (sources.indexOf("streetlevel imagery") === -1) {
-          sources.push("streetlevel imagery");
+  // modules/ui/sections/raw_membership_editor.js
+  function uiSectionRawMembershipEditor(context) {
+    var section = uiSection("raw-membership-editor", context).shouldDisplay(function() {
+      return _entityIDs && _entityIDs.length;
+    }).label(function() {
+      var parents = getSharedParentRelations();
+      var gt2 = parents.length > _maxMemberships ? ">" : "";
+      var count = gt2 + parents.slice(0, _maxMemberships).length;
+      return _t.append("inspector.title_count", { title: _t("inspector.relations"), count });
+    }).disclosureContent(renderDisclosureContent);
+    var taginfo = services.taginfo;
+    var nearbyCombo = uiCombobox(context, "parent-relation").minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function(d3_event, d2) {
+      if (d2.relation) utilHighlightEntities([d2.relation.id], true, context);
+    }).itemsMouseLeave(function(d3_event, d2) {
+      if (d2.relation) utilHighlightEntities([d2.relation.id], false, context);
+    });
+    var _inChange = false;
+    var _entityIDs = [];
+    var _showBlank;
+    var _maxMemberships = 1e3;
+    function getSharedParentRelations() {
+      var parents = [];
+      for (var i3 = 0; i3 < _entityIDs.length; i3++) {
+        var entity = context.graph().hasEntity(_entityIDs[i3]);
+        if (!entity) continue;
+        if (i3 === 0) {
+          parents = context.graph().parentRelations(entity);
+        } else {
+          parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
         }
-        photoOverlaysUsed.forEach(function(photoOverlay) {
-          if (sources.indexOf(photoOverlay) === -1) {
-            sources.push(photoOverlay);
-          }
-        });
-        tags.source = context.cleanTagValue(sources.join(";"));
+        if (!parents.length) break;
       }
-      context.changeset = new osmChangeset({ tags });
+      return parents;
     }
-    function loadDerivedChangesetTags() {
-      var osm = context.connection();
-      if (!osm)
-        return;
-      var tags = Object.assign({}, context.changeset.tags);
-      var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(";"));
-      tags.imagery_used = imageryUsed || "None";
-      var osmClosed = osm.getClosedIDs();
-      var itemType;
-      if (osmClosed.length) {
-        tags["closed:note"] = context.cleanTagValue(osmClosed.join(";"));
-      }
-      if (services.keepRight) {
-        var krClosed = services.keepRight.getClosedIDs();
-        if (krClosed.length) {
-          tags["closed:keepright"] = context.cleanTagValue(krClosed.join(";"));
-        }
-      }
-      if (services.improveOSM) {
-        var iOsmClosed = services.improveOSM.getClosedCounts();
-        for (itemType in iOsmClosed) {
-          tags["closed:improveosm:" + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
-        }
-      }
-      if (services.osmose) {
-        var osmoseClosed = services.osmose.getClosedCounts();
-        for (itemType in osmoseClosed) {
-          tags["closed:osmose:" + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
-        }
-      }
-      for (var key in tags) {
-        if (key.match(/(^warnings:)|(^resolved:)/)) {
-          delete tags[key];
-        }
-      }
-      function addIssueCounts(issues, prefix) {
-        var issuesByType = utilArrayGroupBy(issues, "type");
-        for (var issueType in issuesByType) {
-          var issuesOfType = issuesByType[issueType];
-          if (issuesOfType[0].subtype) {
-            var issuesBySubtype = utilArrayGroupBy(issuesOfType, "subtype");
-            for (var issueSubtype in issuesBySubtype) {
-              var issuesOfSubtype = issuesBySubtype[issueSubtype];
-              tags[prefix + ":" + issueType + ":" + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
+    function getMemberships() {
+      var memberships = [];
+      var relations = getSharedParentRelations().slice(0, _maxMemberships);
+      var isMultiselect = _entityIDs.length > 1;
+      var i3, relation, membership, index, member, indexedMember;
+      for (i3 = 0; i3 < relations.length; i3++) {
+        relation = relations[i3];
+        membership = {
+          relation,
+          members: [],
+          hash: osmEntity.key(relation)
+        };
+        for (index = 0; index < relation.members.length; index++) {
+          member = relation.members[index];
+          if (_entityIDs.indexOf(member.id) !== -1) {
+            indexedMember = Object.assign({}, member, { index });
+            membership.members.push(indexedMember);
+            membership.hash += "," + index.toString();
+            if (!isMultiselect) {
+              memberships.push(membership);
+              membership = {
+                relation,
+                members: [],
+                hash: osmEntity.key(relation)
+              };
             }
-          } else {
-            tags[prefix + ":" + issueType] = context.cleanTagValue(issuesOfType.length.toString());
           }
         }
+        if (membership.members.length) memberships.push(membership);
       }
-      var warnings = context.validator().getIssuesBySeverity({ what: "edited", where: "all", includeIgnored: true, includeDisabledRules: true }).warning.filter(function(issue) {
-        return issue.type !== "help_request";
+      memberships.forEach(function(membership2) {
+        membership2.domId = utilUniqueDomId("membership-" + membership2.relation.id);
+        var roles = [];
+        membership2.members.forEach(function(member2) {
+          if (roles.indexOf(member2.role) === -1) roles.push(member2.role);
+        });
+        membership2.role = roles.length === 1 ? roles[0] : roles;
       });
-      addIssueCounts(warnings, "warnings");
-      var resolvedIssues = context.validator().getResolvedIssues();
-      addIssueCounts(resolvedIssues, "resolved");
-      context.changeset = context.changeset.update({ tags });
+      return memberships;
     }
-    function render(selection2) {
-      var osm = context.connection();
-      if (!osm)
-        return;
-      var header = selection2.selectAll(".header").data([0]);
-      var headerTitle = header.enter().append("div").attr("class", "header fillL");
-      headerTitle.append("div").append("h2").call(_t.append("commit.title"));
-      headerTitle.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
-        dispatch14.call("cancel", this);
-      }).call(svgIcon("#iD-icon-close"));
-      var body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      var changesetSection = body.selectAll(".changeset-editor").data([0]);
-      changesetSection = changesetSection.enter().append("div").attr("class", "modal-section changeset-editor").merge(changesetSection);
-      changesetSection.call(
-        changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)
-      );
-      body.call(commitWarnings);
-      var saveSection = body.selectAll(".save-section").data([0]);
-      saveSection = saveSection.enter().append("div").attr("class", "modal-section save-section fillL").merge(saveSection);
-      var prose = saveSection.selectAll(".commit-info").data([0]);
-      if (prose.enter().size()) {
-        _userDetails2 = null;
-      }
-      prose = prose.enter().append("p").attr("class", "commit-info").call(_t.append("commit.upload_explanation")).merge(prose);
-      osm.userDetails(function(err, user) {
-        if (err)
-          return;
-        if (_userDetails2 === user)
-          return;
-        _userDetails2 = user;
-        var userLink = select_default2(document.createElement("div"));
-        if (user.image_url) {
-          userLink.append("img").attr("src", user.image_url).attr("class", "icon pre-text user-icon");
-        }
-        userLink.append("a").attr("class", "user-info").text(user.display_name).attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
-        prose.html(_t.html("commit.upload_explanation_with_user", { user: { html: userLink.html() } }));
+    function selectRelation(d3_event, d2) {
+      d3_event.preventDefault();
+      utilHighlightEntities([d2.relation.id], false, context);
+      context.enter(modeSelect(context, [d2.relation.id]));
+    }
+    function zoomToRelation(d3_event, d2) {
+      d3_event.preventDefault();
+      var entity = context.entity(d2.relation.id);
+      context.map().zoomToEase(entity);
+      utilHighlightEntities([d2.relation.id], true, context);
+    }
+    function changeRole(d3_event, d2) {
+      if (d2 === 0) return;
+      if (_inChange) return;
+      var newRole = context.cleanRelationRole(select_default2(this).property("value"));
+      if (!newRole.trim() && typeof d2.role !== "string") return;
+      var membersToUpdate = d2.members.filter(function(member) {
+        return member.role !== newRole;
       });
-      var requestReview = saveSection.selectAll(".request-review").data([0]);
-      var requestReviewEnter = requestReview.enter().append("div").attr("class", "request-review");
-      var requestReviewDomId = utilUniqueDomId("commit-input-request-review");
-      var labelEnter = requestReviewEnter.append("label").attr("for", requestReviewDomId);
-      if (!labelEnter.empty()) {
-        labelEnter.call(uiTooltip().title(() => _t.append("commit.request_review_info")).placement("top"));
+      if (membersToUpdate.length) {
+        _inChange = true;
+        context.perform(
+          function actionChangeMemberRoles(graph) {
+            membersToUpdate.forEach(function(member) {
+              var newMember = Object.assign({}, member, { role: newRole });
+              delete newMember.index;
+              graph = actionChangeMember(d2.relation.id, newMember, member.index)(graph);
+            });
+            return graph;
+          },
+          _t("operations.change_role.annotation", {
+            n: membersToUpdate.length
+          })
+        );
+        context.validator().validate();
       }
-      labelEnter.append("input").attr("type", "checkbox").attr("id", requestReviewDomId);
-      labelEnter.append("span").call(_t.append("commit.request_review"));
-      requestReview = requestReview.merge(requestReviewEnter);
-      var requestReviewInput = requestReview.selectAll("input").property("checked", isReviewRequested(context.changeset.tags)).on("change", toggleRequestReview);
-      var buttonSection = saveSection.selectAll(".buttons").data([0]);
-      var buttonEnter = buttonSection.enter().append("div").attr("class", "buttons fillL");
-      buttonEnter.append("button").attr("class", "secondary-action button cancel-button").append("span").attr("class", "label").call(_t.append("commit.cancel"));
-      var uploadButton = buttonEnter.append("button").attr("class", "action button save-button");
-      uploadButton.append("span").attr("class", "label").call(_t.append("commit.save"));
-      var uploadBlockerTooltipText = getUploadBlockerMessage();
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.selectAll(".cancel-button").on("click.cancel", function() {
-        dispatch14.call("cancel", this);
-      });
-      buttonSection.selectAll(".save-button").classed("disabled", uploadBlockerTooltipText !== null).on("click.save", function() {
-        if (!select_default2(this).classed("disabled")) {
-          this.blur();
-          for (var key in context.changeset.tags) {
-            if (!key)
-              delete context.changeset.tags[key];
+      _inChange = false;
+    }
+    function addMembership(d2, role) {
+      this.blur();
+      _showBlank = false;
+      function actionAddMembers(relationId, ids, role2) {
+        return function(graph) {
+          for (var i3 in ids) {
+            var member = { id: ids[i3], type: graph.entity(ids[i3]).type, role: role2 };
+            graph = actionAddMember(relationId, member)(graph);
           }
-          context.uploader().save(context.changeset);
-        }
-      });
-      uiTooltip().destroyAny(buttonSection.selectAll(".save-button"));
-      if (uploadBlockerTooltipText) {
-        buttonSection.selectAll(".save-button").call(uiTooltip().title(() => uploadBlockerTooltipText).placement("top"));
+          return graph;
+        };
       }
-      var tagSection = body.selectAll(".tag-section.raw-tag-editor").data([0]);
-      tagSection = tagSection.enter().append("div").attr("class", "modal-section tag-section raw-tag-editor").merge(tagSection);
-      tagSection.call(
-        rawTagEditor.tags(Object.assign({}, context.changeset.tags)).render
-      );
-      var changesSection = body.selectAll(".commit-changes-section").data([0]);
-      changesSection = changesSection.enter().append("div").attr("class", "modal-section commit-changes-section").merge(changesSection);
-      changesSection.call(commitChanges.render);
-      function toggleRequestReview() {
-        var rr = requestReviewInput.property("checked");
-        updateChangeset({ review_requested: rr ? "yes" : void 0 });
-        tagSection.call(
-          rawTagEditor.tags(Object.assign({}, context.changeset.tags)).render
+      if (d2.relation) {
+        context.perform(
+          actionAddMembers(d2.relation.id, _entityIDs, role),
+          _t("operations.add_member.annotation", {
+            n: _entityIDs.length
+          })
         );
-      }
-    }
-    function getUploadBlockerMessage() {
-      var errors = context.validator().getIssuesBySeverity({ what: "edited", where: "all" }).error;
-      if (errors.length) {
-        return _t.append("commit.outstanding_errors_message", { count: errors.length });
+        context.validator().validate();
       } else {
-        var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
-        if (!hasChangesetComment) {
-          return _t.append("commit.comment_needed_message");
-        }
+        var relation = osmRelation();
+        context.perform(
+          actionAddEntity(relation),
+          actionAddMembers(relation.id, _entityIDs, role),
+          _t("operations.add.annotation.relation")
+        );
+        context.enter(modeSelect(context, [relation.id]).newFeature(true));
       }
-      return null;
     }
-    function changeTags(_2, changed, onInput) {
-      if (changed.hasOwnProperty("comment")) {
-        if (changed.comment === void 0) {
-          changed.comment = "";
-        }
-        if (!onInput) {
-          corePreferences("comment", changed.comment);
-          corePreferences("commentDate", Date.now());
-        }
-      }
-      if (changed.hasOwnProperty("source")) {
-        if (changed.source === void 0) {
-          corePreferences("source", null);
-        } else if (!onInput) {
-          corePreferences("source", changed.source);
-          corePreferences("commentDate", Date.now());
-        }
-      }
-      updateChangeset(changed, onInput);
-      if (_selection) {
-        _selection.call(render);
-      }
-    }
-    function findHashtags(tags, commentOnly) {
-      var detectedHashtags = commentHashtags();
-      if (detectedHashtags.length) {
-        corePreferences("hashtags", null);
-      }
-      if (!detectedHashtags.length || !commentOnly) {
-        detectedHashtags = detectedHashtags.concat(hashtagHashtags());
-      }
-      var allLowerCase = /* @__PURE__ */ new Set();
-      return detectedHashtags.filter(function(hashtag) {
-        var lowerCase = hashtag.toLowerCase();
-        if (!allLowerCase.has(lowerCase)) {
-          allLowerCase.add(lowerCase);
-          return true;
-        }
-        return false;
+    function downloadMembers(d3_event, d2) {
+      d3_event.preventDefault();
+      const button = select_default2(this);
+      button.classed("loading", true);
+      context.loadEntity(d2.relation.id, function() {
+        section.reRender();
       });
-      function commentHashtags() {
-        var matches = (tags.comment || "").replace(/http\S*/g, "").match(hashtagRegex);
-        return matches || [];
-      }
-      function hashtagHashtags() {
-        var matches = (tags.hashtags || "").split(/[,;\s]+/).map(function(s2) {
-          if (s2[0] !== "#") {
-            s2 = "#" + s2;
-          }
-          var matched = s2.match(hashtagRegex);
-          return matched && matched[0];
-        }).filter(Boolean);
-        return matches || [];
-      }
-    }
-    function isReviewRequested(tags) {
-      var rr = tags.review_requested;
-      if (rr === void 0)
-        return false;
-      rr = rr.trim().toLowerCase();
-      return !(rr === "" || rr === "no");
     }
-    function updateChangeset(changed, onInput) {
-      var tags = Object.assign({}, context.changeset.tags);
-      Object.keys(changed).forEach(function(k2) {
-        var v2 = changed[k2];
-        k2 = context.cleanTagKey(k2);
-        if (readOnlyTags.indexOf(k2) !== -1)
-          return;
-        if (v2 === void 0) {
-          delete tags[k2];
-        } else if (onInput) {
-          tags[k2] = v2;
-        } else {
-          tags[k2] = context.cleanTagValue(v2);
-        }
+    function deleteMembership(d3_event, d2) {
+      this.blur();
+      if (d2 === 0) return;
+      utilHighlightEntities([d2.relation.id], false, context);
+      var indexes = d2.members.map(function(member) {
+        return member.index;
       });
-      if (!onInput) {
-        var commentOnly = changed.hasOwnProperty("comment") && changed.comment !== "";
-        var arr = findHashtags(tags, commentOnly);
-        if (arr.length) {
-          tags.hashtags = context.cleanTagValue(arr.join(";"));
-          corePreferences("hashtags", tags.hashtags);
-        } else {
-          delete tags.hashtags;
-          corePreferences("hashtags", null);
-        }
+      context.perform(
+        actionDeleteMembers(d2.relation.id, indexes),
+        _t("operations.delete_member.annotation", {
+          n: _entityIDs.length
+        })
+      );
+      context.validator().validate();
+    }
+    function fetchNearbyRelations(q2, callback) {
+      var newRelation = {
+        relation: null,
+        value: _t("inspector.new_relation"),
+        display: _t.append("inspector.new_relation")
+      };
+      var entityID = _entityIDs[0];
+      var result = [];
+      var graph = context.graph();
+      function baseDisplayValue(entity) {
+        var matched = _mainPresetIndex.match(entity, graph);
+        var presetName = matched && matched.name() || _t("inspector.relation");
+        var entityName = utilDisplayName(entity) || "";
+        return presetName + " " + entityName;
       }
-      if (_userDetails2 && _userDetails2.changesets_count !== void 0) {
-        var changesetsCount = parseInt(_userDetails2.changesets_count, 10) + 1;
-        tags.changesets_count = String(changesetsCount);
-        if (changesetsCount <= 100) {
-          var s2;
-          s2 = corePreferences("walkthrough_completed");
-          if (s2) {
-            tags["ideditor:walkthrough_completed"] = s2;
-          }
-          s2 = corePreferences("walkthrough_progress");
-          if (s2) {
-            tags["ideditor:walkthrough_progress"] = s2;
-          }
-          s2 = corePreferences("walkthrough_started");
-          if (s2) {
-            tags["ideditor:walkthrough_started"] = s2;
-          }
-        }
-      } else {
-        delete tags.changesets_count;
+      function baseDisplayLabel(entity) {
+        var matched = _mainPresetIndex.match(entity, graph);
+        var presetName = matched && matched.name() || _t("inspector.relation");
+        var entityName = utilDisplayName(entity) || "";
+        return (selection2) => {
+          selection2.append("b").text(presetName + " ");
+          selection2.append("span").classed("has-colour", entity.tags.colour && isColourValid(entity.tags.colour)).style("border-color", entity.tags.colour).text(entityName);
+        };
       }
-      if (!(0, import_fast_deep_equal9.default)(context.changeset.tags, tags)) {
-        context.changeset = context.changeset.update({ tags });
+      var explicitRelation = q2 && context.hasEntity(q2.toLowerCase());
+      if (explicitRelation && explicitRelation.type === "relation" && explicitRelation.id !== entityID) {
+        result.push({
+          relation: explicitRelation,
+          value: baseDisplayValue(explicitRelation) + " " + explicitRelation.id,
+          display: baseDisplayLabel(explicitRelation)
+        });
+      } else {
+        context.history().intersects(context.map().extent()).forEach(function(entity) {
+          if (entity.type !== "relation" || entity.id === entityID) return;
+          var value = baseDisplayValue(entity);
+          if (q2 && (value + " " + entity.id).toLowerCase().indexOf(q2.toLowerCase()) === -1) return;
+          result.push({
+            relation: entity,
+            value,
+            display: baseDisplayLabel(entity)
+          });
+        });
+        result.sort(function(a2, b2) {
+          return osmRelation.creationOrder(a2.relation, b2.relation);
+        });
+        var dupeGroups = Object.values(utilArrayGroupBy(result, "value")).filter(function(v2) {
+          return v2.length > 1;
+        });
+        dupeGroups.forEach(function(group) {
+          group.forEach(function(obj) {
+            obj.value += " " + obj.relation.id;
+          });
+        });
       }
+      result.forEach(function(obj) {
+        obj.title = obj.value;
+      });
+      result.unshift(newRelation);
+      callback(result);
     }
-    commit.reset = function() {
-      context.changeset = null;
-    };
-    return utilRebind(commit, dispatch14, "on");
-  }
-
-  // modules/ui/confirm.js
-  function uiConfirm(selection2) {
-    var modalSelection = uiModal(selection2);
-    modalSelection.select(".modal").classed("modal-alert", true);
-    var section = modalSelection.select(".content");
-    section.append("div").attr("class", "modal-section header");
-    section.append("div").attr("class", "modal-section message-text");
-    var buttons = section.append("div").attr("class", "modal-section buttons cf");
-    modalSelection.okButton = function() {
-      buttons.append("button").attr("class", "button ok-button action").on("click.confirm", function() {
-        modalSelection.remove();
-      }).call(_t.append("confirm.okay")).node().focus();
-      return modalSelection;
-    };
-    return modalSelection;
-  }
-
-  // modules/ui/conflicts.js
-  function uiConflicts(context) {
-    var dispatch14 = dispatch_default("cancel", "save");
-    var keybinding = utilKeybinding("conflicts");
-    var _origChanges;
-    var _conflictList;
-    var _shownConflictIndex;
-    function keybindingOn() {
-      select_default2(document).call(keybinding.on("\u238B", cancel, true));
-    }
-    function keybindingOff() {
-      select_default2(document).call(keybinding.unbind);
-    }
-    function tryAgain() {
-      keybindingOff();
-      dispatch14.call("save");
-    }
-    function cancel() {
-      keybindingOff();
-      dispatch14.call("cancel");
-    }
-    function conflicts(selection2) {
-      keybindingOn();
-      var headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "fr").attr("title", _t("icons.close")).on("click", cancel).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("save.conflict.header"));
-      var bodyEnter = selection2.selectAll(".body").data([0]).enter().append("div").attr("class", "body fillL");
-      var conflictsHelpEnter = bodyEnter.append("div").attr("class", "conflicts-help").call(_t.append("save.conflict.help"));
-      var changeset = new osmChangeset();
-      delete changeset.id;
-      var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
-      var blob = new Blob([data], { type: "text/xml;charset=utf-8;" });
-      var fileName = "changes.osc";
-      var linkEnter = conflictsHelpEnter.selectAll(".download-changes").append("a").attr("class", "download-changes");
-      linkEnter.attr("href", window.URL.createObjectURL(blob)).attr("download", fileName);
-      linkEnter.call(svgIcon("#iD-icon-load", "inline")).append("span").call(_t.append("save.conflict.download_changes"));
-      bodyEnter.append("div").attr("class", "conflict-container fillL3").call(showConflict, 0);
-      bodyEnter.append("div").attr("class", "conflicts-done").attr("opacity", 0).style("display", "none").call(_t.append("save.conflict.done"));
-      var buttonsEnter = bodyEnter.append("div").attr("class", "buttons col12 joined conflicts-buttons");
-      buttonsEnter.append("button").attr("disabled", _conflictList.length > 1).attr("class", "action conflicts-button col6").call(_t.append("save.title")).on("click.try_again", tryAgain);
-      buttonsEnter.append("button").attr("class", "secondary-action conflicts-button col6").call(_t.append("confirm.cancel")).on("click.cancel", cancel);
-    }
-    function showConflict(selection2, index) {
-      index = utilWrap(index, _conflictList.length);
-      _shownConflictIndex = index;
-      var parent = select_default2(selection2.node().parentNode);
-      if (index === _conflictList.length - 1) {
-        window.setTimeout(function() {
-          parent.select(".conflicts-button").attr("disabled", null);
-          parent.select(".conflicts-done").transition().attr("opacity", 1).style("display", "block");
-        }, 250);
-      }
-      var conflict = selection2.selectAll(".conflict").data([_conflictList[index]]);
-      conflict.exit().remove();
-      var conflictEnter = conflict.enter().append("div").attr("class", "conflict");
-      conflictEnter.append("h4").attr("class", "conflict-count").call(_t.append("save.conflict.count", { num: index + 1, total: _conflictList.length }));
-      conflictEnter.append("a").attr("class", "conflict-description").attr("href", "#").text(function(d2) {
-        return d2.name;
-      }).on("click", function(d3_event, d2) {
-        d3_event.preventDefault();
-        zoomToEntity(d2.id);
+    function renderDisclosureContent(selection2) {
+      var memberships = getMemberships();
+      var list2 = selection2.selectAll(".member-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "member-list").merge(list2);
+      var items = list2.selectAll("li.member-row-normal").data(memberships, function(d2) {
+        return d2.hash;
       });
-      var details = conflictEnter.append("div").attr("class", "conflict-detail-container");
-      details.append("ul").attr("class", "conflict-detail-list").selectAll("li").data(function(d2) {
-        return d2.details || [];
-      }).enter().append("li").attr("class", "conflict-detail-item").html(function(d2) {
-        return d2;
+      items.exit().each(unbind).remove();
+      var itemsEnter = items.enter().append("li").attr("class", "member-row member-row-normal form-field");
+      itemsEnter.on("mouseover", function(d3_event, d2) {
+        utilHighlightEntities([d2.relation.id], true, context);
+      }).on("mouseout", function(d3_event, d2) {
+        utilHighlightEntities([d2.relation.id], false, context);
       });
-      details.append("div").attr("class", "conflict-choices").call(addChoices);
-      details.append("div").attr("class", "conflict-nav-buttons joined cf").selectAll("button").data(["previous", "next"]).enter().append("button").attr("class", "conflict-nav-button action col6").attr("disabled", function(d2, i3) {
-        return i3 === 0 && index === 0 || i3 === 1 && index === _conflictList.length - 1 || null;
-      }).on("click", function(d3_event, d2) {
-        d3_event.preventDefault();
-        var container = parent.selectAll(".conflict-container");
-        var sign2 = d2 === "previous" ? -1 : 1;
-        container.selectAll(".conflict").remove();
-        container.call(showConflict, index + sign2);
-      }).each(function(d2) {
-        _t.append("save.conflict." + d2)(select_default2(this));
+      var labelEnter = itemsEnter.append("label").attr("class", "field-label").attr("for", function(d2) {
+        return d2.domId;
       });
-    }
-    function addChoices(selection2) {
-      var choices = selection2.append("ul").attr("class", "layer-list").selectAll("li").data(function(d2) {
-        return d2.choices || [];
+      var labelLink = labelEnter.append("span").attr("class", "label-text").append("a").attr("href", "#").on("click", selectRelation);
+      labelLink.append("span").attr("class", "member-entity-type").text(function(d2) {
+        var matched = _mainPresetIndex.match(d2.relation, context.graph());
+        return matched && matched.name() || _t.html("inspector.relation");
       });
-      var choicesEnter = choices.enter().append("li").attr("class", "layer");
-      var labelEnter = choicesEnter.append("label");
-      labelEnter.append("input").attr("type", "radio").attr("name", function(d2) {
-        return d2.id;
-      }).on("change", function(d3_event, d2) {
-        var ul = this.parentNode.parentNode.parentNode;
-        ul.__data__.chosen = d2.id;
-        choose(d3_event, ul, d2);
+      labelLink.append("span").attr("class", "member-entity-name").classed("has-colour", (d2) => d2.relation.tags.colour && isColourValid(d2.relation.tags.colour)).style("border-color", (d2) => d2.relation.tags.colour).text(function(d2) {
+        return utilDisplayName(d2.relation);
       });
-      labelEnter.append("span").text(function(d2) {
-        return d2.text;
+      labelEnter.append("button").attr("class", "members-download").attr("title", _t("icons.download")).call(svgIcon("#iD-icon-load")).on("click", downloadMembers);
+      labelEnter.append("button").attr("class", "remove member-delete").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete")).on("click", deleteMembership);
+      labelEnter.append("button").attr("class", "member-zoom").attr("title", _t("icons.zoom_to")).call(svgIcon("#iD-icon-framed-dot", "monochrome")).on("click", zoomToRelation);
+      items = items.merge(itemsEnter);
+      items.selectAll("button.members-download").classed("hide", (d2) => {
+        const graph = context.graph();
+        return d2.relation.members.every((m2) => graph.hasEntity(m2.id));
       });
-      choicesEnter.merge(choices).each(function(d2) {
-        var ul = this.parentNode;
-        if (ul.__data__.chosen === d2.id) {
-          choose(null, ul, d2);
-        }
+      var wrapEnter = itemsEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
+      wrapEnter.append("input").attr("class", "member-role").attr("id", function(d2) {
+        return d2.domId;
+      }).property("type", "text").property("value", function(d2) {
+        return typeof d2.role === "string" ? d2.role : "";
+      }).attr("title", function(d2) {
+        return Array.isArray(d2.role) ? d2.role.filter(Boolean).join("\n") : d2.role;
+      }).attr("placeholder", function(d2) {
+        return Array.isArray(d2.role) ? _t("inspector.multiple_roles") : _t("inspector.role");
+      }).classed("mixed", function(d2) {
+        return Array.isArray(d2.role);
+      }).call(utilNoAuto).on("blur", changeRole).on("change", changeRole);
+      if (taginfo) {
+        wrapEnter.each(bindTypeahead);
+      }
+      var newMembership = list2.selectAll(".member-row-new").data(_showBlank ? [0] : []);
+      newMembership.exit().remove();
+      var newMembershipEnter = newMembership.enter().append("li").attr("class", "member-row member-row-new form-field");
+      var newLabelEnter = newMembershipEnter.append("label").attr("class", "field-label");
+      newLabelEnter.append("input").attr("placeholder", _t("inspector.choose_relation")).attr("type", "text").attr("class", "member-entity-input").call(utilNoAuto);
+      newLabelEnter.append("button").attr("class", "remove member-delete").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete")).on("click", function() {
+        list2.selectAll(".member-row-new").remove();
       });
-    }
-    function choose(d3_event, ul, datum2) {
-      if (d3_event)
-        d3_event.preventDefault();
-      select_default2(ul).selectAll("li").classed("active", function(d2) {
-        return d2 === datum2;
-      }).selectAll("input").property("checked", function(d2) {
-        return d2 === datum2;
+      var newWrapEnter = newMembershipEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
+      newWrapEnter.append("input").attr("class", "member-role").property("type", "text").attr("placeholder", _t("inspector.role")).call(utilNoAuto);
+      newMembership = newMembership.merge(newMembershipEnter);
+      newMembership.selectAll(".member-entity-input").on("blur", cancelEntity).call(
+        nearbyCombo.on("accept", acceptEntity).on("cancel", cancelEntity)
+      );
+      var addRow = selection2.selectAll(".add-row").data([0]);
+      var addRowEnter = addRow.enter().append("div").attr("class", "add-row");
+      var addRelationButton = addRowEnter.append("button").attr("class", "add-relation").attr("aria-label", _t("inspector.add_to_relation"));
+      addRelationButton.call(svgIcon("#iD-icon-plus", "light"));
+      addRelationButton.call(uiTooltip().title(() => _t.append("inspector.add_to_relation")).placement(_mainLocalizer.textDirection() === "ltr" ? "right" : "left"));
+      addRowEnter.append("div").attr("class", "space-value");
+      addRowEnter.append("div").attr("class", "space-buttons");
+      addRow = addRow.merge(addRowEnter);
+      addRow.select(".add-relation").on("click", function() {
+        _showBlank = true;
+        section.reRender();
+        list2.selectAll(".member-entity-input").node().focus();
       });
-      var extent = geoExtent();
-      var entity;
-      entity = context.graph().hasEntity(datum2.id);
-      if (entity)
-        extent._extend(entity.extent(context.graph()));
-      datum2.action();
-      entity = context.graph().hasEntity(datum2.id);
-      if (entity)
-        extent._extend(entity.extent(context.graph()));
-      zoomToEntity(datum2.id, extent);
-    }
-    function zoomToEntity(id2, extent) {
-      context.surface().selectAll(".hover").classed("hover", false);
-      var entity = context.graph().hasEntity(id2);
-      if (entity) {
-        if (extent) {
-          context.map().trimmedExtent(extent);
-        } else {
-          context.map().zoomToEase(entity);
+      function acceptEntity(d2) {
+        if (!d2) {
+          cancelEntity();
+          return;
         }
-        context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed("hover", true);
+        if (d2.relation) utilHighlightEntities([d2.relation.id], false, context);
+        var role = context.cleanRelationRole(list2.selectAll(".member-row-new .member-role").property("value"));
+        addMembership(d2, role);
       }
-    }
-    conflicts.conflictList = function(_2) {
-      if (!arguments.length)
-        return _conflictList;
-      _conflictList = _2;
-      return conflicts;
-    };
-    conflicts.origChanges = function(_2) {
-      if (!arguments.length)
-        return _origChanges;
-      _origChanges = _2;
-      return conflicts;
-    };
-    conflicts.shownEntityIds = function() {
-      if (_conflictList && typeof _shownConflictIndex === "number") {
-        return [_conflictList[_shownConflictIndex].id];
+      function cancelEntity() {
+        var input = newMembership.selectAll(".member-entity-input");
+        input.property("value", "");
+        context.surface().selectAll(".highlighted").classed("highlighted", false);
       }
-      return [];
+      function bindTypeahead(d2) {
+        var row = select_default2(this);
+        var role = row.selectAll("input.member-role");
+        var origValue = role.property("value");
+        function sort(value, data) {
+          var sameletter = [];
+          var other = [];
+          for (var i3 = 0; i3 < data.length; i3++) {
+            if (data[i3].value.substring(0, value.length) === value) {
+              sameletter.push(data[i3]);
+            } else {
+              other.push(data[i3]);
+            }
+          }
+          return sameletter.concat(other);
+        }
+        role.call(
+          uiCombobox(context, "member-role").fetcher(function(role2, callback) {
+            var rtype = d2.relation.tags.type;
+            taginfo.roles({
+              debounce: true,
+              rtype: rtype || "",
+              geometry: context.graph().geometry(_entityIDs[0]),
+              query: role2
+            }, function(err, data) {
+              if (!err) callback(sort(role2, data));
+            });
+          }).on("cancel", function() {
+            role.property("value", origValue);
+          })
+        );
+      }
+      function unbind() {
+        var row = select_default2(this);
+        row.selectAll("input.member-role").call(uiCombobox.off, context);
+      }
+    }
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      _showBlank = false;
+      return section;
     };
-    return utilRebind(conflicts, dispatch14, "on");
+    return section;
   }
 
-  // modules/ui/entity_editor.js
-  var import_fast_deep_equal10 = __toESM(require_fast_deep_equal());
-
-  // modules/ui/sections/entity_issues.js
-  function uiSectionEntityIssues(context) {
-    var preference = corePreferences("entity-issues.reference.expanded");
-    var _expanded = preference === null ? true : preference === "true";
-    var _entityIDs = [];
-    var _issues = [];
-    var _activeIssueID;
-    var section = uiSection("entity-issues", context).shouldDisplay(function() {
-      return _issues.length > 0;
+  // modules/ui/sections/selection_list.js
+  function uiSectionSelectionList(context) {
+    var _selectedIDs = [];
+    var section = uiSection("selected-features", context).shouldDisplay(function() {
+      return _selectedIDs.length > 1;
     }).label(function() {
-      return _t.append("inspector.title_count", { title: _t("issues.list_title"), count: _issues.length });
+      return _t.append("inspector.title_count", { title: _t("inspector.features"), count: _selectedIDs.length });
     }).disclosureContent(renderDisclosureContent);
-    context.validator().on("validated.entity_issues", function() {
-      reloadIssues();
-      section.reRender();
-    }).on("focusedIssue.entity_issues", function(issue) {
-      makeActiveIssue(issue.id);
+    context.history().on("change.selectionList", function(difference2) {
+      if (difference2) {
+        section.reRender();
+      }
     });
-    function reloadIssues() {
-      _issues = context.validator().getSharedEntityIssues(_entityIDs, { includeDisabledRules: true });
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _selectedIDs;
+      _selectedIDs = val;
+      return section;
+    };
+    function selectEntity(d3_event, entity) {
+      context.enter(modeSelect(context, [entity.id]));
     }
-    function makeActiveIssue(issueID) {
-      _activeIssueID = issueID;
-      section.selection().selectAll(".issue-container").classed("active", function(d2) {
-        return d2.id === _activeIssueID;
-      });
+    function deselectEntity(d3_event, entity) {
+      var selectedIDs = _selectedIDs.slice();
+      var index = selectedIDs.indexOf(entity.id);
+      if (index > -1) {
+        selectedIDs.splice(index, 1);
+        context.enter(modeSelect(context, selectedIDs));
+      }
     }
     function renderDisclosureContent(selection2) {
-      selection2.classed("grouped-items-area", true);
-      _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
-      var containers = selection2.selectAll(".issue-container").data(_issues, function(d2) {
-        return d2.key;
-      });
-      containers.exit().remove();
-      var containersEnter = containers.enter().append("div").attr("class", "issue-container");
-      var itemsEnter = containersEnter.append("div").attr("class", function(d2) {
-        return "issue severity-" + d2.severity;
-      }).on("mouseover.highlight", function(d3_event, d2) {
-        var ids = d2.entityIds.filter(function(e3) {
-          return _entityIDs.indexOf(e3) === -1;
+      var list2 = selection2.selectAll(".feature-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "feature-list").merge(list2);
+      var entities = _selectedIDs.map(function(id2) {
+        return context.hasEntity(id2);
+      }).filter(Boolean);
+      var items = list2.selectAll(".feature-list-item").data(entities, osmEntity.key);
+      items.exit().remove();
+      var enter = items.enter().append("li").attr("class", "feature-list-item").each(function(d2) {
+        select_default2(this).on("mouseover", function() {
+          utilHighlightEntities([d2.id], true, context);
+        }).on("mouseout", function() {
+          utilHighlightEntities([d2.id], false, context);
         });
-        utilHighlightEntities(ids, true, context);
-      }).on("mouseout.highlight", function(d3_event, d2) {
-        var ids = d2.entityIds.filter(function(e3) {
-          return _entityIDs.indexOf(e3) === -1;
-        });
-        utilHighlightEntities(ids, false, context);
-      });
-      var labelsEnter = itemsEnter.append("div").attr("class", "issue-label");
-      var textEnter = labelsEnter.append("button").attr("class", "issue-text").on("click", function(d3_event, d2) {
-        makeActiveIssue(d2.id);
-        var extent = d2.extent(context.graph());
-        if (extent) {
-          var setZoom = Math.max(context.map().zoom(), 19);
-          context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
-        }
-      });
-      textEnter.each(function(d2) {
-        var iconName = "#iD-icon-" + (d2.severity === "warning" ? "alert" : "error");
-        select_default2(this).call(svgIcon(iconName, "issue-icon"));
-      });
-      textEnter.append("span").attr("class", "issue-message");
-      var infoButton = labelsEnter.append("button").attr("class", "issue-info-button").attr("title", _t("icons.information")).call(svgIcon("#iD-icon-inspect"));
-      infoButton.on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        this.blur();
-        var container = select_default2(this.parentNode.parentNode.parentNode);
-        var info = container.selectAll(".issue-info");
-        var isExpanded = info.classed("expanded");
-        _expanded = !isExpanded;
-        corePreferences("entity-issues.reference.expanded", _expanded);
-        if (isExpanded) {
-          info.transition().duration(200).style("max-height", "0px").style("opacity", "0").on("end", function() {
-            info.classed("expanded", false);
-          });
-        } else {
-          info.classed("expanded", true).transition().duration(200).style("max-height", "200px").style("opacity", "1").on("end", function() {
-            info.style("max-height", null);
-          });
-        }
-      });
-      itemsEnter.append("ul").attr("class", "issue-fix-list");
-      containersEnter.append("div").attr("class", "issue-info" + (_expanded ? " expanded" : "")).style("max-height", _expanded ? null : "0").style("opacity", _expanded ? "1" : "0").each(function(d2) {
-        if (typeof d2.reference === "function") {
-          select_default2(this).call(d2.reference);
-        } else {
-          select_default2(this).call(_t.append("inspector.no_documentation_key"));
-        }
-      });
-      containers = containers.merge(containersEnter).classed("active", function(d2) {
-        return d2.id === _activeIssueID;
-      });
-      containers.selectAll(".issue-message").text("").each(function(d2) {
-        return d2.message(context)(select_default2(this));
-      });
-      var fixLists = containers.selectAll(".issue-fix-list");
-      var fixes = fixLists.selectAll(".issue-fix-item").data(function(d2) {
-        return d2.fixes ? d2.fixes(context) : [];
-      }, function(fix) {
-        return fix.id;
-      });
-      fixes.exit().remove();
-      var fixesEnter = fixes.enter().append("li").attr("class", "issue-fix-item");
-      var buttons = fixesEnter.append("button").on("click", function(d3_event, d2) {
-        if (select_default2(this).attr("disabled") || !d2.onClick)
-          return;
-        if (d2.issue.dateLastRanFix && /* @__PURE__ */ new Date() - d2.issue.dateLastRanFix < 1e3)
-          return;
-        d2.issue.dateLastRanFix = /* @__PURE__ */ new Date();
-        utilHighlightEntities(d2.issue.entityIds.concat(d2.entityIds), false, context);
-        new Promise(function(resolve, reject) {
-          d2.onClick(context, resolve, reject);
-          if (d2.onClick.length <= 1) {
-            resolve();
-          }
-        }).then(function() {
-          context.validator().validate();
-        });
-      }).on("mouseover.highlight", function(d3_event, d2) {
-        utilHighlightEntities(d2.entityIds, true, context);
-      }).on("mouseout.highlight", function(d3_event, d2) {
-        utilHighlightEntities(d2.entityIds, false, context);
       });
-      buttons.each(function(d2) {
-        var iconName = d2.icon || "iD-icon-wrench";
-        if (iconName.startsWith("maki")) {
-          iconName += "-15";
-        }
-        select_default2(this).call(svgIcon("#" + iconName, "fix-icon"));
+      var label = enter.append("button").attr("class", "label").on("click", selectEntity);
+      label.append("span").attr("class", "entity-geom-icon").call(svgIcon("", "pre-text"));
+      label.append("span").attr("class", "entity-type");
+      label.append("span").attr("class", "entity-name");
+      enter.append("button").attr("class", "close").attr("title", _t("icons.deselect")).on("click", deselectEntity).call(svgIcon("#iD-icon-close"));
+      items = items.merge(enter);
+      items.selectAll(".entity-geom-icon use").attr("href", function() {
+        var entity = this.parentNode.parentNode.__data__;
+        return "#iD-icon-" + entity.geometry(context.graph());
       });
-      buttons.append("span").attr("class", "fix-message").each(function(d2) {
-        return d2.title(select_default2(this));
+      items.selectAll(".entity-type").text(function(entity) {
+        return _mainPresetIndex.match(entity, context.graph()).name();
       });
-      fixesEnter.merge(fixes).selectAll("button").classed("actionable", function(d2) {
-        return d2.onClick;
-      }).attr("disabled", function(d2) {
-        return d2.onClick ? null : "true";
-      }).attr("title", function(d2) {
-        if (d2.disabledReason) {
-          return d2.disabledReason;
-        }
-        return null;
+      items.selectAll(".entity-name").text(function(d2) {
+        var entity = context.entity(d2.id);
+        return utilDisplayName(entity);
       });
     }
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
-        _entityIDs = val;
-        _activeIssueID = null;
-        reloadIssues();
-      }
-      return section;
-    };
     return section;
   }
 
-  // modules/ui/preset_icon.js
-  function uiPresetIcon() {
-    let _preset;
-    let _geometry;
-    function presetIcon(selection2) {
-      selection2.each(render);
-    }
-    function getIcon(p2, geom) {
-      if (p2.isFallback && p2.isFallback())
-        return geom === "vertex" ? "" : "iD-icon-" + p2.id;
-      if (p2.icon)
-        return p2.icon;
-      if (geom === "line")
-        return "iD-other-line";
-      if (geom === "vertex")
-        return "temaki-vertex";
-      return "maki-marker-stroked";
-    }
-    function renderPointBorder(container, drawPoint) {
-      let pointBorder = container.selectAll(".preset-icon-point-border").data(drawPoint ? [0] : []);
-      pointBorder.exit().remove();
-      let pointBorderEnter = pointBorder.enter();
-      const w2 = 40;
-      const h2 = 40;
-      pointBorderEnter.append("svg").attr("class", "preset-icon-fill preset-icon-point-border").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2)).append("path").attr("transform", "translate(11.5, 8)").attr("d", "M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z");
-      pointBorder = pointBorderEnter.merge(pointBorder);
-    }
-    function renderCategoryBorder(container, category) {
-      let categoryBorder = container.selectAll(".preset-icon-category-border").data(category ? [0] : []);
-      categoryBorder.exit().remove();
-      let categoryBorderEnter = categoryBorder.enter();
-      const d2 = 60;
-      let svgEnter = categoryBorderEnter.append("svg").attr("class", "preset-icon-fill preset-icon-category-border").attr("width", d2).attr("height", d2).attr("viewBox", "0 0 ".concat(d2, " ").concat(d2));
-      svgEnter.append("path").attr("class", "area").attr("d", "M9.5,7.5 L25.5,7.5 L28.5,12.5 L49.5,12.5 C51.709139,12.5 53.5,14.290861 53.5,16.5 L53.5,43.5 C53.5,45.709139 51.709139,47.5 49.5,47.5 L10.5,47.5 C8.290861,47.5 6.5,45.709139 6.5,43.5 L6.5,12.5 L9.5,7.5 Z");
-      categoryBorder = categoryBorderEnter.merge(categoryBorder);
-      if (category) {
-        categoryBorder.selectAll("path").attr("class", "area ".concat(category.id));
-      }
-    }
-    function renderCircleFill(container, drawVertex) {
-      let vertexFill = container.selectAll(".preset-icon-fill-vertex").data(drawVertex ? [0] : []);
-      vertexFill.exit().remove();
-      let vertexFillEnter = vertexFill.enter();
-      const w2 = 60;
-      const h2 = 60;
-      const d2 = 40;
-      vertexFillEnter.append("svg").attr("class", "preset-icon-fill preset-icon-fill-vertex").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2)).append("circle").attr("cx", w2 / 2).attr("cy", h2 / 2).attr("r", d2 / 2);
-      vertexFill = vertexFillEnter.merge(vertexFill);
-    }
-    function renderSquareFill(container, drawArea, tagClasses) {
-      let fill = container.selectAll(".preset-icon-fill-area").data(drawArea ? [0] : []);
-      fill.exit().remove();
-      let fillEnter = fill.enter();
-      const d2 = 60;
-      const w2 = d2;
-      const h2 = d2;
-      const l2 = d2 * 2 / 3;
-      const c1 = (w2 - l2) / 2;
-      const c2 = c1 + l2;
-      fillEnter = fillEnter.append("svg").attr("class", "preset-icon-fill preset-icon-fill-area").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
-      ["fill", "stroke"].forEach((klass) => {
-        fillEnter.append("path").attr("d", "M".concat(c1, " ").concat(c1, " L").concat(c1, " ").concat(c2, " L").concat(c2, " ").concat(c2, " L").concat(c2, " ").concat(c1, " Z")).attr("class", "area ".concat(klass));
-      });
-      const rVertex = 2.5;
-      [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach((point2) => {
-        fillEnter.append("circle").attr("class", "vertex").attr("cx", point2[0]).attr("cy", point2[1]).attr("r", rVertex);
-      });
-      const rMidpoint = 1.25;
-      [[c1, w2 / 2], [c2, w2 / 2], [h2 / 2, c1], [h2 / 2, c2]].forEach((point2) => {
-        fillEnter.append("circle").attr("class", "midpoint").attr("cx", point2[0]).attr("cy", point2[1]).attr("r", rMidpoint);
-      });
-      fill = fillEnter.merge(fill);
-      fill.selectAll("path.stroke").attr("class", "area stroke ".concat(tagClasses));
-      fill.selectAll("path.fill").attr("class", "area fill ".concat(tagClasses));
-    }
-    function renderLine(container, drawLine, tagClasses) {
-      let line = container.selectAll(".preset-icon-line").data(drawLine ? [0] : []);
-      line.exit().remove();
-      let lineEnter = line.enter();
-      const d2 = 60;
-      const w2 = d2;
-      const h2 = d2;
-      const y2 = Math.round(d2 * 0.72);
-      const l2 = Math.round(d2 * 0.6);
-      const r2 = 2.5;
-      const x12 = (w2 - l2) / 2;
-      const x2 = x12 + l2;
-      lineEnter = lineEnter.append("svg").attr("class", "preset-icon-line").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
-      ["casing", "stroke"].forEach((klass) => {
-        lineEnter.append("path").attr("d", "M".concat(x12, " ").concat(y2, " L").concat(x2, " ").concat(y2)).attr("class", "line ".concat(klass));
-      });
-      [[x12 - 1, y2], [x2 + 1, y2]].forEach((point2) => {
-        lineEnter.append("circle").attr("class", "vertex").attr("cx", point2[0]).attr("cy", point2[1]).attr("r", r2);
-      });
-      line = lineEnter.merge(line);
-      line.selectAll("path.stroke").attr("class", "line stroke ".concat(tagClasses));
-      line.selectAll("path.casing").attr("class", "line casing ".concat(tagClasses));
-    }
-    function renderRoute(container, drawRoute, p2) {
-      let route = container.selectAll(".preset-icon-route").data(drawRoute ? [0] : []);
-      route.exit().remove();
-      let routeEnter = route.enter();
-      const d2 = 60;
-      const w2 = d2;
-      const h2 = d2;
-      const y12 = Math.round(d2 * 0.8);
-      const y2 = Math.round(d2 * 0.68);
-      const l2 = Math.round(d2 * 0.6);
-      const r2 = 2;
-      const x12 = (w2 - l2) / 2;
-      const x2 = x12 + l2 / 3;
-      const x3 = x2 + l2 / 3;
-      const x4 = x3 + l2 / 3;
-      routeEnter = routeEnter.append("svg").attr("class", "preset-icon-route").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
-      ["casing", "stroke"].forEach((klass) => {
-        routeEnter.append("path").attr("d", "M".concat(x12, " ").concat(y12, " L").concat(x2, " ").concat(y2)).attr("class", "segment0 line ".concat(klass));
-        routeEnter.append("path").attr("d", "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y12)).attr("class", "segment1 line ".concat(klass));
-        routeEnter.append("path").attr("d", "M".concat(x3, " ").concat(y12, " L").concat(x4, " ").concat(y2)).attr("class", "segment2 line ".concat(klass));
+  // modules/ui/entity_editor.js
+  function uiEntityEditor(context) {
+    var dispatch14 = dispatch_default("choose");
+    var _state = "select";
+    var _coalesceChanges = false;
+    var _modified = false;
+    var _base;
+    var _entityIDs;
+    var _activePresets = [];
+    var _newFeature;
+    var _sections;
+    function entityEditor(selection2) {
+      var combinedTags = utilCombinedTags(_entityIDs, context.graph());
+      var header = selection2.selectAll(".header").data([0]);
+      var headerEnter = header.enter().append("div").attr("class", "header fillL");
+      var direction = _mainLocalizer.textDirection() === "rtl" ? "forward" : "backward";
+      headerEnter.append("button").attr("class", "preset-reset preset-choose").attr("title", _t("inspector.back_tooltip")).call(svgIcon("#iD-icon-".concat(direction)));
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
+        context.enter(modeBrowse(context));
+      }).call(svgIcon(_modified ? "#iD-icon-apply" : "#iD-icon-close"));
+      headerEnter.append("h2");
+      header = header.merge(headerEnter);
+      header.selectAll("h2").text("").call(_entityIDs.length === 1 ? _t.append("inspector.edit") : _t.append("inspector.edit_features"));
+      header.selectAll(".preset-reset").on("click", function() {
+        dispatch14.call("choose", this, _activePresets);
       });
-      [[x12, y12], [x2, y2], [x3, y12], [x4, y2]].forEach((point2) => {
-        routeEnter.append("circle").attr("class", "vertex").attr("cx", point2[0]).attr("cy", point2[1]).attr("r", r2);
+      var body = selection2.selectAll(".inspector-body").data([0]);
+      var bodyEnter = body.enter().append("div").attr("class", "entity-editor inspector-body sep-top");
+      body = body.merge(bodyEnter);
+      if (!_sections) {
+        _sections = [
+          uiSectionSelectionList(context),
+          uiSectionFeatureType(context).on("choose", function(presets) {
+            dispatch14.call("choose", this, presets);
+          }),
+          uiSectionEntityIssues(context),
+          uiSectionPresetFields(context).on("change", changeTags).on("revert", revertTags),
+          uiSectionRawTagEditor("raw-tag-editor", context).on("change", changeTags),
+          uiSectionRawMemberEditor(context),
+          uiSectionRawMembershipEditor(context)
+        ];
+      }
+      _sections.forEach(function(section) {
+        if (section.entityIDs) {
+          section.entityIDs(_entityIDs);
+        }
+        if (section.presets) {
+          section.presets(_activePresets);
+        }
+        if (section.tags) {
+          section.tags(combinedTags);
+        }
+        if (section.state) {
+          section.state(_state);
+        }
+        body.call(section.render);
       });
-      route = routeEnter.merge(route);
-      if (drawRoute) {
-        let routeType = p2.tags.type === "waterway" ? "waterway" : p2.tags.route;
-        const segmentPresetIDs = routeSegments[routeType];
-        for (let i3 in segmentPresetIDs) {
-          const segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i3]);
-          const segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, "");
-          route.selectAll("path.stroke.segment".concat(i3)).attr("class", "segment".concat(i3, " line stroke ").concat(segmentTagClasses));
-          route.selectAll("path.casing.segment".concat(i3)).attr("class", "segment".concat(i3, " line casing ").concat(segmentTagClasses));
+      context.history().on("change.entity-editor", historyChanged);
+      function historyChanged(difference2) {
+        if (selection2.selectAll(".entity-editor").empty()) return;
+        if (_state === "hide") return;
+        var significant = !difference2 || difference2.didChange.properties || difference2.didChange.addition || difference2.didChange.deletion;
+        if (!significant) return;
+        _entityIDs = _entityIDs.filter(context.hasEntity);
+        if (!_entityIDs.length) return;
+        var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
+        loadActivePresets();
+        var graph = context.graph();
+        entityEditor.modified(_base !== graph);
+        entityEditor(selection2);
+        if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
+          context.container().selectAll(".entity-editor button.preset-reset .label").style("background-color", "#fff").transition().duration(750).style("background-color", null);
         }
       }
     }
-    function renderSvgIcon(container, picon, geom, isFramed, category, tagClasses) {
-      const isMaki = picon && /^maki-/.test(picon);
-      const isTemaki = picon && /^temaki-/.test(picon);
-      const isFa = picon && /^fa[srb]-/.test(picon);
-      const isR\u00F6ntgen = picon && /^roentgen-/.test(picon);
-      const isiDIcon = picon && !(isMaki || isTemaki || isFa || isR\u00F6ntgen);
-      let icon2 = container.selectAll(".preset-icon").data(picon ? [0] : []);
-      icon2.exit().remove();
-      icon2 = icon2.enter().append("div").attr("class", "preset-icon").call(svgIcon("")).merge(icon2);
-      icon2.attr("class", "preset-icon " + (geom ? geom + "-geom" : "")).classed("category", category).classed("framed", isFramed).classed("preset-icon-iD", isiDIcon);
-      icon2.selectAll("svg").attr("class", "icon " + picon + " " + (!isiDIcon && geom !== "line" ? "" : tagClasses));
-      icon2.selectAll("use").attr("href", "#" + picon);
-    }
-    function renderImageIcon(container, imageURL) {
-      let imageIcon = container.selectAll("img.image-icon").data(imageURL ? [0] : []);
-      imageIcon.exit().remove();
-      imageIcon = imageIcon.enter().append("img").attr("class", "image-icon").on("load", () => container.classed("showing-img", true)).on("error", () => container.classed("showing-img", false)).merge(imageIcon);
-      imageIcon.attr("src", imageURL);
+    function changeTags(entityIDs, changed, onInput) {
+      var actions = [];
+      for (var i3 in entityIDs) {
+        var entityID = entityIDs[i3];
+        var entity = context.entity(entityID);
+        var tags = Object.assign({}, entity.tags);
+        if (typeof changed === "function") {
+          tags = changed(tags);
+        } else {
+          for (var k2 in changed) {
+            if (!k2) continue;
+            var v2 = changed[k2];
+            if (typeof v2 === "object") {
+              tags[k2] = tags[v2.oldKey];
+            } else if (v2 !== void 0 || tags.hasOwnProperty(k2)) {
+              tags[k2] = v2;
+            }
+          }
+        }
+        if (!onInput) {
+          tags = utilCleanTags(tags);
+        }
+        if (!(0, import_fast_deep_equal9.default)(entity.tags, tags)) {
+          actions.push(actionChangeTags(entityID, tags));
+        }
+      }
+      if (actions.length) {
+        var combinedAction = function(graph) {
+          actions.forEach(function(action) {
+            graph = action(graph);
+          });
+          return graph;
+        };
+        var annotation = _t("operations.change_tags.annotation");
+        if (_coalesceChanges) {
+          context.overwrite(combinedAction, annotation);
+        } else {
+          context.perform(combinedAction, annotation);
+          _coalesceChanges = !!onInput;
+        }
+      }
+      if (!onInput) {
+        context.validator().validate();
+      }
     }
-    const routeSegments = {
-      bicycle: ["highway/cycleway", "highway/cycleway", "highway/cycleway"],
-      bus: ["highway/unclassified", "highway/secondary", "highway/primary"],
-      trolleybus: ["highway/unclassified", "highway/secondary", "highway/primary"],
-      detour: ["highway/tertiary", "highway/residential", "highway/unclassified"],
-      ferry: ["route/ferry", "route/ferry", "route/ferry"],
-      foot: ["highway/footway", "highway/footway", "highway/footway"],
-      hiking: ["highway/path", "highway/path", "highway/path"],
-      horse: ["highway/bridleway", "highway/bridleway", "highway/bridleway"],
-      light_rail: ["railway/light_rail", "railway/light_rail", "railway/light_rail"],
-      monorail: ["railway/monorail", "railway/monorail", "railway/monorail"],
-      mtb: ["highway/path", "highway/track", "highway/bridleway"],
-      pipeline: ["man_made/pipeline", "man_made/pipeline", "man_made/pipeline"],
-      piste: ["piste/downhill", "piste/hike", "piste/nordic"],
-      power: ["power/line", "power/line", "power/line"],
-      road: ["highway/secondary", "highway/primary", "highway/trunk"],
-      subway: ["railway/subway", "railway/subway", "railway/subway"],
-      train: ["railway/rail", "railway/rail", "railway/rail"],
-      tram: ["railway/tram", "railway/tram", "railway/tram"],
-      railway: ["railway/rail", "railway/rail", "railway/rail"],
-      waterway: ["waterway/stream", "waterway/stream", "waterway/stream"]
-    };
-    function render() {
-      let p2 = _preset.apply(this, arguments);
-      let geom = _geometry ? _geometry.apply(this, arguments) : null;
-      if (geom === "relation" && p2.tags && (p2.tags.type === "route" && p2.tags.route && routeSegments[p2.tags.route] || p2.tags.type === "waterway")) {
-        geom = "route";
+    function revertTags(keys2) {
+      var actions = [];
+      for (var i3 in _entityIDs) {
+        var entityID = _entityIDs[i3];
+        var original = context.graph().base().entities[entityID];
+        var changed = {};
+        for (var j2 in keys2) {
+          var key = keys2[j2];
+          changed[key] = original ? original.tags[key] : void 0;
+        }
+        var entity = context.entity(entityID);
+        var tags = Object.assign({}, entity.tags);
+        for (var k2 in changed) {
+          if (!k2) continue;
+          var v2 = changed[k2];
+          if (v2 !== void 0 || tags.hasOwnProperty(k2)) {
+            tags[k2] = v2;
+          }
+        }
+        tags = utilCleanTags(tags);
+        if (!(0, import_fast_deep_equal9.default)(entity.tags, tags)) {
+          actions.push(actionChangeTags(entityID, tags));
+        }
       }
-      const showThirdPartyIcons = corePreferences("preferences.privacy.thirdpartyicons") || "true";
-      const isFallback = p2.isFallback && p2.isFallback();
-      const imageURL = showThirdPartyIcons === "true" && p2.imageURL;
-      const picon = getIcon(p2, geom);
-      const isCategory = !p2.setTags;
-      const drawPoint = false;
-      const drawVertex = picon !== null && geom === "vertex";
-      const drawLine = picon && geom === "line" && !isFallback && !isCategory;
-      const drawArea = picon && geom === "area" && !isFallback && !isCategory;
-      const drawRoute = picon && geom === "route";
-      const isFramed = drawVertex || drawArea || drawLine || drawRoute || isCategory;
-      let tags = !isCategory ? p2.setTags({}, geom) : {};
-      for (let k2 in tags) {
-        if (tags[k2] === "*") {
-          tags[k2] = "yes";
+      if (actions.length) {
+        var combinedAction = function(graph) {
+          actions.forEach(function(action) {
+            graph = action(graph);
+          });
+          return graph;
+        };
+        var annotation = _t("operations.change_tags.annotation");
+        if (_coalesceChanges) {
+          context.overwrite(combinedAction, annotation);
+        } else {
+          context.perform(combinedAction, annotation);
+          _coalesceChanges = false;
         }
       }
-      let tagClasses = svgTagClasses().getClassesString(tags, "");
-      let selection2 = select_default2(this);
-      let container = selection2.selectAll(".preset-icon-container").data([0]);
-      container = container.enter().append("div").attr("class", "preset-icon-container").merge(container);
-      container.classed("showing-img", !!imageURL).classed("fallback", isFallback);
-      renderCategoryBorder(container, isCategory && p2);
-      renderPointBorder(container, drawPoint);
-      renderCircleFill(container, drawVertex);
-      renderSquareFill(container, drawArea, tagClasses);
-      renderLine(container, drawLine, tagClasses);
-      renderRoute(container, drawRoute, p2);
-      renderSvgIcon(container, picon, geom, isFramed, isCategory, tagClasses);
-      renderImageIcon(container, imageURL);
+      context.validator().validate();
     }
-    presetIcon.preset = function(val) {
-      if (!arguments.length)
-        return _preset;
-      _preset = utilFunctor(val);
-      return presetIcon;
+    entityEditor.modified = function(val) {
+      if (!arguments.length) return _modified;
+      _modified = val;
+      return entityEditor;
     };
-    presetIcon.geometry = function(val) {
-      if (!arguments.length)
-        return _geometry;
-      _geometry = utilFunctor(val);
-      return presetIcon;
+    entityEditor.state = function(val) {
+      if (!arguments.length) return _state;
+      _state = val;
+      return entityEditor;
     };
-    return presetIcon;
-  }
-
-  // modules/ui/sections/feature_type.js
-  function uiSectionFeatureType(context) {
-    var dispatch14 = dispatch_default("choose");
-    var _entityIDs = [];
-    var _presets = [];
-    var _tagReference;
-    var section = uiSection("feature-type", context).label(() => _t.append("inspector.feature_type")).disclosureContent(renderDisclosureContent);
-    function renderDisclosureContent(selection2) {
-      selection2.classed("preset-list-item", true);
-      selection2.classed("mixed-types", _presets.length > 1);
-      var presetButtonWrap = selection2.selectAll(".preset-list-button-wrap").data([0]).enter().append("div").attr("class", "preset-list-button-wrap");
-      var presetButton = presetButtonWrap.append("button").attr("class", "preset-list-button preset-reset").call(
-        uiTooltip().title(() => _t.append("inspector.back_tooltip")).placement("bottom")
-      );
-      presetButton.append("div").attr("class", "preset-icon-container");
-      presetButton.append("div").attr("class", "label").append("div").attr("class", "label-inner");
-      presetButtonWrap.append("div").attr("class", "accessory-buttons");
-      var tagReferenceBodyWrap = selection2.selectAll(".tag-reference-body-wrap").data([0]);
-      tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append("div").attr("class", "tag-reference-body-wrap").merge(tagReferenceBodyWrap);
-      if (_tagReference) {
-        selection2.selectAll(".preset-list-button-wrap .accessory-buttons").style("display", _presets.length === 1 ? null : "none").call(_tagReference.button);
-        tagReferenceBodyWrap.style("display", _presets.length === 1 ? null : "none").call(_tagReference.body);
+    entityEditor.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _base = context.graph();
+      _coalesceChanges = false;
+      if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor;
+      _entityIDs = val;
+      loadActivePresets(true);
+      return entityEditor.modified(false);
+    };
+    entityEditor.newFeature = function(val) {
+      if (!arguments.length) return _newFeature;
+      _newFeature = val;
+      return entityEditor;
+    };
+    function loadActivePresets(isForNewSelection) {
+      var graph = context.graph();
+      var counts = {};
+      for (var i3 in _entityIDs) {
+        var entity = graph.hasEntity(_entityIDs[i3]);
+        if (!entity) return;
+        var match = _mainPresetIndex.match(entity, graph);
+        if (!counts[match.id]) counts[match.id] = 0;
+        counts[match.id] += 1;
       }
-      selection2.selectAll(".preset-reset").on("click", function() {
-        dispatch14.call("choose", this, _presets);
-      }).on("pointerdown pointerup mousedown mouseup", function(d3_event) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
+      var matches = Object.keys(counts).sort(function(p1, p2) {
+        return counts[p2] - counts[p1];
+      }).map(function(pID) {
+        return _mainPresetIndex.item(pID);
       });
+      if (!isForNewSelection) {
+        var weakPreset = _activePresets.length === 1 && !_activePresets[0].isFallback() && Object.keys(_activePresets[0].addTags || {}).length === 0;
+        if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
+      }
+      entityEditor.presets(matches);
+    }
+    entityEditor.presets = function(val) {
+      if (!arguments.length) return _activePresets;
+      if (!utilArrayIdentical(val, _activePresets)) {
+        _activePresets = val;
+      }
+      return entityEditor;
+    };
+    return utilRebind(entityEditor, dispatch14, "on");
+  }
+
+  // modules/ui/preset_list.js
+  function uiPresetList(context) {
+    var dispatch14 = dispatch_default("cancel", "choose");
+    var _entityIDs;
+    var _currLoc;
+    var _currentPresets;
+    var _autofocus = false;
+    function presetList(selection2) {
+      if (!_entityIDs) return;
+      var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
+      selection2.html("");
+      var messagewrap = selection2.append("div").attr("class", "header fillL");
+      var message = messagewrap.append("h2").call(_t.append("inspector.choose"));
+      var direction = _mainLocalizer.textDirection() === "rtl" ? "backward" : "forward";
+      messagewrap.append("button").attr("class", "preset-choose").attr("title", _entityIDs.length === 1 ? _t("inspector.edit") : _t("inspector.edit_features")).on("click", function() {
+        dispatch14.call("cancel", this);
+      }).call(svgIcon("#iD-icon-".concat(direction)));
+      function initialKeydown(d3_event) {
+        if (search.property("value").length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes["\u232B"] || d3_event.keyCode === utilKeybinding.keyCodes["\u2326"])) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          operationDelete(context, _entityIDs)();
+        } else if (search.property("value").length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          context.undo();
+        } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
+          select_default2(this).on("keydown", keydown);
+          keydown.call(this, d3_event);
+        }
+      }
+      function keydown(d3_event) {
+        if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"] && // if insertion point is at the end of the string
+        search.node().selectionStart === search.property("value").length) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          var buttons = list2.selectAll(".preset-list-button");
+          if (!buttons.empty()) buttons.nodes()[0].focus();
+        }
+      }
+      function keypress(d3_event) {
+        var value = search.property("value");
+        if (d3_event.keyCode === 13 && // ↩ Return
+        value.length) {
+          list2.selectAll(".preset-list-item:first-child").each(function(d2) {
+            d2.choose.call(this);
+          });
+        }
+      }
+      function inputevent() {
+        var value = search.property("value");
+        list2.classed("filtered", value.length);
+        var results, messageText;
+        if (value.length) {
+          results = presets.search(value, entityGeometries()[0], _currLoc);
+          messageText = _t.html("inspector.results", {
+            n: results.collection.length,
+            search: value
+          });
+        } else {
+          var entityPresets2 = _entityIDs.map((entityID) => _mainPresetIndex.match(context.graph().entity(entityID), context.graph()));
+          results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc, entityPresets2);
+          messageText = _t.html("inspector.choose");
+        }
+        list2.call(drawList, results);
+        message.html(messageText);
+      }
+      var searchWrap = selection2.append("div").attr("class", "search-header");
+      searchWrap.call(svgIcon("#iD-icon-search", "pre-text"));
+      var search = searchWrap.append("input").attr("class", "preset-search-input").attr("placeholder", _t("inspector.search")).attr("type", "search").call(utilNoAuto).on("keydown", initialKeydown).on("keypress", keypress).on("input", debounce_default(inputevent));
+      if (_autofocus) {
+        search.node().focus();
+        setTimeout(function() {
+          search.node().focus();
+        }, 0);
+      }
+      var listWrap = selection2.append("div").attr("class", "inspector-body");
+      var entityPresets = _entityIDs.map((entityID) => _mainPresetIndex.match(context.graph().entity(entityID), context.graph()));
+      var list2 = listWrap.append("div").attr("class", "preset-list").call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc, entityPresets));
+      context.features().on("change.preset-list", updateForFeatureHiddenState);
+    }
+    function drawList(list2, presets) {
+      presets = presets.matchAllGeometry(entityGeometries());
+      var collection = presets.collection.reduce(function(collection2, preset) {
+        if (!preset) return collection2;
+        if (preset.members) {
+          if (preset.members.collection.filter(function(preset2) {
+            return preset2.addable();
+          }).length > 1) {
+            collection2.push(CategoryItem(preset));
+          }
+        } else if (preset.addable()) {
+          collection2.push(PresetItem(preset));
+        }
+        return collection2;
+      }, []);
+      var items = list2.selectAll(".preset-list-item").data(collection, function(d2) {
+        return d2.preset.id;
+      });
+      items.order();
+      items.exit().remove();
+      items.enter().append("div").attr("class", function(item) {
+        return "preset-list-item preset-" + item.preset.id.replace("/", "-");
+      }).classed("current", function(item) {
+        return _currentPresets.indexOf(item.preset) !== -1;
+      }).each(function(item) {
+        select_default2(this).call(item);
+      }).style("opacity", 0).transition().style("opacity", 1);
+      updateForFeatureHiddenState();
+    }
+    function itemKeydown(d3_event) {
+      var item = select_default2(this.closest(".preset-list-item"));
+      var parentItem = select_default2(item.node().parentNode.closest(".preset-list-item"));
+      if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"]) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        var nextItem = select_default2(item.node().nextElementSibling);
+        if (nextItem.empty()) {
+          if (!parentItem.empty()) {
+            nextItem = select_default2(parentItem.node().nextElementSibling);
+          }
+        } else if (select_default2(this).classed("expanded")) {
+          nextItem = item.select(".subgrid .preset-list-item:first-child");
+        }
+        if (!nextItem.empty()) {
+          nextItem.select(".preset-list-button").node().focus();
+        }
+      } else if (d3_event.keyCode === utilKeybinding.keyCodes["\u2191"]) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        var previousItem = select_default2(item.node().previousElementSibling);
+        if (previousItem.empty()) {
+          if (!parentItem.empty()) {
+            previousItem = parentItem;
+          }
+        } else if (previousItem.select(".preset-list-button").classed("expanded")) {
+          previousItem = previousItem.select(".subgrid .preset-list-item:last-child");
+        }
+        if (!previousItem.empty()) {
+          previousItem.select(".preset-list-button").node().focus();
+        } else {
+          var search = select_default2(this.closest(".preset-list-pane")).select(".preset-search-input");
+          search.node().focus();
+        }
+      } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2192" : "\u2190"]) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        if (!parentItem.empty()) {
+          parentItem.select(".preset-list-button").node().focus();
+        }
+      } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2190" : "\u2192"]) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        item.datum().choose.call(select_default2(this).node());
+      }
+    }
+    function CategoryItem(preset) {
+      var box, sublist, shown = false;
+      function item(selection2) {
+        var wrap2 = selection2.append("div").attr("class", "preset-list-button-wrap category");
+        function click() {
+          var isExpanded = select_default2(this).classed("expanded");
+          var iconName = isExpanded ? _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward" : "#iD-icon-down";
+          select_default2(this).classed("expanded", !isExpanded).attr("title", !isExpanded ? _t("icons.collapse") : _t("icons.expand"));
+          select_default2(this).selectAll("div.label-inner svg.icon use").attr("href", iconName);
+          item.choose();
+        }
+        var geometries = entityGeometries();
+        var button = wrap2.append("button").attr("class", "preset-list-button").attr("title", _t("icons.expand")).classed("expanded", false).call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on("click", click).on("keydown", function(d3_event) {
+          if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2190" : "\u2192"]) {
+            d3_event.preventDefault();
+            d3_event.stopPropagation();
+            if (!select_default2(this).classed("expanded")) {
+              click.call(this, d3_event);
+            }
+          } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2192" : "\u2190"]) {
+            d3_event.preventDefault();
+            d3_event.stopPropagation();
+            if (select_default2(this).classed("expanded")) {
+              click.call(this, d3_event);
+            }
+          } else {
+            itemKeydown.call(this, d3_event);
+          }
+        });
+        var label = button.append("div").attr("class", "label").append("div").attr("class", "label-inner");
+        label.append("div").attr("class", "namepart").call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward", "inline")).append("span").call(preset.nameLabel()).append("span").text("\u2026");
+        box = selection2.append("div").attr("class", "subgrid").style("max-height", "0px").style("opacity", 0);
+        box.append("div").attr("class", "arrow");
+        sublist = box.append("div").attr("class", "preset-list fillL3");
+      }
+      item.choose = function() {
+        if (!box || !sublist) return;
+        if (shown) {
+          shown = false;
+          box.transition().duration(200).style("opacity", "0").style("max-height", "0px").style("padding-bottom", "0px");
+        } else {
+          shown = true;
+          var members = preset.members.matchAllGeometry(entityGeometries());
+          sublist.call(drawList, members);
+          box.transition().duration(200).style("opacity", "1").style("max-height", 200 + members.collection.length * 190 + "px").style("padding-bottom", "10px");
+        }
+      };
+      item.preset = preset;
+      return item;
+    }
+    function PresetItem(preset) {
+      function item(selection2) {
+        var wrap2 = selection2.append("div").attr("class", "preset-list-button-wrap");
+        var geometries = entityGeometries();
+        var button = wrap2.append("button").attr("class", "preset-list-button").call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on("click", item.choose).on("keydown", itemKeydown);
+        var label = button.append("div").attr("class", "label").append("div").attr("class", "label-inner");
+        var nameparts = [
+          preset.nameLabel(),
+          preset.subtitleLabel()
+        ].filter(Boolean);
+        label.selectAll(".namepart").data(nameparts, (d2) => d2.stringId).enter().append("div").attr("class", "namepart").text("").each(function(d2) {
+          d2(select_default2(this));
+        });
+        wrap2.call(item.reference.button);
+        selection2.call(item.reference.body);
+      }
+      item.choose = function() {
+        if (select_default2(this).classed("disabled")) return;
+        if (!context.inIntro()) {
+          _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
+        }
+        context.perform(
+          function(graph) {
+            for (var i3 in _entityIDs) {
+              var entityID = _entityIDs[i3];
+              var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
+              graph = actionChangePreset(entityID, oldPreset, preset)(graph);
+            }
+            return graph;
+          },
+          _t("operations.change_tags.annotation")
+        );
+        context.validator().validate();
+        dispatch14.call("choose", this, preset);
+      };
+      item.help = function(d3_event) {
+        d3_event.stopPropagation();
+        item.reference.toggle();
+      };
+      item.preset = preset;
+      item.reference = uiTagReference(preset.reference(), context);
+      return item;
+    }
+    function updateForFeatureHiddenState() {
+      if (!_entityIDs.every(context.hasEntity)) return;
       var geometries = entityGeometries();
-      selection2.select(".preset-list-item button").call(
-        uiPresetIcon().geometry(_presets.length === 1 ? geometries.length === 1 && geometries[0] : null).preset(_presets.length === 1 ? _presets[0] : _mainPresetIndex.item("point"))
-      );
-      var names = _presets.length === 1 ? [
-        _presets[0].nameLabel(),
-        _presets[0].subtitleLabel()
-      ].filter(Boolean) : [_t.append("inspector.multiple_types")];
-      var label = selection2.select(".label-inner");
-      var nameparts = label.selectAll(".namepart").data(names, (d2) => d2.stringId);
-      nameparts.exit().remove();
-      nameparts.enter().append("div").attr("class", "namepart").text("").each(function(d2) {
-        d2(select_default2(this));
+      var button = context.container().selectAll(".preset-list .preset-list-button");
+      button.call(uiTooltip().destroyAny);
+      button.each(function(item, index) {
+        var hiddenPresetFeaturesId;
+        for (var i3 in geometries) {
+          hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i3]);
+          if (hiddenPresetFeaturesId) break;
+        }
+        var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
+        select_default2(this).classed("disabled", isHiddenPreset);
+        if (isHiddenPreset) {
+          var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
+          select_default2(this).call(
+            uiTooltip().title(() => _t.append("inspector.hidden_preset." + (isAutoHidden ? "zoom" : "manual"), {
+              features: _t("feature." + hiddenPresetFeaturesId + ".description")
+            })).placement(index < 2 ? "bottom" : "top")
+          );
+        }
       });
     }
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return section;
+    presetList.autofocus = function(val) {
+      if (!arguments.length) return _autofocus;
+      _autofocus = val;
+      return presetList;
     };
-    section.presets = function(val) {
-      if (!arguments.length)
-        return _presets;
-      if (!utilArrayIdentical(val, _presets)) {
-        _presets = val;
-        if (_presets.length === 1) {
-          _tagReference = uiTagReference(_presets[0].reference(), context).showing(false);
-        }
+    presetList.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      _currLoc = null;
+      if (_entityIDs && _entityIDs.length) {
+        const extent = _entityIDs.reduce(function(extent2, entityID) {
+          var entity = context.graph().entity(entityID);
+          return extent2.extend(entity.extent(context.graph()));
+        }, geoExtent());
+        _currLoc = extent.center();
+        var presets = _entityIDs.map(function(entityID) {
+          return _mainPresetIndex.match(context.entity(entityID), context.graph());
+        });
+        presetList.presets(presets);
       }
-      return section;
+      return presetList;
+    };
+    presetList.presets = function(val) {
+      if (!arguments.length) return _currentPresets;
+      _currentPresets = val;
+      return presetList;
     };
     function entityGeometries() {
       var counts = {};
       for (var i3 in _entityIDs) {
-        var geometry = context.graph().geometry(_entityIDs[i3]);
-        if (!counts[geometry])
-          counts[geometry] = 0;
+        var entityID = _entityIDs[i3];
+        var entity = context.entity(entityID);
+        var geometry = entity.geometry(context.graph());
+        if (geometry === "vertex" && entity.isOnAddressLine(context.graph())) {
+          geometry = "point";
+        }
+        if (!counts[geometry]) counts[geometry] = 0;
         counts[geometry] += 1;
       }
       return Object.keys(counts).sort(function(geom1, geom2) {
         return counts[geom2] - counts[geom1];
       });
     }
-    return utilRebind(section, dispatch14, "on");
+    return utilRebind(presetList, dispatch14, "on");
   }
 
-  // modules/ui/sections/preset_fields.js
-  function uiSectionPresetFields(context) {
-    var section = uiSection("preset-fields", context).label(() => _t.append("inspector.fields")).disclosureContent(renderDisclosureContent);
-    var dispatch14 = dispatch_default("change", "revert");
-    var formFields = uiFormFields(context);
-    var _state;
-    var _fieldsArr;
-    var _presets = [];
-    var _tags;
+  // modules/ui/inspector.js
+  function uiInspector(context) {
+    var presetList = uiPresetList(context);
+    var entityEditor = uiEntityEditor(context);
+    var wrap2 = select_default2(null), presetPane = select_default2(null), editorPane = select_default2(null);
+    var _state = "select";
     var _entityIDs;
-    function renderDisclosureContent(selection2) {
-      if (!_fieldsArr) {
-        var graph = context.graph();
-        var geometries = Object.keys(_entityIDs.reduce(function(geoms, entityID) {
-          geoms[graph.entity(entityID).geometry(graph)] = true;
-          return geoms;
-        }, {}));
-        const loc = _entityIDs.reduce(function(extent, entityID) {
-          var entity = context.graph().entity(entityID);
-          return extent.extend(entity.extent(context.graph()));
-        }, geoExtent()).center();
-        var presetsManager = _mainPresetIndex;
-        var allFields = [];
-        var allMoreFields = [];
-        var sharedTotalFields;
-        _presets.forEach(function(preset) {
-          var fields = preset.fields(loc);
-          var moreFields = preset.moreFields(loc);
-          allFields = utilArrayUnion(allFields, fields);
-          allMoreFields = utilArrayUnion(allMoreFields, moreFields);
-          if (!sharedTotalFields) {
-            sharedTotalFields = utilArrayUnion(fields, moreFields);
-          } else {
-            sharedTotalFields = sharedTotalFields.filter(function(field) {
-              return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
-            });
-          }
-        });
-        var sharedFields = allFields.filter(function(field) {
-          return sharedTotalFields.indexOf(field) !== -1;
-        });
-        var sharedMoreFields = allMoreFields.filter(function(field) {
-          return sharedTotalFields.indexOf(field) !== -1;
-        });
-        _fieldsArr = [];
-        sharedFields.forEach(function(field) {
-          if (field.matchAllGeometry(geometries)) {
-            _fieldsArr.push(
-              uiField(context, field, _entityIDs)
-            );
-          }
-        });
-        var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
-        if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field("restrictions")) {
-          _fieldsArr.push(
-            uiField(context, presetsManager.field("restrictions"), _entityIDs)
-          );
-        }
-        var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
-        additionalFields.sort(function(field1, field2) {
-          return field1.title().localeCompare(field2.title(), _mainLocalizer.localeCode());
-        });
-        additionalFields.forEach(function(field) {
-          if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
-            _fieldsArr.push(
-              uiField(context, field, _entityIDs, { show: false })
-            );
-          }
-        });
-        _fieldsArr.forEach(function(field) {
-          field.on("change", function(t2, onInput) {
-            dispatch14.call("change", field, _entityIDs, t2, onInput);
-          }).on("revert", function(keys2) {
-            dispatch14.call("revert", field, keys2);
-          });
-        });
-      }
-      _fieldsArr.forEach(function(field) {
-        field.state(_state).tags(_tags);
+    var _newFeature = false;
+    function inspector(selection2) {
+      presetList.entityIDs(_entityIDs).autofocus(_newFeature).on("choose", inspector.setPreset).on("cancel", function() {
+        inspector.setPreset();
       });
-      selection2.call(
-        formFields.fieldsArr(_fieldsArr).state(_state).klass("grouped-items-area")
+      entityEditor.state(_state).entityIDs(_entityIDs).on("choose", inspector.showList);
+      wrap2 = selection2.selectAll(".panewrap").data([0]);
+      var enter = wrap2.enter().append("div").attr("class", "panewrap");
+      enter.append("div").attr("class", "preset-list-pane pane");
+      enter.append("div").attr("class", "entity-editor-pane pane");
+      wrap2 = wrap2.merge(enter);
+      presetPane = wrap2.selectAll(".preset-list-pane");
+      editorPane = wrap2.selectAll(".entity-editor-pane");
+      function shouldDefaultToPresetList() {
+        if (_state !== "select") return false;
+        if (_entityIDs.length !== 1) return false;
+        var entityID = _entityIDs[0];
+        var entity = context.hasEntity(entityID);
+        if (!entity) return false;
+        if (entity.hasNonGeometryTags()) return false;
+        if (_newFeature) return true;
+        if (entity.geometry(context.graph()) !== "vertex") return false;
+        if (context.graph().parentRelations(entity).length) return false;
+        if (context.validator().getEntityIssues(entityID).length) return false;
+        if (entity.isHighwayIntersection(context.graph())) return false;
+        return true;
+      }
+      if (shouldDefaultToPresetList()) {
+        wrap2.style("right", "-100%");
+        editorPane.classed("hide", true);
+        presetPane.classed("hide", false).call(presetList);
+      } else {
+        wrap2.style("right", "0%");
+        presetPane.classed("hide", true);
+        editorPane.classed("hide", false).call(entityEditor);
+      }
+      var footer = selection2.selectAll(".footer").data([0]);
+      footer = footer.enter().append("div").attr("class", "footer").merge(footer);
+      footer.call(
+        uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0]))
       );
     }
-    section.presets = function(val) {
-      if (!arguments.length)
-        return _presets;
-      if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
-        _presets = val;
-        _fieldsArr = null;
+    inspector.showList = function(presets) {
+      presetPane.classed("hide", false);
+      wrap2.transition().styleTween("right", function() {
+        return value_default("0%", "-100%");
+      }).on("end", function() {
+        editorPane.classed("hide", true);
+      });
+      if (presets) {
+        presetList.presets(presets);
       }
-      return section;
+      presetPane.call(presetList.autofocus(true));
     };
-    section.state = function(val) {
-      if (!arguments.length)
-        return _state;
+    inspector.setPreset = function(preset) {
+      if (preset && preset.id === "type/multipolygon") {
+        presetPane.call(presetList.autofocus(true));
+      } else {
+        editorPane.classed("hide", false);
+        wrap2.transition().styleTween("right", function() {
+          return value_default("-100%", "0%");
+        }).on("end", function() {
+          presetPane.classed("hide", true);
+        });
+        if (preset) {
+          entityEditor.presets([preset]);
+        }
+        editorPane.call(entityEditor);
+      }
+    };
+    inspector.state = function(val) {
+      if (!arguments.length) return _state;
       _state = val;
-      return section;
+      entityEditor.state(_state);
+      context.container().selectAll(".field-help-body").remove();
+      return inspector;
     };
-    section.tags = function(val) {
-      if (!arguments.length)
-        return _tags;
-      _tags = val;
-      return section;
+    inspector.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return inspector;
     };
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
-        _entityIDs = val;
-        _fieldsArr = null;
-      }
-      return section;
+    inspector.newFeature = function(val) {
+      if (!arguments.length) return _newFeature;
+      _newFeature = val;
+      return inspector;
     };
-    return utilRebind(section, dispatch14, "on");
+    return inspector;
   }
 
-  // modules/ui/sections/raw_member_editor.js
-  function uiSectionRawMemberEditor(context) {
-    var section = uiSection("raw-member-editor", context).shouldDisplay(function() {
-      if (!_entityIDs || _entityIDs.length !== 1)
-        return false;
-      var entity = context.hasEntity(_entityIDs[0]);
-      return entity && entity.type === "relation";
-    }).label(function() {
-      var entity = context.hasEntity(_entityIDs[0]);
-      if (!entity)
-        return "";
-      var gt2 = entity.members.length > _maxMembers ? ">" : "";
-      var count = gt2 + entity.members.slice(0, _maxMembers).length;
-      return _t.append("inspector.title_count", { title: _t("inspector.members"), count });
-    }).disclosureContent(renderDisclosureContent);
-    var taginfo = services.taginfo;
-    var _entityIDs;
-    var _maxMembers = 1e3;
-    function downloadMember(d3_event, d2) {
-      d3_event.preventDefault();
-      select_default2(this).classed("loading", true);
-      context.loadEntity(d2.id, function() {
-        section.reRender();
-      });
+  // modules/ui/keepRight_details.js
+  function uiKeepRightDetails(context) {
+    let _qaItem;
+    function issueDetail(d2) {
+      const { itemType, parentIssueType } = d2;
+      const unknown = { html: _t.html("inspector.unknown") };
+      let replacements = d2.replacements || {};
+      replacements.default = unknown;
+      if (_mainLocalizer.hasTextForStringId("QA.keepRight.errorTypes.".concat(itemType, ".title"))) {
+        return _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
+      } else {
+        return _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
+      }
     }
-    function zoomToMember(d3_event, d2) {
-      d3_event.preventDefault();
-      var entity = context.entity(d2.id);
-      context.map().zoomToEase(entity);
-      utilHighlightEntities([d2.id], true, context);
+    function keepRightDetails(selection2) {
+      const details = selection2.selectAll(".error-details").data(
+        _qaItem ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      details.exit().remove();
+      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
+      const descriptionEnter = detailsEnter.append("div").attr("class", "qa-details-subsection");
+      descriptionEnter.append("h4").call(_t.append("QA.keepRight.detail_description"));
+      descriptionEnter.append("div").attr("class", "qa-details-description-text").html(issueDetail);
+      let relatedEntities = [];
+      descriptionEnter.selectAll(".error_entity_link, .error_object_link").attr("href", "#").each(function() {
+        const link3 = select_default2(this);
+        const isObjectLink = link3.classed("error_object_link");
+        const entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
+        const entity = context.hasEntity(entityID);
+        relatedEntities.push(entityID);
+        link3.on("mouseenter", () => {
+          utilHighlightEntities([entityID], true, context);
+        }).on("mouseleave", () => {
+          utilHighlightEntities([entityID], false, context);
+        }).on("click", (d3_event) => {
+          d3_event.preventDefault();
+          utilHighlightEntities([entityID], false, context);
+          const osmlayer = context.layers().layer("osm");
+          if (!osmlayer.enabled()) {
+            osmlayer.enabled(true);
+          }
+          context.map().centerZoomEase(_qaItem.loc, 20);
+          if (entity) {
+            context.enter(modeSelect(context, [entityID]));
+          } else {
+            context.loadEntity(entityID, (err, result) => {
+              if (err) return;
+              const entity2 = result.data.find((e3) => e3.id === entityID);
+              if (entity2) context.enter(modeSelect(context, [entityID]));
+            });
+          }
+        });
+        if (entity) {
+          let name = utilDisplayName(entity);
+          if (!name && !isObjectLink) {
+            const preset = _mainPresetIndex.match(entity, context.graph());
+            name = preset && !preset.isFallback() && preset.name();
+          }
+          if (name) {
+            this.innerText = name;
+          }
+        }
+      });
+      context.features().forceVisible(relatedEntities);
+      context.map().pan([0, 0]);
     }
-    function selectMember(d3_event, d2) {
-      d3_event.preventDefault();
-      utilHighlightEntities([d2.id], false, context);
-      var entity = context.entity(d2.id);
-      var mapExtent = context.map().extent();
-      if (!entity.intersects(mapExtent, context.graph())) {
-        context.map().zoomToEase(entity);
+    keepRightDetails.issue = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return keepRightDetails;
+    };
+    return keepRightDetails;
+  }
+
+  // modules/ui/keepRight_header.js
+  function uiKeepRightHeader() {
+    let _qaItem;
+    function issueTitle(d2) {
+      const { itemType, parentIssueType } = d2;
+      const unknown = _t.html("inspector.unknown");
+      let replacements = d2.replacements || {};
+      replacements.default = { html: unknown };
+      if (_mainLocalizer.hasTextForStringId("QA.keepRight.errorTypes.".concat(itemType, ".title"))) {
+        return _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
+      } else {
+        return _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
       }
-      context.enter(modeSelect(context, [d2.id]));
     }
-    function changeRole(d3_event, d2) {
-      var oldRole = d2.role;
-      var newRole = context.cleanRelationRole(select_default2(this).property("value"));
-      if (oldRole !== newRole) {
-        var member = { id: d2.id, type: d2.type, role: newRole };
-        context.perform(
-          actionChangeMember(d2.relation.id, member, d2.index),
-          _t("operations.change_role.annotation", {
-            n: 1
-          })
-        );
-        context.validator().validate();
+    function keepRightHeader(selection2) {
+      const header = selection2.selectAll(".qa-header").data(
+        _qaItem ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      header.exit().remove();
+      const headerEnter = header.enter().append("div").attr("class", "qa-header");
+      const iconEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d2) => d2.id < 0);
+      iconEnter.append("div").attr("class", (d2) => "preset-icon-28 qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.parentIssueType)).call(svgIcon("#iD-icon-bolt", "qaItem-fill"));
+      headerEnter.append("div").attr("class", "qa-header-label").html(issueTitle);
+    }
+    keepRightHeader.issue = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return keepRightHeader;
+    };
+    return keepRightHeader;
+  }
+
+  // modules/ui/view_on_keepRight.js
+  function uiViewOnKeepRight() {
+    let _qaItem;
+    function viewOnKeepRight(selection2) {
+      let url;
+      if (services.keepRight && _qaItem instanceof QAItem) {
+        url = services.keepRight.issueURL(_qaItem);
       }
+      const link3 = selection2.selectAll(".view-on-keepRight").data(url ? [url] : []);
+      link3.exit().remove();
+      const linkEnter = link3.enter().append("a").attr("class", "view-on-keepRight").attr("target", "_blank").attr("rel", "noopener").attr("href", (d2) => d2).call(svgIcon("#iD-icon-out-link", "inline"));
+      linkEnter.append("span").call(_t.append("inspector.view_on_keepRight"));
     }
-    function deleteMember(d3_event, d2) {
-      utilHighlightEntities([d2.id], false, context);
-      context.perform(
-        actionDeleteMember(d2.relation.id, d2.index),
-        _t("operations.delete_member.annotation", {
-          n: 1
-        })
+    viewOnKeepRight.what = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return viewOnKeepRight;
+    };
+    return viewOnKeepRight;
+  }
+
+  // modules/ui/keepRight_editor.js
+  function uiKeepRightEditor(context) {
+    const dispatch14 = dispatch_default("change");
+    const qaDetails = uiKeepRightDetails(context);
+    const qaHeader = uiKeepRightHeader(context);
+    let _qaItem;
+    function keepRightEditor(selection2) {
+      const headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("QA.keepRight.title"));
+      let body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      const editor = body.selectAll(".qa-editor").data([0]);
+      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
+      const footer = selection2.selectAll(".footer").data([0]);
+      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnKeepRight(context).what(_qaItem));
+    }
+    function keepRightSaveSection(selection2) {
+      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
+      const isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
+      let saveSection = selection2.selectAll(".qa-save").data(
+        isShown ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
       );
-      if (!context.hasEntity(d2.relation.id)) {
-        context.enter(modeBrowse(context));
-      } else {
-        context.validator().validate();
+      saveSection.exit().remove();
+      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
+      saveSectionEnter.append("h4").attr("class", ".qa-save-header").call(_t.append("QA.keepRight.comment"));
+      saveSectionEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("QA.keepRight.comment_placeholder")).attr("maxlength", 1e3).property("value", (d2) => d2.newComment || d2.comment).call(utilNoAuto).on("input", changeInput).on("blur", changeInput);
+      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
+      function changeInput() {
+        const input = select_default2(this);
+        let val = input.property("value").trim();
+        if (val === _qaItem.comment) {
+          val = void 0;
+        }
+        _qaItem = _qaItem.update({ newComment: val });
+        const qaService = services.keepRight;
+        if (qaService) {
+          qaService.replaceItem(_qaItem);
+        }
+        saveSection.call(qaSaveButtons);
       }
     }
-    function renderDisclosureContent(selection2) {
-      var entityID = _entityIDs[0];
-      var memberships = [];
-      var entity = context.entity(entityID);
-      entity.members.slice(0, _maxMembers).forEach(function(member, index) {
-        memberships.push({
-          index,
-          id: member.id,
-          type: member.type,
-          role: member.role,
-          relation: entity,
-          member: context.hasEntity(member.id),
-          domId: utilUniqueDomId(entityID + "-member-" + index)
-        });
-      });
-      var list2 = selection2.selectAll(".member-list").data([0]);
-      list2 = list2.enter().append("ul").attr("class", "member-list").merge(list2);
-      var items = list2.selectAll("li").data(memberships, function(d2) {
-        return osmEntity.key(d2.relation) + "," + d2.index + "," + (d2.member ? osmEntity.key(d2.member) : "incomplete");
+    function qaSaveButtons(selection2) {
+      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
+      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d2) => d2.status + d2.id);
+      buttonSection.exit().remove();
+      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
+      buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("QA.keepRight.save_comment"));
+      buttonEnter.append("button").attr("class", "button close-button action");
+      buttonEnter.append("button").attr("class", "button ignore-button action");
+      buttonSection = buttonSection.merge(buttonEnter);
+      buttonSection.select(".comment-button").attr("disabled", (d2) => d2.newComment ? null : true).on("click.comment", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.keepRight;
+        if (qaService) {
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
+        }
       });
-      items.exit().each(unbind).remove();
-      var itemsEnter = items.enter().append("li").attr("class", "member-row form-field").classed("member-incomplete", function(d2) {
-        return !d2.member;
+      buttonSection.select(".close-button").html((d2) => {
+        const andComment = d2.newComment ? "_comment" : "";
+        return _t.html("QA.keepRight.close".concat(andComment));
+      }).on("click.close", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.keepRight;
+        if (qaService) {
+          d2.newStatus = "ignore_t";
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
+        }
       });
-      itemsEnter.each(function(d2) {
-        var item = select_default2(this);
-        var label = item.append("label").attr("class", "field-label").attr("for", d2.domId);
-        if (d2.member) {
-          item.on("mouseover", function() {
-            utilHighlightEntities([d2.id], true, context);
-          }).on("mouseout", function() {
-            utilHighlightEntities([d2.id], false, context);
-          });
-          var labelLink = label.append("span").attr("class", "label-text").append("a").attr("href", "#").on("click", selectMember);
-          labelLink.append("span").attr("class", "member-entity-type").text(function(d4) {
-            var matched = _mainPresetIndex.match(d4.member, context.graph());
-            return matched && matched.name() || utilDisplayType(d4.member.id);
-          });
-          labelLink.append("span").attr("class", "member-entity-name").classed("has-colour", (d4) => d4.member.type === "relation" && d4.member.tags.colour && isColourValid(d4.member.tags.colour)).style("border-color", (d4) => d4.member.type === "relation" && d4.member.tags.colour).text(function(d4) {
-            return utilDisplayName(d4.member);
-          });
-          label.append("button").attr("title", _t("icons.remove")).attr("class", "remove member-delete").call(svgIcon("#iD-operation-delete"));
-          label.append("button").attr("class", "member-zoom").attr("title", _t("icons.zoom_to")).call(svgIcon("#iD-icon-framed-dot", "monochrome")).on("click", zoomToMember);
-        } else {
-          var labelText = label.append("span").attr("class", "label-text");
-          labelText.append("span").attr("class", "member-entity-type").call(_t.append("inspector." + d2.type, { id: d2.id }));
-          labelText.append("span").attr("class", "member-entity-name").call(_t.append("inspector.incomplete", { id: d2.id }));
-          label.append("button").attr("class", "member-download").attr("title", _t("icons.download")).call(svgIcon("#iD-icon-load")).on("click", downloadMember);
+      buttonSection.select(".ignore-button").html((d2) => {
+        const andComment = d2.newComment ? "_comment" : "";
+        return _t.html("QA.keepRight.ignore".concat(andComment));
+      }).on("click.ignore", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.keepRight;
+        if (qaService) {
+          d2.newStatus = "ignore";
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
         }
       });
-      var wrapEnter = itemsEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
-      wrapEnter.append("input").attr("class", "member-role").attr("id", function(d2) {
-        return d2.domId;
-      }).property("type", "text").attr("placeholder", _t("inspector.role")).call(utilNoAuto);
-      if (taginfo) {
-        wrapEnter.each(bindTypeahead);
+    }
+    keepRightEditor.error = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return keepRightEditor;
+    };
+    return utilRebind(keepRightEditor, dispatch14, "on");
+  }
+
+  // modules/ui/osmose_details.js
+  function uiOsmoseDetails(context) {
+    let _qaItem;
+    function issueString(d2, type2) {
+      if (!d2) return "";
+      const s2 = services.osmose.getStrings(d2.itemType);
+      return type2 in s2 ? s2[type2] : "";
+    }
+    function osmoseDetails(selection2) {
+      const details = selection2.selectAll(".error-details").data(
+        _qaItem ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      details.exit().remove();
+      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
+      if (issueString(_qaItem, "detail")) {
+        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
+        div.append("h4").call(_t.append("QA.keepRight.detail_description"));
+        div.append("p").attr("class", "qa-details-description-text").html((d2) => issueString(d2, "detail")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
       }
-      items = items.merge(itemsEnter).order();
-      items.select("input.member-role").property("value", function(d2) {
-        return d2.role;
-      }).on("blur", changeRole).on("change", changeRole);
-      items.select("button.member-delete").on("click", deleteMember);
-      var dragOrigin, targetIndex;
-      items.call(
-        drag_default().on("start", function(d3_event) {
-          dragOrigin = {
-            x: d3_event.x,
-            y: d3_event.y
-          };
-          targetIndex = null;
-        }).on("drag", function(d3_event) {
-          var x2 = d3_event.x - dragOrigin.x, y2 = d3_event.y - dragOrigin.y;
-          if (!select_default2(this).classed("dragging") && // don't display drag until dragging beyond a distance threshold
-          Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2)) <= 5)
-            return;
-          var index = items.nodes().indexOf(this);
-          select_default2(this).classed("dragging", true);
-          targetIndex = null;
-          selection2.selectAll("li.member-row").style("transform", function(d2, index2) {
-            var node = select_default2(this).node();
-            if (index === index2) {
-              return "translate(" + x2 + "px, " + y2 + "px)";
-            } else if (index2 > index && d3_event.y > node.offsetTop) {
-              if (targetIndex === null || index2 > targetIndex) {
-                targetIndex = index2;
-              }
-              return "translateY(-100%)";
-            } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
-              if (targetIndex === null || index2 < targetIndex) {
-                targetIndex = index2;
-              }
-              return "translateY(100%)";
+      const detailsDiv = detailsEnter.append("div").attr("class", "qa-details-subsection");
+      const elemsDiv = detailsEnter.append("div").attr("class", "qa-details-subsection");
+      if (issueString(_qaItem, "fix")) {
+        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
+        div.append("h4").call(_t.append("QA.osmose.fix_title"));
+        div.append("p").html((d2) => issueString(d2, "fix")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+      }
+      if (issueString(_qaItem, "trap")) {
+        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
+        div.append("h4").call(_t.append("QA.osmose.trap_title"));
+        div.append("p").html((d2) => issueString(d2, "trap")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+      }
+      const thisItem = _qaItem;
+      services.osmose.loadIssueDetail(_qaItem).then((d2) => {
+        if (!d2.elems || d2.elems.length === 0) return;
+        if (context.selectedErrorID() !== thisItem.id && context.container().selectAll(".qaItem.osmose.hover.itemId-".concat(thisItem.id)).empty()) return;
+        if (d2.detail) {
+          detailsDiv.append("h4").call(_t.append("QA.osmose.detail_title"));
+          detailsDiv.append("p").html((d4) => d4.detail).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+        }
+        elemsDiv.append("h4").call(_t.append("QA.osmose.elems_title"));
+        elemsDiv.append("ul").selectAll("li").data(d2.elems).enter().append("li").append("a").attr("href", "#").attr("class", "error_entity_link").text((d4) => d4).each(function() {
+          const link3 = select_default2(this);
+          const entityID = this.textContent;
+          const entity = context.hasEntity(entityID);
+          link3.on("mouseenter", () => {
+            utilHighlightEntities([entityID], true, context);
+          }).on("mouseleave", () => {
+            utilHighlightEntities([entityID], false, context);
+          }).on("click", (d3_event) => {
+            d3_event.preventDefault();
+            utilHighlightEntities([entityID], false, context);
+            const osmlayer = context.layers().layer("osm");
+            if (!osmlayer.enabled()) {
+              osmlayer.enabled(true);
             }
-            return null;
-          });
-        }).on("end", function(d3_event, d2) {
-          if (!select_default2(this).classed("dragging"))
-            return;
-          var index = items.nodes().indexOf(this);
-          select_default2(this).classed("dragging", false);
-          selection2.selectAll("li.member-row").style("transform", null);
-          if (targetIndex !== null) {
-            context.perform(
-              actionMoveMember(d2.relation.id, index, targetIndex),
-              _t("operations.reorder_members.annotation")
-            );
-            context.validator().validate();
-          }
-        })
-      );
-      function bindTypeahead(d2) {
-        var row = select_default2(this);
-        var role = row.selectAll("input.member-role");
-        var origValue = role.property("value");
-        function sort(value, data) {
-          var sameletter = [];
-          var other = [];
-          for (var i3 = 0; i3 < data.length; i3++) {
-            if (data[i3].value.substring(0, value.length) === value) {
-              sameletter.push(data[i3]);
+            context.map().centerZoom(d2.loc, 20);
+            if (entity) {
+              context.enter(modeSelect(context, [entityID]));
             } else {
-              other.push(data[i3]);
+              context.loadEntity(entityID, (err, result) => {
+                if (err) return;
+                const entity2 = result.data.find((e3) => e3.id === entityID);
+                if (entity2) context.enter(modeSelect(context, [entityID]));
+              });
             }
-          }
-          return sameletter.concat(other);
-        }
-        role.call(
-          uiCombobox(context, "member-role").fetcher(function(role2, callback) {
-            var geometry;
-            if (d2.member) {
-              geometry = context.graph().geometry(d2.member.id);
-            } else if (d2.type === "relation") {
-              geometry = "relation";
-            } else if (d2.type === "way") {
-              geometry = "line";
-            } else {
-              geometry = "point";
+          });
+          if (entity) {
+            let name = utilDisplayName(entity);
+            if (!name) {
+              const preset = _mainPresetIndex.match(entity, context.graph());
+              name = preset && !preset.isFallback() && preset.name();
             }
-            var rtype = entity.tags.type;
-            taginfo.roles({
-              debounce: true,
-              rtype: rtype || "",
-              geometry,
-              query: role2
-            }, function(err, data) {
-              if (!err)
-                callback(sort(role2, data));
-            });
-          }).on("cancel", function() {
-            role.property("value", origValue);
-          })
-        );
-      }
-      function unbind() {
-        var row = select_default2(this);
-        row.selectAll("input.member-role").call(uiCombobox.off, context);
-      }
+            if (name) {
+              this.innerText = name;
+            }
+          }
+        });
+        context.features().forceVisible(d2.elems);
+        context.map().pan([0, 0]);
+      }).catch((err) => {
+        console.log(err);
+      });
     }
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return section;
+    osmoseDetails.issue = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return osmoseDetails;
     };
-    return section;
+    return osmoseDetails;
   }
 
-  // modules/actions/delete_members.js
-  function actionDeleteMembers(relationId, memberIndexes) {
-    return function(graph) {
-      memberIndexes.sort((a2, b2) => b2 - a2);
-      for (var i3 in memberIndexes) {
-        graph = actionDeleteMember(relationId, memberIndexes[i3])(graph);
-      }
-      return graph;
+  // modules/ui/osmose_header.js
+  function uiOsmoseHeader() {
+    let _qaItem;
+    function issueTitle(d2) {
+      const unknown = _t("inspector.unknown");
+      if (!d2) return unknown;
+      const s2 = services.osmose.getStrings(d2.itemType);
+      return "title" in s2 ? s2.title : unknown;
+    }
+    function osmoseHeader(selection2) {
+      const header = selection2.selectAll(".qa-header").data(
+        _qaItem ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      header.exit().remove();
+      const headerEnter = header.enter().append("div").attr("class", "qa-header");
+      const svgEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d2) => d2.id < 0).append("svg").attr("width", "20px").attr("height", "30px").attr("viewbox", "0 0 20 30").attr("class", (d2) => "preset-icon-28 qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.itemType));
+      svgEnter.append("polygon").attr("fill", (d2) => services.osmose.getColor(d2.item)).attr("class", "qaItem-fill").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
+      svgEnter.append("use").attr("class", "icon-annotation").attr("width", "12px").attr("height", "12px").attr("transform", "translate(4, 5.5)").attr("xlink:href", (d2) => d2.icon ? "#" + d2.icon : "");
+      headerEnter.append("div").attr("class", "qa-header-label").text(issueTitle);
+    }
+    osmoseHeader.issue = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return osmoseHeader;
     };
+    return osmoseHeader;
   }
 
-  // modules/ui/sections/raw_membership_editor.js
-  function uiSectionRawMembershipEditor(context) {
-    var section = uiSection("raw-membership-editor", context).shouldDisplay(function() {
-      return _entityIDs && _entityIDs.length;
-    }).label(function() {
-      var parents = getSharedParentRelations();
-      var gt2 = parents.length > _maxMemberships ? ">" : "";
-      var count = gt2 + parents.slice(0, _maxMemberships).length;
-      return _t.append("inspector.title_count", { title: _t("inspector.relations"), count });
-    }).disclosureContent(renderDisclosureContent);
-    var taginfo = services.taginfo;
-    var nearbyCombo = uiCombobox(context, "parent-relation").minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function(d3_event, d2) {
-      if (d2.relation)
-        utilHighlightEntities([d2.relation.id], true, context);
-    }).itemsMouseLeave(function(d3_event, d2) {
-      if (d2.relation)
-        utilHighlightEntities([d2.relation.id], false, context);
-    });
-    var _inChange = false;
-    var _entityIDs = [];
-    var _showBlank;
-    var _maxMemberships = 1e3;
-    function getSharedParentRelations() {
-      var parents = [];
-      for (var i3 = 0; i3 < _entityIDs.length; i3++) {
-        var entity = context.graph().hasEntity(_entityIDs[i3]);
-        if (!entity)
-          continue;
-        if (i3 === 0) {
-          parents = context.graph().parentRelations(entity);
-        } else {
-          parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
-        }
-        if (!parents.length)
-          break;
-      }
-      return parents;
-    }
-    function getMemberships() {
-      var memberships = [];
-      var relations = getSharedParentRelations().slice(0, _maxMemberships);
-      var isMultiselect = _entityIDs.length > 1;
-      var i3, relation, membership, index, member, indexedMember;
-      for (i3 = 0; i3 < relations.length; i3++) {
-        relation = relations[i3];
-        membership = {
-          relation,
-          members: [],
-          hash: osmEntity.key(relation)
-        };
-        for (index = 0; index < relation.members.length; index++) {
-          member = relation.members[index];
-          if (_entityIDs.indexOf(member.id) !== -1) {
-            indexedMember = Object.assign({}, member, { index });
-            membership.members.push(indexedMember);
-            membership.hash += "," + index.toString();
-            if (!isMultiselect) {
-              memberships.push(membership);
-              membership = {
-                relation,
-                members: [],
-                hash: osmEntity.key(relation)
-              };
-            }
-          }
-        }
-        if (membership.members.length)
-          memberships.push(membership);
+  // modules/ui/view_on_osmose.js
+  function uiViewOnOsmose() {
+    let _qaItem;
+    function viewOnOsmose(selection2) {
+      let url;
+      if (services.osmose && _qaItem instanceof QAItem) {
+        url = services.osmose.itemURL(_qaItem);
       }
-      memberships.forEach(function(membership2) {
-        membership2.domId = utilUniqueDomId("membership-" + membership2.relation.id);
-        var roles = [];
-        membership2.members.forEach(function(member2) {
-          if (roles.indexOf(member2.role) === -1)
-            roles.push(member2.role);
-        });
-        membership2.role = roles.length === 1 ? roles[0] : roles;
-      });
-      return memberships;
-    }
-    function selectRelation(d3_event, d2) {
-      d3_event.preventDefault();
-      utilHighlightEntities([d2.relation.id], false, context);
-      context.enter(modeSelect(context, [d2.relation.id]));
-    }
-    function zoomToRelation(d3_event, d2) {
-      d3_event.preventDefault();
-      var entity = context.entity(d2.relation.id);
-      context.map().zoomToEase(entity);
-      utilHighlightEntities([d2.relation.id], true, context);
+      const link3 = selection2.selectAll(".view-on-osmose").data(url ? [url] : []);
+      link3.exit().remove();
+      const linkEnter = link3.enter().append("a").attr("class", "view-on-osmose").attr("target", "_blank").attr("rel", "noopener").attr("href", (d2) => d2).call(svgIcon("#iD-icon-out-link", "inline"));
+      linkEnter.append("span").call(_t.append("inspector.view_on_osmose"));
     }
-    function changeRole(d3_event, d2) {
-      if (d2 === 0)
-        return;
-      if (_inChange)
-        return;
-      var newRole = context.cleanRelationRole(select_default2(this).property("value"));
-      if (!newRole.trim() && typeof d2.role !== "string")
-        return;
-      var membersToUpdate = d2.members.filter(function(member) {
-        return member.role !== newRole;
-      });
-      if (membersToUpdate.length) {
-        _inChange = true;
-        context.perform(
-          function actionChangeMemberRoles(graph) {
-            membersToUpdate.forEach(function(member) {
-              var newMember = Object.assign({}, member, { role: newRole });
-              delete newMember.index;
-              graph = actionChangeMember(d2.relation.id, newMember, member.index)(graph);
-            });
-            return graph;
-          },
-          _t("operations.change_role.annotation", {
-            n: membersToUpdate.length
-          })
-        );
-        context.validator().validate();
-      }
-      _inChange = false;
+    viewOnOsmose.what = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return viewOnOsmose;
+    };
+    return viewOnOsmose;
+  }
+
+  // modules/ui/osmose_editor.js
+  function uiOsmoseEditor(context) {
+    const dispatch14 = dispatch_default("change");
+    const qaDetails = uiOsmoseDetails(context);
+    const qaHeader = uiOsmoseHeader(context);
+    let _qaItem;
+    function osmoseEditor(selection2) {
+      const header = selection2.selectAll(".header").data([0]);
+      const headerEnter = header.enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("QA.osmose.title"));
+      let body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      let editor = body.selectAll(".qa-editor").data([0]);
+      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
+      const footer = selection2.selectAll(".footer").data([0]);
+      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnOsmose(context).what(_qaItem));
     }
-    function addMembership(d2, role) {
-      this.blur();
-      _showBlank = false;
-      function actionAddMembers(relationId, ids, role2) {
-        return function(graph) {
-          for (var i3 in ids) {
-            var member = { id: ids[i3], type: graph.entity(ids[i3]).type, role: role2 };
-            graph = actionAddMember(relationId, member)(graph);
-          }
-          return graph;
-        };
-      }
-      if (d2.relation) {
-        context.perform(
-          actionAddMembers(d2.relation.id, _entityIDs, role),
-          _t("operations.add_member.annotation", {
-            n: _entityIDs.length
-          })
-        );
-        context.validator().validate();
-      } else {
-        var relation = osmRelation();
-        context.perform(
-          actionAddEntity(relation),
-          actionAddMembers(relation.id, _entityIDs, role),
-          _t("operations.add.annotation.relation")
-        );
-        context.enter(modeSelect(context, [relation.id]).newFeature(true));
-      }
+    function osmoseSaveSection(selection2) {
+      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
+      const isShown = _qaItem && isSelected;
+      let saveSection = selection2.selectAll(".qa-save").data(
+        isShown ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      saveSection.exit().remove();
+      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
+      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
     }
-    function downloadMembers(d3_event, d2) {
-      d3_event.preventDefault();
-      const button = select_default2(this);
-      button.classed("loading", true);
-      context.loadEntity(d2.relation.id, function() {
-        section.reRender();
+    function qaSaveButtons(selection2) {
+      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
+      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d2) => d2.status + d2.id);
+      buttonSection.exit().remove();
+      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
+      buttonEnter.append("button").attr("class", "button close-button action");
+      buttonEnter.append("button").attr("class", "button ignore-button action");
+      buttonSection = buttonSection.merge(buttonEnter);
+      buttonSection.select(".close-button").call(_t.append("QA.keepRight.close")).on("click.close", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.osmose;
+        if (qaService) {
+          d2.newStatus = "done";
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
+        }
       });
-    }
-    function deleteMembership(d3_event, d2) {
-      this.blur();
-      if (d2 === 0)
-        return;
-      utilHighlightEntities([d2.relation.id], false, context);
-      var indexes = d2.members.map(function(member) {
-        return member.index;
+      buttonSection.select(".ignore-button").call(_t.append("QA.keepRight.ignore")).on("click.ignore", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.osmose;
+        if (qaService) {
+          d2.newStatus = "false";
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
+        }
       });
-      context.perform(
-        actionDeleteMembers(d2.relation.id, indexes),
-        _t("operations.delete_member.annotation", {
-          n: _entityIDs.length
-        })
-      );
-      context.validator().validate();
     }
-    function fetchNearbyRelations(q2, callback) {
-      var newRelation = {
-        relation: null,
-        value: _t("inspector.new_relation"),
-        display: _t.append("inspector.new_relation")
-      };
-      var entityID = _entityIDs[0];
-      var result = [];
-      var graph = context.graph();
-      function baseDisplayValue(entity) {
-        var matched = _mainPresetIndex.match(entity, graph);
-        var presetName = matched && matched.name() || _t("inspector.relation");
-        var entityName = utilDisplayName(entity) || "";
-        return presetName + " " + entityName;
+    osmoseEditor.error = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return osmoseEditor;
+    };
+    return utilRebind(osmoseEditor, dispatch14, "on");
+  }
+
+  // modules/ui/sidebar.js
+  function uiSidebar(context) {
+    var inspector = uiInspector(context);
+    var dataEditor = uiDataEditor(context);
+    var noteEditor = uiNoteEditor(context);
+    var keepRightEditor = uiKeepRightEditor(context);
+    var osmoseEditor = uiOsmoseEditor(context);
+    var _current;
+    var _wasData = false;
+    var _wasNote = false;
+    var _wasQaItem = false;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function sidebar(selection2) {
+      var container = context.container();
+      var minWidth = 240;
+      var sidebarWidth;
+      var containerWidth;
+      var dragOffset;
+      selection2.style("min-width", minWidth + "px").style("max-width", "400px").style("width", "33.3333%");
+      var resizer = selection2.append("div").attr("class", "sidebar-resizer").on(_pointerPrefix + "down.sidebar-resizer", pointerdown);
+      var downPointerId, lastClientX, containerLocGetter;
+      function pointerdown(d3_event) {
+        if (downPointerId) return;
+        if ("button" in d3_event && d3_event.button !== 0) return;
+        downPointerId = d3_event.pointerId || "mouse";
+        lastClientX = d3_event.clientX;
+        containerLocGetter = utilFastMouse(container.node());
+        dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
+        sidebarWidth = selection2.node().getBoundingClientRect().width;
+        containerWidth = container.node().getBoundingClientRect().width;
+        var widthPct = sidebarWidth / containerWidth * 100;
+        selection2.style("width", widthPct + "%").style("max-width", "85%");
+        resizer.classed("dragging", true);
+        select_default2(window).on("touchmove.sidebar-resizer", function(d3_event2) {
+          d3_event2.preventDefault();
+        }, { passive: false }).on(_pointerPrefix + "move.sidebar-resizer", pointermove).on(_pointerPrefix + "up.sidebar-resizer pointercancel.sidebar-resizer", pointerup);
       }
-      function baseDisplayLabel(entity) {
-        var matched = _mainPresetIndex.match(entity, graph);
-        var presetName = matched && matched.name() || _t("inspector.relation");
-        var entityName = utilDisplayName(entity) || "";
-        return (selection2) => {
-          selection2.append("b").text(presetName + " ");
-          selection2.append("span").classed("has-colour", entity.tags.colour && isColourValid(entity.tags.colour)).style("border-color", entity.tags.colour).text(entityName);
-        };
+      function pointermove(d3_event) {
+        if (downPointerId !== (d3_event.pointerId || "mouse")) return;
+        d3_event.preventDefault();
+        var dx = d3_event.clientX - lastClientX;
+        lastClientX = d3_event.clientX;
+        var isRTL = _mainLocalizer.textDirection() === "rtl";
+        var scaleX = isRTL ? 0 : 1;
+        var xMarginProperty = isRTL ? "margin-right" : "margin-left";
+        var x2 = containerLocGetter(d3_event)[0] - dragOffset;
+        sidebarWidth = isRTL ? containerWidth - x2 : x2;
+        var isCollapsed = selection2.classed("collapsed");
+        var shouldCollapse = sidebarWidth < minWidth;
+        selection2.classed("collapsed", shouldCollapse);
+        if (shouldCollapse) {
+          if (!isCollapsed) {
+            selection2.style(xMarginProperty, "-400px").style("width", "400px");
+            context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
+          }
+        } else {
+          var widthPct = sidebarWidth / containerWidth * 100;
+          selection2.style(xMarginProperty, null).style("width", widthPct + "%");
+          if (isCollapsed) {
+            context.ui().onResize([-sidebarWidth * scaleX, 0]);
+          } else {
+            context.ui().onResize([-dx * scaleX, 0]);
+          }
+        }
       }
-      var explicitRelation = q2 && context.hasEntity(q2.toLowerCase());
-      if (explicitRelation && explicitRelation.type === "relation" && explicitRelation.id !== entityID) {
-        result.push({
-          relation: explicitRelation,
-          value: baseDisplayValue(explicitRelation) + " " + explicitRelation.id,
-          display: baseDisplayLabel(explicitRelation)
-        });
-      } else {
-        context.history().intersects(context.map().extent()).forEach(function(entity) {
-          if (entity.type !== "relation" || entity.id === entityID)
-            return;
-          var value = baseDisplayValue(entity);
-          if (q2 && (value + " " + entity.id).toLowerCase().indexOf(q2.toLowerCase()) === -1)
-            return;
-          result.push({
-            relation: entity,
-            value,
-            display: baseDisplayLabel(entity)
+      function pointerup(d3_event) {
+        if (downPointerId !== (d3_event.pointerId || "mouse")) return;
+        downPointerId = null;
+        resizer.classed("dragging", false);
+        select_default2(window).on("touchmove.sidebar-resizer", null).on(_pointerPrefix + "move.sidebar-resizer", null).on(_pointerPrefix + "up.sidebar-resizer pointercancel.sidebar-resizer", null);
+      }
+      var featureListWrap = selection2.append("div").attr("class", "feature-list-pane").call(uiFeatureList(context));
+      var inspectorWrap = selection2.append("div").attr("class", "inspector-hidden inspector-wrap");
+      var hoverModeSelect = function(targets) {
+        context.container().selectAll(".feature-list-item button").classed("hover", false);
+        if (context.selectedIDs().length > 1 && targets && targets.length) {
+          var elements = context.container().selectAll(".feature-list-item button").filter(function(node) {
+            return targets.indexOf(node) !== -1;
           });
-        });
-        result.sort(function(a2, b2) {
-          return osmRelation.creationOrder(a2.relation, b2.relation);
-        });
-        var dupeGroups = Object.values(utilArrayGroupBy(result, "value")).filter(function(v2) {
-          return v2.length > 1;
-        });
-        dupeGroups.forEach(function(group) {
-          group.forEach(function(obj) {
-            obj.value += " " + obj.relation.id;
+          if (!elements.empty()) {
+            elements.classed("hover", true);
+          }
+        }
+      };
+      sidebar.hoverModeSelect = throttle_default(hoverModeSelect, 200);
+      function hover(targets) {
+        var datum2 = targets && targets.length && targets[0];
+        if (datum2 && datum2.__featurehash__) {
+          _wasData = true;
+          sidebar.show(dataEditor.datum(datum2));
+          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
+        } else if (datum2 instanceof osmNote) {
+          if (context.mode().id === "drag-note") return;
+          _wasNote = true;
+          var osm = services.osm;
+          if (osm) {
+            datum2 = osm.getNote(datum2.id);
+          }
+          sidebar.show(noteEditor.note(datum2));
+          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
+        } else if (datum2 instanceof QAItem) {
+          _wasQaItem = true;
+          var errService = services[datum2.service];
+          if (errService) {
+            datum2 = errService.getError(datum2.id);
+          }
+          var errEditor;
+          if (datum2.service === "keepRight") {
+            errEditor = keepRightEditor;
+          } else {
+            errEditor = osmoseEditor;
+          }
+          context.container().selectAll(".qaItem." + datum2.service).classed("hover", function(d2) {
+            return d2.id === datum2.id;
           });
-        });
+          sidebar.show(errEditor.error(datum2));
+          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
+        } else if (!_current && datum2 instanceof osmEntity) {
+          featureListWrap.classed("inspector-hidden", true);
+          inspectorWrap.classed("inspector-hidden", false).classed("inspector-hover", true);
+          if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum2.id]) || inspector.state() !== "hover") {
+            inspector.state("hover").entityIDs([datum2.id]).newFeature(false);
+            inspectorWrap.call(inspector);
+          }
+        } else if (!_current) {
+          featureListWrap.classed("inspector-hidden", false);
+          inspectorWrap.classed("inspector-hidden", true);
+          inspector.state("hide");
+        } else if (_wasData || _wasNote || _wasQaItem) {
+          _wasNote = false;
+          _wasData = false;
+          _wasQaItem = false;
+          context.container().selectAll(".note").classed("hover", false);
+          context.container().selectAll(".qaItem").classed("hover", false);
+          sidebar.hide();
+        }
       }
-      result.forEach(function(obj) {
-        obj.title = obj.value;
-      });
-      result.unshift(newRelation);
-      callback(result);
-    }
-    function renderDisclosureContent(selection2) {
-      var memberships = getMemberships();
-      var list2 = selection2.selectAll(".member-list").data([0]);
-      list2 = list2.enter().append("ul").attr("class", "member-list").merge(list2);
-      var items = list2.selectAll("li.member-row-normal").data(memberships, function(d2) {
-        return d2.hash;
-      });
-      items.exit().each(unbind).remove();
-      var itemsEnter = items.enter().append("li").attr("class", "member-row member-row-normal form-field");
-      itemsEnter.on("mouseover", function(d3_event, d2) {
-        utilHighlightEntities([d2.relation.id], true, context);
-      }).on("mouseout", function(d3_event, d2) {
-        utilHighlightEntities([d2.relation.id], false, context);
+      sidebar.hover = throttle_default(hover, 200);
+      sidebar.intersects = function(extent) {
+        var rect = selection2.node().getBoundingClientRect();
+        return extent.intersects([
+          context.projection.invert([0, rect.height]),
+          context.projection.invert([rect.width, 0])
+        ]);
+      };
+      sidebar.select = function(ids, newFeature) {
+        sidebar.hide();
+        if (ids && ids.length) {
+          var entity = ids.length === 1 && context.entity(ids[0]);
+          if (entity && newFeature && selection2.classed("collapsed")) {
+            var extent = entity.extent(context.graph());
+            sidebar.expand(sidebar.intersects(extent));
+          }
+          featureListWrap.classed("inspector-hidden", true);
+          inspectorWrap.classed("inspector-hidden", false).classed("inspector-hover", false);
+          inspector.state("select").entityIDs(ids).newFeature(newFeature);
+          inspectorWrap.call(inspector);
+        } else {
+          inspector.state("hide");
+        }
+      };
+      sidebar.showPresetList = function() {
+        inspector.showList();
+      };
+      sidebar.show = function(component, element) {
+        featureListWrap.classed("inspector-hidden", true);
+        inspectorWrap.classed("inspector-hidden", true);
+        if (_current) _current.remove();
+        _current = selection2.append("div").attr("class", "sidebar-component").call(component, element);
+      };
+      sidebar.hide = function() {
+        featureListWrap.classed("inspector-hidden", false);
+        inspectorWrap.classed("inspector-hidden", true);
+        if (_current) _current.remove();
+        _current = null;
+      };
+      sidebar.expand = function(moveMap) {
+        if (selection2.classed("collapsed")) {
+          sidebar.toggle(moveMap);
+        }
+      };
+      sidebar.collapse = function(moveMap) {
+        if (!selection2.classed("collapsed")) {
+          sidebar.toggle(moveMap);
+        }
+      };
+      sidebar.toggle = function(moveMap) {
+        if (context.inIntro()) return;
+        var isCollapsed = selection2.classed("collapsed");
+        var isCollapsing = !isCollapsed;
+        var isRTL = _mainLocalizer.textDirection() === "rtl";
+        var scaleX = isRTL ? 0 : 1;
+        var xMarginProperty = isRTL ? "margin-right" : "margin-left";
+        sidebarWidth = selection2.node().getBoundingClientRect().width;
+        selection2.style("width", sidebarWidth + "px");
+        var startMargin, endMargin, lastMargin;
+        if (isCollapsing) {
+          startMargin = lastMargin = 0;
+          endMargin = -sidebarWidth;
+        } else {
+          startMargin = lastMargin = -sidebarWidth;
+          endMargin = 0;
+        }
+        if (!isCollapsing) {
+          selection2.classed("collapsed", isCollapsing);
+        }
+        selection2.transition().style(xMarginProperty, endMargin + "px").tween("panner", function() {
+          var i3 = number_default(startMargin, endMargin);
+          return function(t2) {
+            var dx = lastMargin - Math.round(i3(t2));
+            lastMargin = lastMargin - dx;
+            context.ui().onResize(moveMap ? void 0 : [dx * scaleX, 0]);
+          };
+        }).on("end", function() {
+          if (isCollapsing) {
+            selection2.classed("collapsed", isCollapsing);
+          }
+          if (!isCollapsing) {
+            var containerWidth2 = container.node().getBoundingClientRect().width;
+            var widthPct = sidebarWidth / containerWidth2 * 100;
+            selection2.style(xMarginProperty, null).style("width", widthPct + "%");
+          }
+        });
+      };
+      resizer.on("dblclick", function(d3_event) {
+        d3_event.preventDefault();
+        if (d3_event.sourceEvent) {
+          d3_event.sourceEvent.preventDefault();
+        }
+        sidebar.toggle();
       });
-      var labelEnter = itemsEnter.append("label").attr("class", "field-label").attr("for", function(d2) {
-        return d2.domId;
+      context.map().on("crossEditableZoom.sidebar", function(within) {
+        if (!within && !selection2.select(".inspector-hover").empty()) {
+          hover([]);
+        }
       });
-      var labelLink = labelEnter.append("span").attr("class", "label-text").append("a").attr("href", "#").on("click", selectRelation);
-      labelLink.append("span").attr("class", "member-entity-type").text(function(d2) {
-        var matched = _mainPresetIndex.match(d2.relation, context.graph());
-        return matched && matched.name() || _t.html("inspector.relation");
-      });
-      labelLink.append("span").attr("class", "member-entity-name").classed("has-colour", (d2) => d2.relation.tags.colour && isColourValid(d2.relation.tags.colour)).style("border-color", (d2) => d2.relation.tags.colour).text(function(d2) {
-        return utilDisplayName(d2.relation);
-      });
-      labelEnter.append("button").attr("class", "members-download").attr("title", _t("icons.download")).call(svgIcon("#iD-icon-load")).on("click", downloadMembers);
-      labelEnter.append("button").attr("class", "remove member-delete").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete")).on("click", deleteMembership);
-      labelEnter.append("button").attr("class", "member-zoom").attr("title", _t("icons.zoom_to")).call(svgIcon("#iD-icon-framed-dot", "monochrome")).on("click", zoomToRelation);
-      items = items.merge(itemsEnter);
-      items.selectAll("button.members-download").classed("hide", (d2) => {
-        const graph = context.graph();
-        return d2.relation.members.every((m2) => graph.hasEntity(m2.id));
-      });
-      var wrapEnter = itemsEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
-      wrapEnter.append("input").attr("class", "member-role").attr("id", function(d2) {
-        return d2.domId;
-      }).property("type", "text").property("value", function(d2) {
-        return typeof d2.role === "string" ? d2.role : "";
-      }).attr("title", function(d2) {
-        return Array.isArray(d2.role) ? d2.role.filter(Boolean).join("\n") : d2.role;
-      }).attr("placeholder", function(d2) {
-        return Array.isArray(d2.role) ? _t("inspector.multiple_roles") : _t("inspector.role");
-      }).classed("mixed", function(d2) {
-        return Array.isArray(d2.role);
-      }).call(utilNoAuto).on("blur", changeRole).on("change", changeRole);
-      if (taginfo) {
-        wrapEnter.each(bindTypeahead);
-      }
-      var newMembership = list2.selectAll(".member-row-new").data(_showBlank ? [0] : []);
-      newMembership.exit().remove();
-      var newMembershipEnter = newMembership.enter().append("li").attr("class", "member-row member-row-new form-field");
-      var newLabelEnter = newMembershipEnter.append("label").attr("class", "field-label");
-      newLabelEnter.append("input").attr("placeholder", _t("inspector.choose_relation")).attr("type", "text").attr("class", "member-entity-input").call(utilNoAuto);
-      newLabelEnter.append("button").attr("class", "remove member-delete").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete")).on("click", function() {
-        list2.selectAll(".member-row-new").remove();
-      });
-      var newWrapEnter = newMembershipEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
-      newWrapEnter.append("input").attr("class", "member-role").property("type", "text").attr("placeholder", _t("inspector.role")).call(utilNoAuto);
-      newMembership = newMembership.merge(newMembershipEnter);
-      newMembership.selectAll(".member-entity-input").on("blur", cancelEntity).call(
-        nearbyCombo.on("accept", acceptEntity).on("cancel", cancelEntity)
-      );
-      var addRow = selection2.selectAll(".add-row").data([0]);
-      var addRowEnter = addRow.enter().append("div").attr("class", "add-row");
-      var addRelationButton = addRowEnter.append("button").attr("class", "add-relation").attr("aria-label", _t("inspector.add_to_relation"));
-      addRelationButton.call(svgIcon("#iD-icon-plus", "light"));
-      addRelationButton.call(uiTooltip().title(() => _t.append("inspector.add_to_relation")).placement(_mainLocalizer.textDirection() === "ltr" ? "right" : "left"));
-      addRowEnter.append("div").attr("class", "space-value");
-      addRowEnter.append("div").attr("class", "space-buttons");
-      addRow = addRow.merge(addRowEnter);
-      addRow.select(".add-relation").on("click", function() {
-        _showBlank = true;
-        section.reRender();
-        list2.selectAll(".member-entity-input").node().focus();
-      });
-      function acceptEntity(d2) {
-        if (!d2) {
-          cancelEntity();
-          return;
-        }
-        if (d2.relation)
-          utilHighlightEntities([d2.relation.id], false, context);
-        var role = context.cleanRelationRole(list2.selectAll(".member-row-new .member-role").property("value"));
-        addMembership(d2, role);
-      }
-      function cancelEntity() {
-        var input = newMembership.selectAll(".member-entity-input");
-        input.property("value", "");
-        context.surface().selectAll(".highlighted").classed("highlighted", false);
-      }
-      function bindTypeahead(d2) {
-        var row = select_default2(this);
-        var role = row.selectAll("input.member-role");
-        var origValue = role.property("value");
-        function sort(value, data) {
-          var sameletter = [];
-          var other = [];
-          for (var i3 = 0; i3 < data.length; i3++) {
-            if (data[i3].value.substring(0, value.length) === value) {
-              sameletter.push(data[i3]);
-            } else {
-              other.push(data[i3]);
-            }
-          }
-          return sameletter.concat(other);
-        }
-        role.call(
-          uiCombobox(context, "member-role").fetcher(function(role2, callback) {
-            var rtype = d2.relation.tags.type;
-            taginfo.roles({
-              debounce: true,
-              rtype: rtype || "",
-              geometry: context.graph().geometry(_entityIDs[0]),
-              query: role2
-            }, function(err, data) {
-              if (!err)
-                callback(sort(role2, data));
-            });
-          }).on("cancel", function() {
-            role.property("value", origValue);
-          })
-        );
-      }
-      function unbind() {
-        var row = select_default2(this);
-        row.selectAll("input.member-role").call(uiCombobox.off, context);
-      }
     }
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      _showBlank = false;
-      return section;
+    sidebar.showPresetList = function() {
     };
-    return section;
+    sidebar.hover = function() {
+    };
+    sidebar.hover.cancel = function() {
+    };
+    sidebar.intersects = function() {
+    };
+    sidebar.select = function() {
+    };
+    sidebar.show = function() {
+    };
+    sidebar.hide = function() {
+    };
+    sidebar.expand = function() {
+    };
+    sidebar.collapse = function() {
+    };
+    sidebar.toggle = function() {
+    };
+    return sidebar;
   }
 
-  // modules/ui/sections/selection_list.js
-  function uiSectionSelectionList(context) {
-    var _selectedIDs = [];
-    var section = uiSection("selected-features", context).shouldDisplay(function() {
-      return _selectedIDs.length > 1;
-    }).label(function() {
-      return _t.append("inspector.title_count", { title: _t("inspector.features"), count: _selectedIDs.length });
-    }).disclosureContent(renderDisclosureContent);
-    context.history().on("change.selectionList", function(difference2) {
-      if (difference2) {
-        section.reRender();
-      }
-    });
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _selectedIDs;
-      _selectedIDs = val;
-      return section;
-    };
-    function selectEntity(d3_event, entity) {
-      context.enter(modeSelect(context, [entity.id]));
+  // modules/ui/source_switch.js
+  function uiSourceSwitch(context) {
+    var keys2;
+    function click(d3_event) {
+      d3_event.preventDefault();
+      var osm = context.connection();
+      if (!osm) return;
+      if (context.inIntro()) return;
+      if (context.history().hasChanges() && !window.confirm(_t("source_switch.lose_changes"))) return;
+      var isLive = select_default2(this).classed("live");
+      isLive = !isLive;
+      context.enter(modeBrowse(context));
+      context.history().clearSaved();
+      context.flush();
+      select_default2(this).html(isLive ? _t.html("source_switch.live") : _t.html("source_switch.dev")).classed("live", isLive).classed("chip", isLive);
+      osm.switch(isLive ? keys2[0] : keys2[1]);
     }
-    function deselectEntity(d3_event, entity) {
-      var selectedIDs = _selectedIDs.slice();
-      var index = selectedIDs.indexOf(entity.id);
-      if (index > -1) {
-        selectedIDs.splice(index, 1);
-        context.enter(modeSelect(context, selectedIDs));
+    var sourceSwitch = function(selection2) {
+      selection2.append("a").attr("href", "#").call(_t.append("source_switch.live")).attr("class", "live chip").on("click", click);
+    };
+    sourceSwitch.keys = function(_2) {
+      if (!arguments.length) return keys2;
+      keys2 = _2;
+      return sourceSwitch;
+    };
+    return sourceSwitch;
+  }
+
+  // modules/ui/spinner.js
+  function uiSpinner(context) {
+    var osm = context.connection();
+    return function(selection2) {
+      var img = selection2.append("img").attr("src", context.imagePath("loader-black.gif")).style("opacity", 0);
+      if (osm) {
+        osm.on("loading.spinner", function() {
+          img.transition().style("opacity", 1);
+        }).on("loaded.spinner", function() {
+          img.transition().style("opacity", 0);
+        });
       }
-    }
+    };
+  }
+
+  // modules/ui/sections/privacy.js
+  function uiSectionPrivacy(context) {
+    let section = uiSection("preferences-third-party", context).label(() => _t.append("preferences.privacy.title")).disclosureContent(renderDisclosureContent);
     function renderDisclosureContent(selection2) {
-      var list2 = selection2.selectAll(".feature-list").data([0]);
-      list2 = list2.enter().append("ul").attr("class", "feature-list").merge(list2);
-      var entities = _selectedIDs.map(function(id2) {
-        return context.hasEntity(id2);
-      }).filter(Boolean);
-      var items = list2.selectAll(".feature-list-item").data(entities, osmEntity.key);
-      items.exit().remove();
-      var enter = items.enter().append("li").attr("class", "feature-list-item").each(function(d2) {
-        select_default2(this).on("mouseover", function() {
-          utilHighlightEntities([d2.id], true, context);
-        }).on("mouseout", function() {
-          utilHighlightEntities([d2.id], false, context);
-        });
-      });
-      var label = enter.append("button").attr("class", "label").on("click", selectEntity);
-      label.append("span").attr("class", "entity-geom-icon").call(svgIcon("", "pre-text"));
-      label.append("span").attr("class", "entity-type");
-      label.append("span").attr("class", "entity-name");
-      enter.append("button").attr("class", "close").attr("title", _t("icons.deselect")).on("click", deselectEntity).call(svgIcon("#iD-icon-close"));
-      items = items.merge(enter);
-      items.selectAll(".entity-geom-icon use").attr("href", function() {
-        var entity = this.parentNode.parentNode.__data__;
-        return "#iD-icon-" + entity.geometry(context.graph());
-      });
-      items.selectAll(".entity-type").text(function(entity) {
-        return _mainPresetIndex.match(entity, context.graph()).name();
-      });
-      items.selectAll(".entity-name").text(function(d2) {
-        var entity = context.entity(d2.id);
-        return utilDisplayName(entity);
+      selection2.selectAll(".privacy-options-list").data([0]).enter().append("ul").attr("class", "layer-list privacy-options-list");
+      let thirdPartyIconsEnter = selection2.select(".privacy-options-list").selectAll(".privacy-third-party-icons-item").data([corePreferences("preferences.privacy.thirdpartyicons") || "true"]).enter().append("li").attr("class", "privacy-third-party-icons-item").append("label").call(
+        uiTooltip().title(() => _t.append("preferences.privacy.third_party_icons.tooltip")).placement("bottom")
+      );
+      thirdPartyIconsEnter.append("input").attr("type", "checkbox").on("change", (d3_event, d2) => {
+        d3_event.preventDefault();
+        corePreferences("preferences.privacy.thirdpartyicons", d2 === "true" ? "false" : "true");
       });
+      thirdPartyIconsEnter.append("span").call(_t.append("preferences.privacy.third_party_icons.description"));
+      selection2.selectAll(".privacy-third-party-icons-item").classed("active", (d2) => d2 === "true").select("input").property("checked", (d2) => d2 === "true");
+      selection2.selectAll(".privacy-link").data([0]).enter().append("div").attr("class", "privacy-link").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/openstreetmap/iD/blob/release/PRIVACY.md").append("span").call(_t.append("preferences.privacy.privacy_link"));
     }
+    corePreferences.onChange("preferences.privacy.thirdpartyicons", section.reRender);
     return section;
   }
 
-  // modules/ui/entity_editor.js
-  function uiEntityEditor(context) {
-    var dispatch14 = dispatch_default("choose");
-    var _state = "select";
-    var _coalesceChanges = false;
-    var _modified = false;
-    var _base;
-    var _entityIDs;
-    var _activePresets = [];
-    var _newFeature;
-    var _sections;
-    function entityEditor(selection2) {
-      var combinedTags = utilCombinedTags(_entityIDs, context.graph());
-      var header = selection2.selectAll(".header").data([0]);
-      var headerEnter = header.enter().append("div").attr("class", "header fillL");
-      var direction = _mainLocalizer.textDirection() === "rtl" ? "forward" : "backward";
-      headerEnter.append("button").attr("class", "preset-reset preset-choose").attr("title", _t("inspector.back_tooltip")).call(svgIcon("#iD-icon-".concat(direction)));
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
-        context.enter(modeBrowse(context));
-      }).call(svgIcon(_modified ? "#iD-icon-apply" : "#iD-icon-close"));
-      headerEnter.append("h2");
-      header = header.merge(headerEnter);
-      header.selectAll("h2").text("").call(_entityIDs.length === 1 ? _t.append("inspector.edit") : _t.append("inspector.edit_features"));
-      header.selectAll(".preset-reset").on("click", function() {
-        dispatch14.call("choose", this, _activePresets);
-      });
-      var body = selection2.selectAll(".inspector-body").data([0]);
-      var bodyEnter = body.enter().append("div").attr("class", "entity-editor inspector-body sep-top");
-      body = body.merge(bodyEnter);
-      if (!_sections) {
-        _sections = [
-          uiSectionSelectionList(context),
-          uiSectionFeatureType(context).on("choose", function(presets) {
-            dispatch14.call("choose", this, presets);
-          }),
-          uiSectionEntityIssues(context),
-          uiSectionPresetFields(context).on("change", changeTags).on("revert", revertTags),
-          uiSectionRawTagEditor("raw-tag-editor", context).on("change", changeTags),
-          uiSectionRawMemberEditor(context),
-          uiSectionRawMembershipEditor(context)
-        ];
+  // modules/ui/splash.js
+  function uiSplash(context) {
+    return (selection2) => {
+      if (context.history().hasRestorableChanges()) return;
+      let updateMessage = "";
+      const sawPrivacyVersion = corePreferences("sawPrivacyVersion");
+      let showSplash = !corePreferences("sawSplash");
+      if (sawPrivacyVersion !== context.privacyVersion) {
+        updateMessage = _t("splash.privacy_update");
+        showSplash = true;
       }
-      _sections.forEach(function(section) {
-        if (section.entityIDs) {
-          section.entityIDs(_entityIDs);
-        }
-        if (section.presets) {
-          section.presets(_activePresets);
-        }
-        if (section.tags) {
-          section.tags(combinedTags);
-        }
-        if (section.state) {
-          section.state(_state);
-        }
-        body.call(section.render);
+      if (!showSplash) return;
+      corePreferences("sawSplash", true);
+      corePreferences("sawPrivacyVersion", context.privacyVersion);
+      _mainFileFetcher.get("intro_graph");
+      let modalSelection = uiModal(selection2);
+      modalSelection.select(".modal").attr("class", "modal-splash modal");
+      let introModal = modalSelection.select(".content").append("div").attr("class", "fillL");
+      introModal.append("div").attr("class", "modal-section").append("h3").call(_t.append("splash.welcome"));
+      let modalSection = introModal.append("div").attr("class", "modal-section");
+      modalSection.append("p").html(_t.html("splash.text", {
+        version: context.version,
+        website: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/develop/CHANGELOG.md#whats-new">' + _t.html("splash.changelog") + "</a>" },
+        github: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/issues">github.com</a>' }
+      }));
+      modalSection.append("p").html(_t.html("splash.privacy", {
+        updateMessage,
+        privacyLink: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t("splash.privacy_policy") + "</a>" }
+      }));
+      uiSectionPrivacy(context).label(() => _t.append("splash.privacy_settings")).render(modalSection);
+      let buttonWrap = introModal.append("div").attr("class", "modal-actions");
+      let walkthrough = buttonWrap.append("button").attr("class", "walkthrough").on("click", () => {
+        context.container().call(uiIntro(context));
+        modalSelection.close();
       });
-      context.history().on("change.entity-editor", historyChanged);
-      function historyChanged(difference2) {
-        if (selection2.selectAll(".entity-editor").empty())
-          return;
-        if (_state === "hide")
-          return;
-        var significant = !difference2 || difference2.didChange.properties || difference2.didChange.addition || difference2.didChange.deletion;
-        if (!significant)
-          return;
-        _entityIDs = _entityIDs.filter(context.hasEntity);
-        if (!_entityIDs.length)
-          return;
-        var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
-        loadActivePresets();
-        var graph = context.graph();
-        entityEditor.modified(_base !== graph);
-        entityEditor(selection2);
-        if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
-          context.container().selectAll(".entity-editor button.preset-reset .label").style("background-color", "#fff").transition().duration(750).style("background-color", null);
-        }
-      }
-    }
-    function changeTags(entityIDs, changed, onInput) {
-      var actions = [];
-      for (var i3 in entityIDs) {
-        var entityID = entityIDs[i3];
-        var entity = context.entity(entityID);
-        var tags = Object.assign({}, entity.tags);
-        if (typeof changed === "function") {
-          tags = changed(tags);
-        } else {
-          for (var k2 in changed) {
-            if (!k2)
-              continue;
-            var v2 = changed[k2];
-            if (typeof v2 === "object") {
-              tags[k2] = tags[v2.oldKey];
-            } else if (v2 !== void 0 || tags.hasOwnProperty(k2)) {
-              tags[k2] = v2;
-            }
-          }
-        }
-        if (!onInput) {
-          tags = utilCleanTags(tags);
-        }
-        if (!(0, import_fast_deep_equal10.default)(entity.tags, tags)) {
-          actions.push(actionChangeTags(entityID, tags));
-        }
-      }
-      if (actions.length) {
-        var combinedAction = function(graph) {
-          actions.forEach(function(action) {
-            graph = action(graph);
-          });
-          return graph;
-        };
-        var annotation = _t("operations.change_tags.annotation");
-        if (_coalesceChanges) {
-          context.overwrite(combinedAction, annotation);
-        } else {
-          context.perform(combinedAction, annotation);
-          _coalesceChanges = !!onInput;
-        }
-      }
-      if (!onInput) {
-        context.validator().validate();
-      }
-    }
-    function revertTags(keys2) {
-      var actions = [];
-      for (var i3 in _entityIDs) {
-        var entityID = _entityIDs[i3];
-        var original = context.graph().base().entities[entityID];
-        var changed = {};
-        for (var j2 in keys2) {
-          var key = keys2[j2];
-          changed[key] = original ? original.tags[key] : void 0;
-        }
-        var entity = context.entity(entityID);
-        var tags = Object.assign({}, entity.tags);
-        for (var k2 in changed) {
-          if (!k2)
-            continue;
-          var v2 = changed[k2];
-          if (v2 !== void 0 || tags.hasOwnProperty(k2)) {
-            tags[k2] = v2;
+      walkthrough.append("svg").attr("class", "logo logo-walkthrough").append("use").attr("xlink:href", "#iD-logo-walkthrough");
+      walkthrough.append("div").call(_t.append("splash.walkthrough"));
+      let startEditing = buttonWrap.append("button").attr("class", "start-editing").on("click", modalSelection.close);
+      startEditing.append("svg").attr("class", "logo logo-features").append("use").attr("xlink:href", "#iD-logo-features");
+      startEditing.append("div").call(_t.append("splash.start"));
+      modalSelection.select("button.close").attr("class", "hide");
+    };
+  }
+
+  // modules/ui/status.js
+  function uiStatus(context) {
+    var osm = context.connection();
+    return function(selection2) {
+      if (!osm) return;
+      function update(err, apiStatus) {
+        selection2.html("");
+        if (err) {
+          if (apiStatus === "connectionSwitched") {
+            return;
+          } else if (apiStatus === "rateLimited") {
+            selection2.call(_t.append("osm_api_status.message.rateLimit")).append("a").attr("href", "#").attr("class", "api-status-login").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("login")).on("click.login", function(d3_event) {
+              d3_event.preventDefault();
+              osm.authenticate();
+            });
+          } else {
+            var throttledRetry = throttle_default(function() {
+              context.loadTiles(context.projection);
+              osm.reloadApiStatus();
+            }, 2e3);
+            selection2.call(_t.append("osm_api_status.message.error", { suffix: " " })).append("a").attr("href", "#").call(_t.append("osm_api_status.retry")).on("click.retry", function(d3_event) {
+              d3_event.preventDefault();
+              throttledRetry();
+            });
           }
+        } else if (apiStatus === "readonly") {
+          selection2.call(_t.append("osm_api_status.message.readonly"));
+        } else if (apiStatus === "offline") {
+          selection2.call(_t.append("osm_api_status.message.offline"));
         }
-        tags = utilCleanTags(tags);
-        if (!(0, import_fast_deep_equal10.default)(entity.tags, tags)) {
-          actions.push(actionChangeTags(entityID, tags));
-        }
-      }
-      if (actions.length) {
-        var combinedAction = function(graph) {
-          actions.forEach(function(action) {
-            graph = action(graph);
-          });
-          return graph;
-        };
-        var annotation = _t("operations.change_tags.annotation");
-        if (_coalesceChanges) {
-          context.overwrite(combinedAction, annotation);
-        } else {
-          context.perform(combinedAction, annotation);
-          _coalesceChanges = false;
-        }
-      }
-      context.validator().validate();
-    }
-    entityEditor.modified = function(val) {
-      if (!arguments.length)
-        return _modified;
-      _modified = val;
-      return entityEditor;
-    };
-    entityEditor.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      _state = val;
-      return entityEditor;
-    };
-    entityEditor.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _base = context.graph();
-      _coalesceChanges = false;
-      if (val && _entityIDs && utilArrayIdentical(_entityIDs, val))
-        return entityEditor;
-      _entityIDs = val;
-      loadActivePresets(true);
-      return entityEditor.modified(false);
-    };
-    entityEditor.newFeature = function(val) {
-      if (!arguments.length)
-        return _newFeature;
-      _newFeature = val;
-      return entityEditor;
-    };
-    function loadActivePresets(isForNewSelection) {
-      var graph = context.graph();
-      var counts = {};
-      for (var i3 in _entityIDs) {
-        var entity = graph.hasEntity(_entityIDs[i3]);
-        if (!entity)
-          return;
-        var match = _mainPresetIndex.match(entity, graph);
-        if (!counts[match.id])
-          counts[match.id] = 0;
-        counts[match.id] += 1;
+        selection2.attr("class", "api-status " + (err ? "error" : apiStatus));
       }
-      var matches = Object.keys(counts).sort(function(p1, p2) {
-        return counts[p2] - counts[p1];
-      }).map(function(pID) {
-        return _mainPresetIndex.item(pID);
+      osm.on("apiStatusChange.uiStatus", update);
+      context.history().on("storage_error", () => {
+        selection2.selectAll("span.local-storage-full").remove();
+        selection2.append("span").attr("class", "local-storage-full").call(_t.append("osm_api_status.message.local_storage_full"));
+        selection2.classed("error", true);
       });
-      if (!isForNewSelection) {
-        var weakPreset = _activePresets.length === 1 && !_activePresets[0].isFallback() && Object.keys(_activePresets[0].addTags || {}).length === 0;
-        if (weakPreset && matches.length === 1 && matches[0].isFallback())
-          return;
-      }
-      entityEditor.presets(matches);
-    }
-    entityEditor.presets = function(val) {
-      if (!arguments.length)
-        return _activePresets;
-      if (!utilArrayIdentical(val, _activePresets)) {
-        _activePresets = val;
-      }
-      return entityEditor;
+      window.setInterval(function() {
+        osm.reloadApiStatus();
+      }, 9e4);
+      osm.reloadApiStatus();
     };
-    return utilRebind(entityEditor, dispatch14, "on");
   }
 
-  // modules/ui/feature_list.js
-  var sexagesimal = __toESM(require_sexagesimal());
-
-  // modules/modes/draw_area.js
-  function modeDrawArea(context, wayID, startGraph, button) {
-    var mode = {
-      button,
-      id: "draw-area"
-    };
-    var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on("rejectedSelfIntersection.modeDrawArea", function() {
-      context.ui().flash.iconName("#iD-icon-no").label(_t.append("self_intersection.error.areas"))();
-    });
-    mode.wayID = wayID;
-    mode.enter = function() {
-      context.install(behavior);
-    };
-    mode.exit = function() {
-      context.uninstall(behavior);
-    };
-    mode.selectedIDs = function() {
-      return [wayID];
-    };
-    mode.activeID = function() {
-      return behavior && behavior.activeID() || [];
+  // modules/ui/tools/modes.js
+  function uiToolDrawModes(context) {
+    var tool = {
+      id: "old_modes",
+      label: _t.append("toolbar.add_feature")
     };
-    return mode;
-  }
-
-  // modules/modes/add_area.js
-  function modeAddArea(context, mode) {
-    mode.id = "add-area";
-    var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
-    function defaultTags(loc) {
-      var defaultTags2 = { area: "yes" };
-      if (mode.preset)
-        defaultTags2 = mode.preset.setTags(defaultTags2, "area", false, loc);
-      return defaultTags2;
-    }
-    function actionClose(wayId) {
-      return function(graph) {
-        return graph.replace(graph.entity(wayId).close());
-      };
-    }
-    function start2(loc) {
-      var startGraph = context.graph();
-      var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags(loc) });
-      context.perform(
-        actionAddEntity(node),
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id),
-        actionClose(way.id)
-      );
-      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
-    }
-    function startFromWay(loc, edge) {
-      var startGraph = context.graph();
-      var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags(loc) });
-      context.perform(
-        actionAddEntity(node),
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id),
-        actionClose(way.id),
-        actionAddMidpoint({ loc, edge }, node)
-      );
-      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    var modes = [
+      modeAddPoint(context, {
+        title: _t.append("modes.add_point.title"),
+        button: "point",
+        description: _t.append("modes.add_point.description"),
+        preset: _mainPresetIndex.item("point"),
+        key: "1"
+      }),
+      modeAddLine(context, {
+        title: _t.append("modes.add_line.title"),
+        button: "line",
+        description: _t.append("modes.add_line.description"),
+        preset: _mainPresetIndex.item("line"),
+        key: "2"
+      }),
+      modeAddArea(context, {
+        title: _t.append("modes.add_area.title"),
+        button: "area",
+        description: _t.append("modes.add_area.description"),
+        preset: _mainPresetIndex.item("area"),
+        key: "3"
+      })
+    ];
+    function enabled(_mode) {
+      return osmEditable();
     }
-    function startFromNode(node) {
-      var startGraph = context.graph();
-      var way = osmWay({ tags: defaultTags(node.loc) });
-      context.perform(
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id),
-        actionClose(way.id)
-      );
-      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    function osmEditable() {
+      return context.editable();
     }
-    mode.enter = function() {
-      context.install(behavior);
-    };
-    mode.exit = function() {
-      context.uninstall(behavior);
+    modes.forEach(function(mode) {
+      context.keybinding().on(mode.key, function() {
+        if (!enabled(mode)) return;
+        if (mode.id === context.mode().id) {
+          context.enter(modeBrowse(context));
+        } else {
+          context.enter(mode);
+        }
+      });
+    });
+    tool.render = function(selection2) {
+      var wrap2 = selection2.append("div").attr("class", "joined").style("display", "flex");
+      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
+      context.map().on("move.modes", debouncedUpdate).on("drawn.modes", debouncedUpdate);
+      context.on("enter.modes", update);
+      update();
+      function update() {
+        var buttons = wrap2.selectAll("button.add-button").data(modes, function(d2) {
+          return d2.id;
+        });
+        buttons.exit().remove();
+        var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
+          return d2.id + " add-button bar-button";
+        }).on("click.mode-buttons", function(d3_event, d2) {
+          if (!enabled(d2)) return;
+          var currMode = context.mode().id;
+          if (/^draw/.test(currMode)) return;
+          if (d2.id === currMode) {
+            context.enter(modeBrowse(context));
+          } else {
+            context.enter(d2);
+          }
+        }).call(
+          uiTooltip().placement("bottom").title(function(d2) {
+            return d2.description;
+          }).keys(function(d2) {
+            return [d2.key];
+          }).scrollContainer(context.container().select(".top-toolbar"))
+        );
+        buttonsEnter.each(function(d2) {
+          select_default2(this).call(svgIcon("#iD-icon-" + d2.button));
+        });
+        buttonsEnter.append("span").attr("class", "label").text("").each(function(mode) {
+          mode.title(select_default2(this));
+        });
+        if (buttons.enter().size() || buttons.exit().size()) {
+          context.ui().checkOverflow(".top-toolbar", true);
+        }
+        buttons = buttons.merge(buttonsEnter).attr("aria-disabled", function(d2) {
+          return !enabled(d2);
+        }).classed("disabled", function(d2) {
+          return !enabled(d2);
+        }).attr("aria-pressed", function(d2) {
+          return context.mode() && context.mode().button === d2.button;
+        }).classed("active", function(d2) {
+          return context.mode() && context.mode().button === d2.button;
+        });
+      }
     };
-    return mode;
+    return tool;
   }
 
-  // modules/modes/add_line.js
-  function modeAddLine(context, mode) {
-    mode.id = "add-line";
-    var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
-    function defaultTags(loc) {
-      var defaultTags2 = {};
-      if (mode.preset)
-        defaultTags2 = mode.preset.setTags(defaultTags2, "line", false, loc);
-      return defaultTags2;
-    }
-    function start2(loc) {
-      var startGraph = context.graph();
-      var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags(loc) });
-      context.perform(
-        actionAddEntity(node),
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id)
-      );
-      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+  // modules/ui/tools/notes.js
+  function uiToolNotes(context) {
+    var tool = {
+      id: "notes",
+      label: _t.append("modes.add_note.label")
+    };
+    var mode = modeAddNote(context);
+    function enabled() {
+      return notesEnabled() && notesEditable();
     }
-    function startFromWay(loc, edge) {
-      var startGraph = context.graph();
-      var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags(loc) });
-      context.perform(
-        actionAddEntity(node),
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id),
-        actionAddMidpoint({ loc, edge }, node)
-      );
-      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+    function notesEnabled() {
+      var noteLayer = context.layers().layer("notes");
+      return noteLayer && noteLayer.enabled();
     }
-    function startFromNode(node) {
-      var startGraph = context.graph();
-      var way = osmWay({ tags: defaultTags(node.loc) });
-      context.perform(
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id)
-      );
-      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+    function notesEditable() {
+      var mode2 = context.mode();
+      return context.map().notesEditable() && mode2 && mode2.id !== "save";
     }
-    mode.enter = function() {
-      context.install(behavior);
+    context.keybinding().on(mode.key, function() {
+      if (!enabled()) return;
+      if (mode.id === context.mode().id) {
+        context.enter(modeBrowse(context));
+      } else {
+        context.enter(mode);
+      }
+    });
+    tool.render = function(selection2) {
+      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
+      context.map().on("move.notes", debouncedUpdate).on("drawn.notes", debouncedUpdate);
+      context.on("enter.notes", update);
+      update();
+      function update() {
+        var showNotes = notesEnabled();
+        var data = showNotes ? [mode] : [];
+        var buttons = selection2.selectAll("button.add-button").data(data, function(d2) {
+          return d2.id;
+        });
+        buttons.exit().remove();
+        var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
+          return d2.id + " add-button bar-button";
+        }).on("click.notes", function(d3_event, d2) {
+          if (!enabled()) return;
+          var currMode = context.mode().id;
+          if (/^draw/.test(currMode)) return;
+          if (d2.id === currMode) {
+            context.enter(modeBrowse(context));
+          } else {
+            context.enter(d2);
+          }
+        }).call(
+          uiTooltip().placement("bottom").title(function(d2) {
+            return d2.description;
+          }).keys(function(d2) {
+            return [d2.key];
+          }).scrollContainer(context.container().select(".top-toolbar"))
+        );
+        buttonsEnter.each(function(d2) {
+          select_default2(this).call(svgIcon(d2.icon || "#iD-icon-" + d2.button));
+        });
+        if (buttons.enter().size() || buttons.exit().size()) {
+          context.ui().checkOverflow(".top-toolbar", true);
+        }
+        buttons = buttons.merge(buttonsEnter).classed("disabled", function() {
+          return !enabled();
+        }).attr("aria-disabled", function() {
+          return !enabled();
+        }).classed("active", function(d2) {
+          return context.mode() && context.mode().button === d2.button;
+        }).attr("aria-pressed", function(d2) {
+          return context.mode() && context.mode().button === d2.button;
+        });
+      }
     };
-    mode.exit = function() {
-      context.uninstall(behavior);
+    tool.uninstall = function() {
+      context.on("enter.editor.notes", null).on("exit.editor.notes", null).on("enter.notes", null);
+      context.map().on("move.notes", null).on("drawn.notes", null);
     };
-    return mode;
+    return tool;
   }
 
-  // modules/modes/add_point.js
-  function modeAddPoint(context, mode) {
-    mode.id = "add-point";
-    var behavior = behaviorDraw(context).on("click", add).on("clickWay", addWay).on("clickNode", addNode).on("cancel", cancel).on("finish", cancel);
-    function defaultTags(loc) {
-      var defaultTags2 = {};
-      if (mode.preset)
-        defaultTags2 = mode.preset.setTags(defaultTags2, "point", false, loc);
-      return defaultTags2;
+  // modules/ui/tools/save.js
+  function uiToolSave(context) {
+    var tool = {
+      id: "save",
+      label: _t.append("save.title")
+    };
+    var button = null;
+    var tooltipBehavior = null;
+    var history = context.history();
+    var key = uiCmd("\u2318S");
+    var _numChanges = 0;
+    function isSaving() {
+      var mode = context.mode();
+      return mode && mode.id === "save";
     }
-    function add(loc) {
-      var node = osmNode({ loc, tags: defaultTags(loc) });
-      context.perform(
-        actionAddEntity(node),
-        _t("operations.add.annotation.point")
-      );
-      enterSelectMode(node);
+    function isDisabled() {
+      return _numChanges === 0 || isSaving();
     }
-    function addWay(loc, edge) {
-      var node = osmNode({ tags: defaultTags(loc) });
-      context.perform(
-        actionAddMidpoint({ loc, edge }, node),
-        _t("operations.add.annotation.vertex")
-      );
-      enterSelectMode(node);
+    function save(d3_event) {
+      d3_event.preventDefault();
+      if (!context.inIntro() && !isSaving() && history.hasChanges()) {
+        context.enter(modeSave(context));
+      }
     }
-    function enterSelectMode(node) {
-      context.enter(
-        modeSelect(context, [node.id]).newFeature(true)
-      );
+    function bgColor(numChanges) {
+      var step;
+      if (numChanges === 0) {
+        return null;
+      } else if (numChanges <= 50) {
+        step = numChanges / 50;
+        return rgb_default("#fff", "#ff8")(step);
+      } else {
+        step = Math.min((numChanges - 50) / 50, 1);
+        return rgb_default("#ff8", "#f88")(step);
+      }
     }
-    function addNode(node) {
-      const _defaultTags = defaultTags(node.loc);
-      if (Object.keys(_defaultTags).length === 0) {
-        enterSelectMode(node);
-        return;
+    function updateCount() {
+      var val = history.difference().summary().length;
+      if (val === _numChanges) return;
+      _numChanges = val;
+      if (tooltipBehavior) {
+        tooltipBehavior.title(() => _t.append(_numChanges > 0 ? "save.help" : "save.no_changes")).keys([key]);
       }
-      var tags = Object.assign({}, node.tags);
-      for (var key in _defaultTags) {
-        tags[key] = _defaultTags[key];
+      if (button) {
+        button.classed("disabled", isDisabled()).style("background", bgColor(_numChanges));
+        button.select("span.count").text(_numChanges);
       }
-      context.perform(
-        actionChangeTags(node.id, tags),
-        _t("operations.add.annotation.point")
-      );
-      enterSelectMode(node);
     }
-    function cancel() {
-      context.enter(modeBrowse(context));
-    }
-    mode.enter = function() {
-      context.install(behavior);
-    };
-    mode.exit = function() {
-      context.uninstall(behavior);
-    };
-    return mode;
-  }
-
-  // modules/ui/note_comments.js
-  function uiNoteComments() {
-    var _note;
-    function noteComments(selection2) {
-      if (_note.isNew())
-        return;
-      var comments = selection2.selectAll(".comments-container").data([0]);
-      comments = comments.enter().append("div").attr("class", "comments-container").merge(comments);
-      var commentEnter = comments.selectAll(".comment").data(_note.comments).enter().append("div").attr("class", "comment");
-      commentEnter.append("div").attr("class", function(d2) {
-        return "comment-avatar user-" + d2.uid;
-      }).call(svgIcon("#iD-icon-avatar", "comment-avatar-icon"));
-      var mainEnter = commentEnter.append("div").attr("class", "comment-main");
-      var metadataEnter = mainEnter.append("div").attr("class", "comment-metadata");
-      metadataEnter.append("div").attr("class", "comment-author").each(function(d2) {
-        var selection3 = select_default2(this);
-        var osm = services.osm;
-        if (osm && d2.user) {
-          selection3 = selection3.append("a").attr("class", "comment-author-link").attr("href", osm.userURL(d2.user)).attr("target", "_blank");
+    tool.render = function(selection2) {
+      tooltipBehavior = uiTooltip().placement("bottom").title(() => _t.append("save.no_changes")).keys([key]).scrollContainer(context.container().select(".top-toolbar"));
+      var lastPointerUpType;
+      button = selection2.append("button").attr("class", "save disabled bar-button").on("pointerup", function(d3_event) {
+        lastPointerUpType = d3_event.pointerType;
+      }).on("click", function(d3_event) {
+        save(d3_event);
+        if (_numChanges === 0 && (lastPointerUpType === "touch" || lastPointerUpType === "pen")) {
+          context.ui().flash.duration(2e3).iconName("#iD-icon-save").iconClass("disabled").label(_t.append("save.no_changes"))();
         }
-        if (d2.user) {
-          selection3.text(d2.user);
-        } else {
-          selection3.call(_t.append("note.anonymous"));
+        lastPointerUpType = null;
+      }).call(tooltipBehavior);
+      button.call(svgIcon("#iD-icon-save"));
+      button.append("span").attr("class", "count").attr("aria-hidden", "true").text("0");
+      updateCount();
+      context.keybinding().on(key, save, true);
+      context.history().on("change.save", updateCount);
+      context.on("enter.save", function() {
+        if (button) {
+          button.classed("disabled", isDisabled());
+          if (isSaving()) {
+            button.call(tooltipBehavior.hide);
+          }
         }
       });
-      metadataEnter.append("div").attr("class", "comment-date").html(function(d2) {
-        return _t.html("note.status." + d2.action, { when: localeDateString2(d2.date) });
-      });
-      mainEnter.append("div").attr("class", "comment-text").html(function(d2) {
-        return d2.html;
-      }).selectAll("a").attr("rel", "noopener nofollow").attr("target", "_blank");
-      comments.call(replaceAvatars);
-    }
-    function replaceAvatars(selection2) {
-      var showThirdPartyIcons = corePreferences("preferences.privacy.thirdpartyicons") || "true";
-      var osm = services.osm;
-      if (showThirdPartyIcons !== "true" || !osm)
-        return;
-      var uids = {};
-      _note.comments.forEach(function(d2) {
-        if (d2.uid)
-          uids[d2.uid] = true;
-      });
-      Object.keys(uids).forEach(function(uid) {
-        osm.loadUser(uid, function(err, user) {
-          if (!user || !user.image_url)
-            return;
-          selection2.selectAll(".comment-avatar.user-" + uid).html("").append("img").attr("class", "icon comment-avatar-icon").attr("src", user.image_url).attr("alt", user.display_name);
-        });
-      });
-    }
-    function localeDateString2(s2) {
-      if (!s2)
-        return null;
-      var options2 = { day: "numeric", month: "short", year: "numeric" };
-      s2 = s2.replace(/-/g, "/");
-      var d2 = new Date(s2);
-      if (isNaN(d2.getTime()))
-        return null;
-      return d2.toLocaleDateString(_mainLocalizer.localeCode(), options2);
-    }
-    noteComments.note = function(val) {
-      if (!arguments.length)
-        return _note;
-      _note = val;
-      return noteComments;
     };
-    return noteComments;
+    tool.uninstall = function() {
+      context.keybinding().off(key, true);
+      context.history().on("change.save", null);
+      context.on("enter.save", null);
+      button = null;
+      tooltipBehavior = null;
+    };
+    return tool;
   }
 
-  // modules/ui/note_header.js
-  function uiNoteHeader() {
-    var _note;
-    function noteHeader(selection2) {
-      var header = selection2.selectAll(".note-header").data(
-        _note ? [_note] : [],
-        function(d2) {
-          return d2.status + d2.id;
-        }
-      );
-      header.exit().remove();
-      var headerEnter = header.enter().append("div").attr("class", "note-header");
-      var iconEnter = headerEnter.append("div").attr("class", function(d2) {
-        return "note-header-icon " + d2.status;
-      }).classed("new", function(d2) {
-        return d2.id < 0;
-      });
-      iconEnter.append("div").attr("class", "preset-icon-28").call(svgIcon("#iD-icon-note", "note-fill"));
-      iconEnter.each(function(d2) {
-        var statusIcon;
-        if (d2.id < 0) {
-          statusIcon = "#iD-icon-plus";
-        } else if (d2.status === "open") {
-          statusIcon = "#iD-icon-close";
-        } else {
-          statusIcon = "#iD-icon-apply";
-        }
-        iconEnter.append("div").attr("class", "note-icon-annotation").attr("title", _t("icons.close")).call(svgIcon(statusIcon, "icon-annotation"));
-      });
-      headerEnter.append("div").attr("class", "note-header-label").html(function(d2) {
-        if (_note.isNew()) {
-          return _t.html("note.new");
-        }
-        return _t.html("note.note") + " " + d2.id + " " + (d2.status === "closed" ? _t.html("note.closed") : "");
-      });
-    }
-    noteHeader.note = function(val) {
-      if (!arguments.length)
-        return _note;
-      _note = val;
-      return noteHeader;
+  // modules/ui/tools/sidebar_toggle.js
+  function uiToolSidebarToggle(context) {
+    var tool = {
+      id: "sidebar_toggle",
+      label: _t.append("toolbar.inspect")
     };
-    return noteHeader;
+    tool.render = function(selection2) {
+      selection2.append("button").attr("class", "bar-button").attr("aria-label", _t("sidebar.tooltip")).on("click", function() {
+        context.ui().sidebar.toggle();
+      }).call(
+        uiTooltip().placement("bottom").title(() => _t.append("sidebar.tooltip")).keys([_t("sidebar.key")]).scrollContainer(context.container().select(".top-toolbar"))
+      ).call(svgIcon("#iD-icon-sidebar-" + (_mainLocalizer.textDirection() === "rtl" ? "right" : "left")));
+    };
+    return tool;
   }
 
-  // modules/ui/note_report.js
-  function uiNoteReport() {
-    var _note;
-    function noteReport(selection2) {
-      var url;
-      if (services.osm && _note instanceof osmNote && !_note.isNew()) {
-        url = services.osm.noteReportURL(_note);
-      }
-      var link3 = selection2.selectAll(".note-report").data(url ? [url] : []);
-      link3.exit().remove();
-      var linkEnter = link3.enter().append("a").attr("class", "note-report").attr("target", "_blank").attr("href", function(d2) {
-        return d2;
-      }).call(svgIcon("#iD-icon-out-link", "inline"));
-      linkEnter.append("span").call(_t.append("note.report"));
-    }
-    noteReport.note = function(val) {
-      if (!arguments.length)
-        return _note;
-      _note = val;
-      return noteReport;
-    };
-    return noteReport;
-  }
-
-  // modules/ui/view_on_osm.js
-  function uiViewOnOSM(context) {
-    var _what;
-    function viewOnOSM(selection2) {
-      var url;
-      if (_what instanceof osmEntity) {
-        url = context.connection().entityURL(_what);
-      } else if (_what instanceof osmNote) {
-        url = context.connection().noteURL(_what);
-      }
-      var data = !_what || _what.isNew() ? [] : [_what];
-      var link3 = selection2.selectAll(".view-on-osm").data(data, function(d2) {
-        return d2.id;
-      });
-      link3.exit().remove();
-      var linkEnter = link3.enter().append("a").attr("class", "view-on-osm").attr("target", "_blank").attr("href", url).call(svgIcon("#iD-icon-out-link", "inline"));
-      linkEnter.append("span").call(_t.append("inspector.view_on_osm"));
-    }
-    viewOnOSM.what = function(_2) {
-      if (!arguments.length)
-        return _what;
-      _what = _2;
-      return viewOnOSM;
+  // modules/ui/tools/undo_redo.js
+  function uiToolUndoRedo(context) {
+    var tool = {
+      id: "undo_redo",
+      label: _t.append("toolbar.undo_redo")
     };
-    return viewOnOSM;
-  }
-
-  // modules/ui/note_editor.js
-  function uiNoteEditor(context) {
-    var dispatch14 = dispatch_default("change");
-    var noteComments = uiNoteComments(context);
-    var noteHeader = uiNoteHeader();
-    var _note;
-    var _newNote;
-    function noteEditor(selection2) {
-      var header = selection2.selectAll(".header").data([0]);
-      var headerEnter = header.enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
-        context.enter(modeBrowse(context));
-      }).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("note.title"));
-      var body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      var editor = body.selectAll(".note-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section note-editor").merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
-      var footer = selection2.selectAll(".footer").data([0]);
-      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnOSM(context).what(_note)).call(uiNoteReport(context).note(_note));
-      var osm = services.osm;
-      if (osm) {
-        osm.on("change.note-save", function() {
-          selection2.call(noteEditor);
-        });
-      }
+    var commands = [{
+      id: "undo",
+      cmd: uiCmd("\u2318Z"),
+      action: function() {
+        context.undo();
+      },
+      annotation: function() {
+        return context.history().undoAnnotation();
+      },
+      icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")
+    }, {
+      id: "redo",
+      cmd: uiCmd("\u2318\u21E7Z"),
+      action: function() {
+        context.redo();
+      },
+      annotation: function() {
+        return context.history().redoAnnotation();
+      },
+      icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "undo" : "redo")
+    }];
+    function editable() {
+      return context.mode() && context.mode().id !== "save" && context.map().editableDataEnabled(
+        true
+        /* ignore min zoom */
+      );
     }
-    function noteSaveSection(selection2) {
-      var isSelected = _note && _note.id === context.selectedNoteID();
-      var noteSave = selection2.selectAll(".note-save").data(isSelected ? [_note] : [], function(d2) {
-        return d2.status + d2.id;
-      });
-      noteSave.exit().remove();
-      var noteSaveEnter = noteSave.enter().append("div").attr("class", "note-save save-section cf");
-      noteSaveEnter.append("h4").attr("class", ".note-save-header").text("").each(function() {
-        if (_note.isNew()) {
-          _t.append("note.newDescription")(select_default2(this));
-        } else {
-          _t.append("note.newComment")(select_default2(this));
+    tool.render = function(selection2) {
+      var tooltipBehavior = uiTooltip().placement("bottom").title(function(d2) {
+        return d2.annotation() ? _t.append(d2.id + ".tooltip", { action: d2.annotation() }) : _t.append(d2.id + ".nothing");
+      }).keys(function(d2) {
+        return [d2.cmd];
+      }).scrollContainer(context.container().select(".top-toolbar"));
+      var lastPointerUpType;
+      var buttons = selection2.selectAll("button").data(commands).enter().append("button").attr("class", function(d2) {
+        return "disabled " + d2.id + "-button bar-button";
+      }).on("pointerup", function(d3_event) {
+        lastPointerUpType = d3_event.pointerType;
+      }).on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        var annotation = d2.annotation();
+        if (editable() && annotation) {
+          d2.action();
+        }
+        if (editable() && (lastPointerUpType === "touch" || lastPointerUpType === "pen")) {
+          var label = annotation ? _t.append(d2.id + ".tooltip", { action: annotation }) : _t.append(d2.id + ".nothing");
+          context.ui().flash.duration(2e3).iconName("#" + d2.icon).iconClass(annotation ? "" : "disabled").label(label)();
         }
+        lastPointerUpType = null;
+      }).call(tooltipBehavior);
+      buttons.each(function(d2) {
+        select_default2(this).call(svgIcon("#" + d2.icon));
       });
-      var commentTextarea = noteSaveEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("note.inputPlaceholder")).attr("maxlength", 1e3).property("value", function(d2) {
-        return d2.newComment;
-      }).call(utilNoAuto).on("keydown.note-input", keydown).on("input.note-input", changeInput).on("blur.note-input", changeInput);
-      if (!commentTextarea.empty() && _newNote) {
-        commentTextarea.node().focus();
-      }
-      noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons);
-      function keydown(d3_event) {
-        if (!(d3_event.keyCode === 13 && // ↩ Return
-        d3_event.metaKey))
-          return;
-        var osm = services.osm;
-        if (!osm)
-          return;
-        var hasAuth = osm.authenticated();
-        if (!hasAuth)
-          return;
-        if (!_note.newComment)
-          return;
+      context.keybinding().on(commands[0].cmd, function(d3_event) {
         d3_event.preventDefault();
-        select_default2(this).on("keydown.note-input", null);
-        window.setTimeout(function() {
-          if (_note.isNew()) {
-            noteSave.selectAll(".save-button").node().focus();
-            clickSave(_note);
-          } else {
-            noteSave.selectAll(".comment-button").node().focus();
-            clickComment(_note);
+        if (editable()) commands[0].action();
+      }).on(commands[1].cmd, function(d3_event) {
+        d3_event.preventDefault();
+        if (editable()) commands[1].action();
+      });
+      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
+      context.map().on("move.undo_redo", debouncedUpdate).on("drawn.undo_redo", debouncedUpdate);
+      context.history().on("change.undo_redo", function(difference2) {
+        if (difference2) update();
+      });
+      context.on("enter.undo_redo", update);
+      function update() {
+        buttons.classed("disabled", function(d2) {
+          return !editable() || !d2.annotation();
+        }).each(function() {
+          var selection3 = select_default2(this);
+          if (!selection3.select(".tooltip.in").empty()) {
+            selection3.call(tooltipBehavior.updateContent);
           }
-        }, 10);
-      }
-      function changeInput() {
-        var input = select_default2(this);
-        var val = input.property("value").trim() || void 0;
-        _note = _note.update({ newComment: val });
-        var osm = services.osm;
-        if (osm) {
-          osm.replaceNote(_note);
-        }
-        noteSave.call(noteSaveButtons);
+        });
       }
+    };
+    tool.uninstall = function() {
+      context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
+      context.map().on("move.undo_redo", null).on("drawn.undo_redo", null);
+      context.history().on("change.undo_redo", null);
+      context.on("enter.undo_redo", null);
+    };
+    return tool;
+  }
+
+  // modules/ui/top_toolbar.js
+  function uiTopToolbar(context) {
+    var sidebarToggle = uiToolSidebarToggle(context), modes = uiToolDrawModes(context), notes = uiToolNotes(context), undoRedo = uiToolUndoRedo(context), save = uiToolSave(context);
+    function notesEnabled() {
+      var noteLayer = context.layers().layer("notes");
+      return noteLayer && noteLayer.enabled();
     }
-    function userDetails(selection2) {
-      var detailSection = selection2.selectAll(".detail-section").data([0]);
-      detailSection = detailSection.enter().append("div").attr("class", "detail-section").merge(detailSection);
-      var osm = services.osm;
-      if (!osm)
-        return;
-      var hasAuth = osm.authenticated();
-      var authWarning = detailSection.selectAll(".auth-warning").data(hasAuth ? [] : [0]);
-      authWarning.exit().transition().duration(200).style("opacity", 0).remove();
-      var authEnter = authWarning.enter().insert("div", ".tag-reference-body").attr("class", "field-warning auth-warning").style("opacity", 0);
-      authEnter.call(svgIcon("#iD-icon-alert", "inline"));
-      authEnter.append("span").call(_t.append("note.login"));
-      authEnter.append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("login")).on("click.note-login", function(d3_event) {
-        d3_event.preventDefault();
-        osm.authenticate();
-      });
-      authEnter.transition().duration(200).style("opacity", 1);
-      var prose = detailSection.selectAll(".note-save-prose").data(hasAuth ? [0] : []);
-      prose.exit().remove();
-      prose = prose.enter().append("p").attr("class", "note-save-prose").call(_t.append("note.upload_explanation")).merge(prose);
-      osm.userDetails(function(err, user) {
-        if (err)
-          return;
-        var userLink = select_default2(document.createElement("div"));
-        if (user.image_url) {
-          userLink.append("img").attr("src", user.image_url).attr("class", "icon pre-text user-icon");
+    function topToolbar(bar) {
+      bar.on("wheel.topToolbar", function(d3_event) {
+        if (!d3_event.deltaX) {
+          bar.node().scrollLeft += d3_event.deltaY;
         }
-        userLink.append("a").attr("class", "user-info").text(user.display_name).attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
-        prose.html(_t.html("note.upload_explanation_with_user", { user: { html: userLink.html() } }));
       });
+      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
+      context.layers().on("change.topToolbar", debouncedUpdate);
+      update();
+      function update() {
+        var tools = [
+          sidebarToggle,
+          "spacer",
+          modes
+        ];
+        tools.push("spacer");
+        if (notesEnabled()) {
+          tools = tools.concat([notes, "spacer"]);
+        }
+        tools = tools.concat([undoRedo, save]);
+        var toolbarItems = bar.selectAll(".toolbar-item").data(tools, function(d2) {
+          return d2.id || d2;
+        });
+        toolbarItems.exit().each(function(d2) {
+          if (d2.uninstall) {
+            d2.uninstall();
+          }
+        }).remove();
+        var itemsEnter = toolbarItems.enter().append("div").attr("class", function(d2) {
+          var classes = "toolbar-item " + (d2.id || d2).replace("_", "-");
+          if (d2.klass) classes += " " + d2.klass;
+          return classes;
+        });
+        var actionableItems = itemsEnter.filter(function(d2) {
+          return d2 !== "spacer";
+        });
+        actionableItems.append("div").attr("class", "item-content").each(function(d2) {
+          select_default2(this).call(d2.render, bar);
+        });
+        actionableItems.append("div").attr("class", "item-label").each(function(d2) {
+          d2.label(select_default2(this));
+        });
+      }
     }
-    function noteSaveButtons(selection2) {
-      var osm = services.osm;
-      var hasAuth = osm && osm.authenticated();
-      var isSelected = _note && _note.id === context.selectedNoteID();
-      var buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_note] : [], function(d2) {
-        return d2.status + d2.id;
-      });
-      buttonSection.exit().remove();
-      var buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
-      if (_note.isNew()) {
-        buttonEnter.append("button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
-        buttonEnter.append("button").attr("class", "button save-button action").call(_t.append("note.save"));
+    return topToolbar;
+  }
+
+  // modules/ui/version.js
+  var sawVersion = null;
+  var isNewVersion = false;
+  var isNewUser = false;
+  function uiVersion(context) {
+    var currVersion = context.version;
+    var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
+    if (sawVersion === null && matchedVersion !== null) {
+      if (corePreferences("sawVersion")) {
+        isNewUser = false;
+        isNewVersion = corePreferences("sawVersion") !== currVersion && currVersion.indexOf("-") === -1;
       } else {
-        buttonEnter.append("button").attr("class", "button status-button action");
-        buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("note.comment"));
-      }
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
-      buttonSection.select(".save-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
-      buttonSection.select(".status-button").attr("disabled", hasAuth ? null : true).text("").each(function(d2) {
-        var action = d2.status === "open" ? "close" : "open";
-        var andComment = d2.newComment ? "_comment" : "";
-        _t.append("note." + action + andComment)(select_default2(this));
-      });
-      buttonSection.select(".status-button").on("click.status", clickStatus);
-      buttonSection.select(".comment-button").attr("disabled", isSaveDisabled).on("click.comment", clickComment);
-      function isSaveDisabled(d2) {
-        return hasAuth && d2.status === "open" && d2.newComment ? null : true;
+        isNewUser = true;
+        isNewVersion = true;
       }
+      corePreferences("sawVersion", currVersion);
+      sawVersion = currVersion;
     }
-    function clickCancel(d3_event, d2) {
-      this.blur();
-      var osm = services.osm;
-      if (osm) {
-        osm.removeNote(d2);
+    return function(selection2) {
+      selection2.append("a").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD").text(currVersion);
+      if (isNewVersion && !isNewUser) {
+        selection2.append("a").attr("class", "badge").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new").call(svgIcon("#maki-gift")).call(
+          uiTooltip().title(() => _t.append("version.whats_new", { version: currVersion })).placement("top").scrollContainer(context.container().select(".main-footer-wrap"))
+        );
       }
-      context.enter(modeBrowse(context));
-      dispatch14.call("change");
+    };
+  }
+
+  // modules/ui/zoom.js
+  function uiZoom(context) {
+    var zooms = [{
+      id: "zoom-in",
+      icon: "iD-icon-plus",
+      title: _t.append("zoom.in"),
+      action: zoomIn,
+      disabled: function() {
+        return !context.map().canZoomIn();
+      },
+      disabledTitle: _t.append("zoom.disabled.in"),
+      key: "+"
+    }, {
+      id: "zoom-out",
+      icon: "iD-icon-minus",
+      title: _t.append("zoom.out"),
+      action: zoomOut,
+      disabled: function() {
+        return !context.map().canZoomOut();
+      },
+      disabledTitle: _t.append("zoom.disabled.out"),
+      key: "-"
+    }];
+    function zoomIn(d3_event) {
+      if (d3_event.shiftKey) return;
+      d3_event.preventDefault();
+      context.map().zoomIn();
     }
-    function clickSave(d3_event, d2) {
-      this.blur();
-      var osm = services.osm;
-      if (osm) {
-        osm.postNoteCreate(d2, function(err, note) {
-          dispatch14.call("change", note);
-        });
-      }
+    function zoomOut(d3_event) {
+      if (d3_event.shiftKey) return;
+      d3_event.preventDefault();
+      context.map().zoomOut();
     }
-    function clickStatus(d3_event, d2) {
-      this.blur();
-      var osm = services.osm;
-      if (osm) {
-        var setStatus = d2.status === "open" ? "closed" : "open";
-        osm.postNoteUpdate(d2, setStatus, function(err, note) {
-          dispatch14.call("change", note);
-        });
-      }
+    function zoomInFurther(d3_event) {
+      if (d3_event.shiftKey) return;
+      d3_event.preventDefault();
+      context.map().zoomInFurther();
     }
-    function clickComment(d3_event, d2) {
-      this.blur();
-      var osm = services.osm;
-      if (osm) {
-        osm.postNoteUpdate(d2, d2.status, function(err, note) {
-          dispatch14.call("change", note);
+    function zoomOutFurther(d3_event) {
+      if (d3_event.shiftKey) return;
+      d3_event.preventDefault();
+      context.map().zoomOutFurther();
+    }
+    return function(selection2) {
+      var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(function(d2) {
+        if (d2.disabled()) {
+          return d2.disabledTitle;
+        }
+        return d2.title;
+      }).keys(function(d2) {
+        return [d2.key];
+      });
+      var lastPointerUpType;
+      var buttons = selection2.selectAll("button").data(zooms).enter().append("button").attr("class", function(d2) {
+        return d2.id;
+      }).on("pointerup.editor", function(d3_event) {
+        lastPointerUpType = d3_event.pointerType;
+      }).on("click.editor", function(d3_event, d2) {
+        if (!d2.disabled()) {
+          d2.action(d3_event);
+        } else if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
+          context.ui().flash.duration(2e3).iconName("#" + d2.icon).iconClass("disabled").label(d2.disabledTitle)();
+        }
+        lastPointerUpType = null;
+      }).call(tooltipBehavior);
+      buttons.each(function(d2) {
+        select_default2(this).call(svgIcon("#" + d2.icon, "light"));
+      });
+      utilKeybinding.plusKeys.forEach(function(key) {
+        context.keybinding().on([key], zoomIn);
+        context.keybinding().on([uiCmd("\u2325" + key)], zoomInFurther);
+      });
+      utilKeybinding.minusKeys.forEach(function(key) {
+        context.keybinding().on([key], zoomOut);
+        context.keybinding().on([uiCmd("\u2325" + key)], zoomOutFurther);
+      });
+      function updateButtonStates() {
+        buttons.classed("disabled", function(d2) {
+          return d2.disabled();
+        }).each(function() {
+          var selection3 = select_default2(this);
+          if (!selection3.select(".tooltip.in").empty()) {
+            selection3.call(tooltipBehavior.updateContent);
+          }
         });
       }
-    }
-    noteEditor.note = function(val) {
-      if (!arguments.length)
-        return _note;
-      _note = val;
-      return noteEditor;
-    };
-    noteEditor.newNote = function(val) {
-      if (!arguments.length)
-        return _newNote;
-      _newNote = val;
-      return noteEditor;
+      updateButtonStates();
+      context.map().on("move.uiZoom", updateButtonStates);
     };
-    return utilRebind(noteEditor, dispatch14, "on");
   }
 
-  // modules/modes/select_note.js
-  function modeSelectNote(context, selectedNoteID) {
-    var mode = {
-      id: "select-note",
-      button: "browse"
-    };
-    var _keybinding = utilKeybinding("select-note");
-    var _noteEditor = uiNoteEditor(context).on("change", function() {
-      context.map().pan([0, 0]);
-      var note = checkSelectedID();
-      if (!note)
-        return;
-      context.ui().sidebar.show(_noteEditor.note(note));
-    });
-    var _behaviors = [
-      behaviorBreathe(context),
-      behaviorHover(context),
-      behaviorSelect(context),
-      behaviorLasso(context),
-      modeDragNode(context).behavior,
-      modeDragNote(context).behavior
-    ];
-    var _newFeature = false;
-    function checkSelectedID() {
-      if (!services.osm)
-        return;
-      var note = services.osm.getNote(selectedNoteID);
-      if (!note) {
-        context.enter(modeBrowse(context));
-      }
-      return note;
+  // modules/ui/zoom_to_selection.js
+  function uiZoomToSelection(context) {
+    function isDisabled() {
+      var mode = context.mode();
+      return !mode || !mode.zoomToSelected;
     }
-    function selectNote(d3_event, drawn) {
-      if (!checkSelectedID())
-        return;
-      var selection2 = context.surface().selectAll(".layer-notes .note-" + selectedNoteID);
-      if (selection2.empty()) {
-        var source = d3_event && d3_event.type === "zoom" && d3_event.sourceEvent;
-        if (drawn && source && (source.type === "pointermove" || source.type === "mousemove" || source.type === "touchmove")) {
-          context.enter(modeBrowse(context));
+    var _lastPointerUpType;
+    function pointerup(d3_event) {
+      _lastPointerUpType = d3_event.pointerType;
+    }
+    function click(d3_event) {
+      d3_event.preventDefault();
+      if (isDisabled()) {
+        if (_lastPointerUpType === "touch" || _lastPointerUpType === "pen") {
+          context.ui().flash.duration(2e3).iconName("#iD-icon-framed-dot").iconClass("disabled").label(_t.append("inspector.zoom_to.no_selection"))();
         }
       } else {
-        selection2.classed("selected", true);
-        context.selectedNoteID(selectedNoteID);
+        var mode = context.mode();
+        if (mode && mode.zoomToSelected) {
+          mode.zoomToSelected();
+        }
       }
+      _lastPointerUpType = null;
     }
-    function esc() {
-      if (context.container().select(".combobox").size())
-        return;
-      context.enter(modeBrowse(context));
-    }
-    mode.zoomToSelected = function() {
-      if (!services.osm)
-        return;
-      var note = services.osm.getNote(selectedNoteID);
-      if (note) {
-        context.map().centerZoomEase(note.loc, 20);
-      }
-    };
-    mode.newFeature = function(val) {
-      if (!arguments.length)
-        return _newFeature;
-      _newFeature = val;
-      return mode;
-    };
-    mode.enter = function() {
-      var note = checkSelectedID();
-      if (!note)
-        return;
-      _behaviors.forEach(context.install);
-      _keybinding.on(_t("inspector.zoom_to.key"), mode.zoomToSelected).on("\u238B", esc, true);
-      select_default2(document).call(_keybinding);
-      selectNote();
-      var sidebar = context.ui().sidebar;
-      sidebar.show(_noteEditor.note(note).newNote(_newFeature));
-      sidebar.expand(sidebar.intersects(note.extent()));
-      context.map().on("drawn.select", selectNote);
-    };
-    mode.exit = function() {
-      _behaviors.forEach(context.uninstall);
-      select_default2(document).call(_keybinding.unbind);
-      context.surface().selectAll(".layer-notes .selected").classed("selected hover", false);
-      context.map().on("drawn.select", null);
-      context.ui().sidebar.hide();
-      context.selectedNoteID(null);
+    return function(selection2) {
+      var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(function() {
+        if (isDisabled()) {
+          return _t.append("inspector.zoom_to.no_selection");
+        }
+        return _t.append("inspector.zoom_to.title");
+      }).keys([_t("inspector.zoom_to.key")]);
+      var button = selection2.append("button").on("pointerup", pointerup).on("click", click).call(svgIcon("#iD-icon-framed-dot", "light")).call(tooltipBehavior);
+      function setEnabledState() {
+        button.classed("disabled", isDisabled());
+        if (!button.select(".tooltip.in").empty()) {
+          button.call(tooltipBehavior.updateContent);
+        }
+      }
+      context.on("enter.uiZoomToSelection", setEnabledState);
+      setEnabledState();
     };
-    return mode;
   }
 
-  // modules/modes/add_note.js
-  function modeAddNote(context) {
-    var mode = {
-      id: "add-note",
-      button: "note",
-      description: _t.append("modes.add_note.description"),
-      key: _t("modes.add_note.key")
+  // modules/ui/pane.js
+  function uiPane(id2, context) {
+    var _key;
+    var _label = "";
+    var _description = "";
+    var _iconName = "";
+    var _sections;
+    var _paneSelection = select_default2(null);
+    var _paneTooltip;
+    var pane = {
+      id: id2
     };
-    var behavior = behaviorDraw(context).on("click", add).on("cancel", cancel).on("finish", cancel);
-    function add(loc) {
-      var osm = services.osm;
-      if (!osm)
-        return;
-      var note = osmNote({ loc, status: "open", comments: [] });
-      osm.replaceNote(note);
-      context.map().pan([0, 0]);
-      context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
-    }
-    function cancel() {
-      context.enter(modeBrowse(context));
+    pane.label = function(val) {
+      if (!arguments.length) return _label;
+      _label = val;
+      return pane;
+    };
+    pane.key = function(val) {
+      if (!arguments.length) return _key;
+      _key = val;
+      return pane;
+    };
+    pane.description = function(val) {
+      if (!arguments.length) return _description;
+      _description = val;
+      return pane;
+    };
+    pane.iconName = function(val) {
+      if (!arguments.length) return _iconName;
+      _iconName = val;
+      return pane;
+    };
+    pane.sections = function(val) {
+      if (!arguments.length) return _sections;
+      _sections = val;
+      return pane;
+    };
+    pane.selection = function() {
+      return _paneSelection;
+    };
+    function hidePane() {
+      context.ui().togglePanes();
     }
-    mode.enter = function() {
-      context.install(behavior);
+    pane.togglePane = function(d3_event) {
+      if (d3_event) d3_event.preventDefault();
+      _paneTooltip.hide();
+      context.ui().togglePanes(!_paneSelection.classed("shown") ? _paneSelection : void 0);
     };
-    mode.exit = function() {
-      context.uninstall(behavior);
+    pane.renderToggleButton = function(selection2) {
+      if (!_paneTooltip) {
+        _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(() => _description).keys([_key]);
+      }
+      selection2.append("button").on("click", pane.togglePane).call(svgIcon("#" + _iconName, "light")).call(_paneTooltip);
     };
-    return mode;
+    pane.renderContent = function(selection2) {
+      if (_sections) {
+        _sections.forEach(function(section) {
+          selection2.call(section.render);
+        });
+      }
+    };
+    pane.renderPane = function(selection2) {
+      _paneSelection = selection2.append("div").attr("class", "fillL map-pane hide " + id2 + "-pane").attr("pane", id2);
+      var heading2 = _paneSelection.append("div").attr("class", "pane-heading");
+      heading2.append("h2").text("").call(_label);
+      heading2.append("button").attr("title", _t("icons.close")).on("click", hidePane).call(svgIcon("#iD-icon-close"));
+      _paneSelection.append("div").attr("class", "pane-content").call(pane.renderContent);
+      if (_key) {
+        context.keybinding().on(_key, pane.togglePane);
+      }
+    };
+    return pane;
   }
 
-  // node_modules/osm-community-index/lib/simplify.js
-  var import_diacritics2 = __toESM(require_diacritics(), 1);
-  function simplify(str) {
-    if (typeof str !== "string")
-      return "";
-    return import_diacritics2.default.remove(
-      str.replace(/&/g, "and").replace(/(İ|i̇)/ig, "i").replace(/[\s\-=_!"#%'*{},.\/:;?\(\)\[\]@\\$\^*+<>«»~`’\u00a1\u00a7\u00b6\u00b7\u00bf\u037e\u0387\u055a-\u055f\u0589\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0af0\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f14\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1360-\u1368\u166d\u166e\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u1805\u1807-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cc0-\u1cc7\u1cd3\u2000-\u206f\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00-\u2e7f\u3001-\u3003\u303d\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uaaf0\uaaf1\uabeb\ufe10-\ufe16\ufe19\ufe30\ufe45\ufe46\ufe49-\ufe4c\ufe50-\ufe52\ufe54-\ufe57\ufe5f-\ufe61\ufe68\ufe6a\ufe6b\ufeff\uff01-\uff03\uff05-\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65]+/g, "").toLowerCase()
-    );
+  // modules/ui/sections/background_display_options.js
+  function uiSectionBackgroundDisplayOptions(context) {
+    var section = uiSection("background-display-options", context).label(() => _t.append("background.display_options")).disclosureContent(renderDisclosureContent);
+    var _storedOpacity = corePreferences("background-opacity");
+    var _minVal = 0;
+    var _maxVal = 3;
+    var _sliders = ["brightness", "contrast", "saturation", "sharpness"];
+    var _options = {
+      brightness: _storedOpacity !== null ? +_storedOpacity : 1,
+      contrast: 1,
+      saturation: 1,
+      sharpness: 1
+    };
+    function clamp3(x2, min3, max3) {
+      return Math.max(min3, Math.min(x2, max3));
+    }
+    function updateValue(d2, val) {
+      val = clamp3(val, _minVal, _maxVal);
+      _options[d2] = val;
+      context.background()[d2](val);
+      if (d2 === "brightness") {
+        corePreferences("background-opacity", val);
+      }
+      section.reRender();
+    }
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".display-options-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "display-options-container controls-list");
+      var slidersEnter = containerEnter.selectAll(".display-control").data(_sliders).enter().append("label").attr("class", function(d2) {
+        return "display-control display-control-" + d2;
+      });
+      slidersEnter.html(function(d2) {
+        return _t.html("background." + d2);
+      }).append("span").attr("class", function(d2) {
+        return "display-option-value display-option-value-" + d2;
+      });
+      var sildersControlEnter = slidersEnter.append("div").attr("class", "control-wrap");
+      sildersControlEnter.append("input").attr("class", function(d2) {
+        return "display-option-input display-option-input-" + d2;
+      }).attr("type", "range").attr("min", _minVal).attr("max", _maxVal).attr("step", "0.05").on("input", function(d3_event, d2) {
+        var val = select_default2(this).property("value");
+        if (!val && d3_event && d3_event.target) {
+          val = d3_event.target.value;
+        }
+        updateValue(d2, val);
+      });
+      sildersControlEnter.append("button").attr("title", function(d2) {
+        return "".concat(_t("background.reset"), " ").concat(_t("background." + d2));
+      }).attr("class", function(d2) {
+        return "display-option-reset display-option-reset-" + d2;
+      }).on("click", function(d3_event, d2) {
+        if (d3_event.button !== 0) return;
+        updateValue(d2, 1);
+      }).call(svgIcon("#iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")));
+      containerEnter.append("a").attr("class", "display-option-resetlink").attr("role", "button").attr("href", "#").call(_t.append("background.reset_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        for (var i3 = 0; i3 < _sliders.length; i3++) {
+          updateValue(_sliders[i3], 1);
+        }
+      });
+      container = containerEnter.merge(container);
+      container.selectAll(".display-option-input").property("value", function(d2) {
+        return _options[d2];
+      });
+      container.selectAll(".display-option-value").text(function(d2) {
+        return Math.floor(_options[d2] * 100) + "%";
+      });
+      container.selectAll(".display-option-reset").classed("disabled", function(d2) {
+        return _options[d2] === 1;
+      });
+      if (containerEnter.size() && _options.brightness !== 1) {
+        context.background().brightness(_options.brightness);
+      }
+    }
+    return section;
   }
 
-  // node_modules/osm-community-index/lib/resolve_strings.js
-  function resolveStrings(item, defaults, localizerFn) {
-    let itemStrings = Object.assign({}, item.strings);
-    let defaultStrings = Object.assign({}, defaults[item.type]);
-    const anyToken = new RegExp(/(\{\w+\})/, "gi");
-    if (localizerFn) {
-      if (itemStrings.community) {
-        const communityID = simplify(itemStrings.community);
-        itemStrings.community = localizerFn("_communities.".concat(communityID));
+  // modules/ui/settings/custom_background.js
+  function uiSettingsCustomBackground() {
+    var dispatch14 = dispatch_default("change");
+    function render(selection2) {
+      var _origSettings = {
+        template: corePreferences("background-custom-template")
+      };
+      var _currSettings = {
+        template: corePreferences("background-custom-template")
+      };
+      var example = "https://tile.openstreetmap.org/{zoom}/{x}/{y}.png";
+      var modal = uiConfirm(selection2).okButton();
+      modal.classed("settings-modal settings-custom-background", true);
+      modal.select(".modal-section.header").append("h3").call(_t.append("settings.custom_background.header"));
+      var textSection = modal.select(".modal-section.message-text");
+      var instructions = "".concat(_t.html("settings.custom_background.instructions.info"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.wms.tokens_label"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.proj"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.wkid"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.dimensions"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.bbox"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.tms.tokens_label"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.xyz"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.flipped_y"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.switch"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.quadtile"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.scale_factor"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.example"), "\n") + "`".concat(example, "`");
+      textSection.append("div").attr("class", "instructions-template").html(marked(instructions));
+      textSection.append("textarea").attr("class", "field-template").attr("placeholder", _t("settings.custom_background.template.placeholder")).call(utilNoAuto).property("value", _currSettings.template);
+      var buttonSection = modal.select(".modal-section.buttons");
+      buttonSection.insert("button", ".ok-button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
+      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
+      buttonSection.select(".ok-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
+      function isSaveDisabled() {
+        return null;
+      }
+      function clickCancel() {
+        textSection.select(".field-template").property("value", _origSettings.template);
+        corePreferences("background-custom-template", _origSettings.template);
+        this.blur();
+        modal.close();
+      }
+      function clickSave() {
+        _currSettings.template = textSection.select(".field-template").property("value");
+        corePreferences("background-custom-template", _currSettings.template);
+        this.blur();
+        modal.close();
+        dispatch14.call("change", this, _currSettings);
       }
-      ["name", "description", "extendedDescription"].forEach((prop) => {
-        if (defaultStrings[prop])
-          defaultStrings[prop] = localizerFn("_defaults.".concat(item.type, ".").concat(prop));
-        if (itemStrings[prop])
-          itemStrings[prop] = localizerFn("".concat(item.id, ".").concat(prop));
-      });
     }
-    let replacements = {
-      account: item.account,
-      community: itemStrings.community,
-      signupUrl: itemStrings.signupUrl,
-      url: itemStrings.url
-    };
-    if (!replacements.signupUrl) {
-      replacements.signupUrl = resolve(itemStrings.signupUrl || defaultStrings.signupUrl);
+    return utilRebind(render, dispatch14, "on");
+  }
+
+  // modules/ui/sections/background_list.js
+  function uiSectionBackgroundList(context) {
+    var _backgroundList = select_default2(null);
+    var _customSource = context.background().findSource("custom");
+    var _settingsCustomBackground = uiSettingsCustomBackground(context).on("change", customChanged);
+    var section = uiSection("background-list", context).label(() => _t.append("background.backgrounds")).disclosureContent(renderDisclosureContent);
+    function previousBackgroundID() {
+      return corePreferences("background-last-used-toggle");
     }
-    if (!replacements.url) {
-      replacements.url = resolve(itemStrings.url || defaultStrings.url);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".layer-background-list").data([0]);
+      _backgroundList = container.enter().append("ul").attr("class", "layer-list layer-background-list").attr("dir", "auto").merge(container);
+      var bgExtrasListEnter = selection2.selectAll(".bg-extras-list").data([0]).enter().append("ul").attr("class", "layer-list bg-extras-list");
+      var minimapLabelEnter = bgExtrasListEnter.append("li").attr("class", "minimap-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("background.minimap.tooltip")).keys([_t("background.minimap.key")]).placement("top")
+      );
+      minimapLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        uiMapInMap.toggle();
+      });
+      minimapLabelEnter.append("span").call(_t.append("background.minimap.description"));
+      var panelLabelEnter = bgExtrasListEnter.append("li").attr("class", "background-panel-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("background.panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.background.key"))]).placement("top")
+      );
+      panelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        context.ui().info.toggle("background");
+      });
+      panelLabelEnter.append("span").call(_t.append("background.panel.description"));
+      var locPanelLabelEnter = bgExtrasListEnter.append("li").attr("class", "location-panel-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("background.location_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.location.key"))]).placement("top")
+      );
+      locPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        context.ui().info.toggle("location");
+      });
+      locPanelLabelEnter.append("span").call(_t.append("background.location_panel.description"));
+      selection2.selectAll(".imagery-faq").data([0]).enter().append("div").attr("class", "imagery-faq").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/openstreetmap/iD/blob/develop/FAQ.md#how-can-i-report-an-issue-with-background-imagery").append("span").call(_t.append("background.imagery_problem_faq"));
+      _backgroundList.call(drawListItems, "radio", function(d3_event, d2) {
+        chooseBackground(d2);
+      }, function(d2) {
+        return !d2.isHidden() && !d2.overlay;
+      });
     }
-    let resolved = {
-      name: resolve(itemStrings.name || defaultStrings.name),
-      url: resolve(itemStrings.url || defaultStrings.url),
-      signupUrl: resolve(itemStrings.signupUrl || defaultStrings.signupUrl),
-      description: resolve(itemStrings.description || defaultStrings.description),
-      extendedDescription: resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription)
-    };
-    resolved.nameHTML = linkify(resolved.url, resolved.name);
-    resolved.urlHTML = linkify(resolved.url);
-    resolved.signupUrlHTML = linkify(resolved.signupUrl);
-    resolved.descriptionHTML = resolve(itemStrings.description || defaultStrings.description, true);
-    resolved.extendedDescriptionHTML = resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription, true);
-    return resolved;
-    function resolve(s2, addLinks) {
-      if (!s2)
-        return void 0;
-      let result = s2;
-      for (let key in replacements) {
-        const token = "{".concat(key, "}");
-        const regex = new RegExp(token, "g");
-        if (regex.test(result)) {
-          let replacement = replacements[key];
-          if (!replacement) {
-            throw new Error("Cannot resolve token: ".concat(token));
-          } else {
-            if (addLinks && (key === "signupUrl" || key === "url")) {
-              replacement = linkify(replacement);
-            }
-            result = result.replace(regex, replacement);
-          }
+    function setTooltips(selection2) {
+      selection2.each(function(d2, i3, nodes) {
+        var item = select_default2(this).select("label");
+        var span = item.select("span");
+        var placement = i3 < nodes.length / 2 ? "bottom" : "top";
+        var hasDescription = d2.hasDescription();
+        var isOverflowing = span.property("clientWidth") !== span.property("scrollWidth");
+        item.call(uiTooltip().destroyAny);
+        if (d2.id === previousBackgroundID()) {
+          item.call(
+            uiTooltip().placement(placement).title(() => _t.append("background.switch")).keys([uiCmd("\u2318" + _t("background.key"))])
+          );
+        } else if (hasDescription || isOverflowing) {
+          item.call(
+            uiTooltip().placement(placement).title(() => hasDescription ? d2.description() : d2.label())
+          );
         }
+      });
+    }
+    function drawListItems(layerList, type2, change, filter2) {
+      var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter2).sort(function(a2, b2) {
+        return a2.best() && !b2.best() ? -1 : b2.best() && !a2.best() ? 1 : descending(a2.area(), b2.area()) || ascending(a2.name(), b2.name()) || 0;
+      });
+      var layerLinks = layerList.selectAll("li").data(sources, function(d2, i3) {
+        return d2.id + "---" + i3;
+      });
+      layerLinks.exit().remove();
+      var enter = layerLinks.enter().append("li").classed("layer-custom", function(d2) {
+        return d2.id === "custom";
+      }).classed("best", function(d2) {
+        return d2.best();
+      });
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", "background-layer").attr("value", function(d2) {
+        return d2.id;
+      }).on("change", change);
+      label.append("span").each(function(d2) {
+        d2.label()(select_default2(this));
+      });
+      enter.filter(function(d2) {
+        return d2.id === "custom";
+      }).append("button").attr("class", "layer-browse").call(
+        uiTooltip().title(() => _t.append("settings.custom_background.tooltip")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        editCustom();
+      }).call(svgIcon("#iD-icon-more"));
+      enter.filter(function(d2) {
+        return d2.best();
+      }).append("div").attr("class", "best").call(
+        uiTooltip().title(() => _t.append("background.best_imagery")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).append("span").text("\u2605");
+      layerList.call(updateLayerSelections);
+    }
+    function updateLayerSelections(selection2) {
+      function active(d2) {
+        return context.background().showsLayer(d2);
       }
-      const leftovers = result.match(anyToken);
-      if (leftovers) {
-        throw new Error("Cannot resolve tokens: ".concat(leftovers));
+      selection2.selectAll("li").classed("active", active).classed("switch", function(d2) {
+        return d2.id === previousBackgroundID();
+      }).call(setTooltips).selectAll("input").property("checked", active);
+    }
+    function chooseBackground(d2) {
+      if (d2.id === "custom" && !d2.template()) {
+        return editCustom();
       }
-      if (addLinks && item.type === "reddit") {
-        result = result.replace(/(\/r\/\w+\/*)/i, (match) => linkify(resolved.url, match));
+      var previousBackground = context.background().baseLayerSource();
+      corePreferences("background-last-used-toggle", previousBackground.id);
+      corePreferences("background-last-used", d2.id);
+      context.background().baseLayerSource(d2);
+    }
+    function customChanged(d2) {
+      if (d2 && d2.template) {
+        _customSource.template(d2.template);
+        chooseBackground(_customSource);
+      } else {
+        _customSource.template("");
+        chooseBackground(context.background().findSource("none"));
       }
-      return result;
     }
-    function linkify(url, text) {
-      if (!url)
-        return void 0;
-      text = text || url;
-      return '<a target="_blank" href="'.concat(url, '">').concat(text, "</a>");
+    function editCustom() {
+      context.container().call(_settingsCustomBackground);
     }
+    context.background().on("change.background_list", function() {
+      _backgroundList.call(updateLayerSelections);
+    });
+    context.map().on(
+      "move.background_list",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
   }
 
-  // modules/ui/success.js
-  var _oci = null;
-  function uiSuccess(context) {
-    const MAXEVENTS = 2;
-    const dispatch14 = dispatch_default("cancel");
-    let _changeset2;
-    let _location;
-    ensureOSMCommunityIndex();
-    function ensureOSMCommunityIndex() {
-      const data = _mainFileFetcher;
-      return Promise.all([
-        data.get("oci_features"),
-        data.get("oci_resources"),
-        data.get("oci_defaults")
-      ]).then((vals) => {
-        if (_oci)
-          return _oci;
-        if (vals[0] && Array.isArray(vals[0].features)) {
-          _sharedLocationManager.mergeCustomGeoJSON(vals[0]);
-        }
-        let ociResources = Object.values(vals[1].resources);
-        if (ociResources.length) {
-          return _sharedLocationManager.mergeLocationSets(ociResources).then(() => {
-            _oci = {
-              resources: ociResources,
-              defaults: vals[2].defaults
-            };
-            return _oci;
-          });
-        } else {
-          _oci = {
-            resources: [],
-            // no resources?
-            defaults: vals[2].defaults
-          };
-          return _oci;
-        }
+  // modules/ui/sections/background_offset.js
+  function uiSectionBackgroundOffset(context) {
+    var section = uiSection("background-offset", context).label(() => _t.append("background.fix_misalignment")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    var _directions = [
+      ["top", [0, -0.5]],
+      ["left", [-0.5, 0]],
+      ["right", [0.5, 0]],
+      ["bottom", [0, 0.5]]
+    ];
+    function updateValue() {
+      var meters = geoOffsetToMeters(context.background().offset());
+      var x2 = +meters[0].toFixed(2);
+      var y2 = +meters[1].toFixed(2);
+      context.container().selectAll(".nudge-inner-rect").select("input").classed("error", false).property("value", x2 + ", " + y2);
+      context.container().selectAll(".nudge-reset").classed("disabled", function() {
+        return x2 === 0 && y2 === 0;
       });
     }
-    function parseEventDate(when) {
-      if (!when)
-        return;
-      let raw = when.trim();
-      if (!raw)
+    function resetOffset() {
+      context.background().offset([0, 0]);
+      updateValue();
+    }
+    function nudge(d2) {
+      context.background().nudge(d2, context.map().zoom());
+      updateValue();
+    }
+    function inputOffset() {
+      var input = select_default2(this);
+      var d2 = input.node().value;
+      if (d2 === "") return resetOffset();
+      d2 = d2.replace(/;/g, ",").split(",").map(function(n3) {
+        return !isNaN(n3) && n3;
+      });
+      if (d2.length !== 2 || !d2[0] || !d2[1]) {
+        input.classed("error", true);
         return;
-      if (!/Z$/.test(raw)) {
-        raw += "Z";
       }
-      const parsed = new Date(raw);
-      return new Date(parsed.toUTCString().slice(0, 25));
+      context.background().offset(geoMetersToOffset(d2));
+      updateValue();
     }
-    function success(selection2) {
-      let header = selection2.append("div").attr("class", "header fillL");
-      header.append("h2").call(_t.append("success.just_edited"));
-      header.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => dispatch14.call("cancel")).call(svgIcon("#iD-icon-close"));
-      let body = selection2.append("div").attr("class", "body save-success fillL");
-      let summary = body.append("div").attr("class", "save-summary");
-      summary.append("h3").call(_t.append("success.thank_you" + (_location ? "_location" : ""), { where: _location }));
-      summary.append("p").call(_t.append("success.help_html")).append("a").attr("class", "link-out").attr("target", "_blank").attr("href", _t("success.help_link_url")).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("success.help_link_text"));
-      let osm = context.connection();
-      if (!osm)
-        return;
-      let changesetURL = osm.changesetURL(_changeset2.id);
-      let table = summary.append("table").attr("class", "summary-table");
-      let row = table.append("tr").attr("class", "summary-row");
-      row.append("td").attr("class", "cell-icon summary-icon").append("a").attr("target", "_blank").attr("href", changesetURL).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", "#iD-logo-osm");
-      let summaryDetail = row.append("td").attr("class", "cell-detail summary-detail");
-      summaryDetail.append("a").attr("class", "cell-detail summary-view-on-osm").attr("target", "_blank").attr("href", changesetURL).call(_t.append("success.view_on_osm"));
-      summaryDetail.append("div").html(_t.html("success.changeset_id", {
-        changeset_id: { html: '<a href="'.concat(changesetURL, '" target="_blank">').concat(_changeset2.id, "</a>") }
-      }));
-      if (showDonationMessage !== false) {
-        const donationUrl = "https://supporting.openstreetmap.org/";
-        let supporting = body.append("div").attr("class", "save-supporting");
-        supporting.append("h3").call(_t.append("success.supporting.title"));
-        supporting.append("p").call(_t.append("success.supporting.details"));
-        table = supporting.append("table").attr("class", "supporting-table");
-        row = table.append("tr").attr("class", "supporting-row");
-        row.append("td").attr("class", "cell-icon supporting-icon").append("a").attr("target", "_blank").attr("href", donationUrl).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", "#iD-donation");
-        let supportingDetail = row.append("td").attr("class", "cell-detail supporting-detail");
-        supportingDetail.append("a").attr("class", "cell-detail support-the-map").attr("target", "_blank").attr("href", donationUrl).call(_t.append("success.supporting.donation.title"));
-        supportingDetail.append("div").call(_t.append("success.supporting.donation.details"));
-      }
-      ensureOSMCommunityIndex().then((oci) => {
-        const loc = context.map().center();
-        const validHere = _sharedLocationManager.locationSetsAt(loc);
-        let communities = [];
-        oci.resources.forEach((resource) => {
-          let area = validHere[resource.locationSetID];
-          if (!area)
-            return;
-          const localizer = (stringID) => _t.html("community.".concat(stringID));
-          resource.resolved = resolveStrings(resource, oci.defaults, localizer);
-          communities.push({
-            area,
-            order: resource.order || 0,
-            resource
-          });
-        });
-        communities.sort((a2, b2) => a2.area - b2.area || b2.order - a2.order);
-        body.call(showCommunityLinks, communities.map((c2) => c2.resource));
-      });
-    }
-    function showCommunityLinks(selection2, resources) {
-      let communityLinks = selection2.append("div").attr("class", "save-communityLinks");
-      communityLinks.append("h3").call(_t.append("success.like_osm"));
-      let table = communityLinks.append("table").attr("class", "community-table");
-      let row = table.selectAll(".community-row").data(resources);
-      let rowEnter = row.enter().append("tr").attr("class", "community-row");
-      rowEnter.append("td").attr("class", "cell-icon community-icon").append("a").attr("target", "_blank").attr("href", (d2) => d2.resolved.url).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", (d2) => "#community-".concat(d2.type));
-      let communityDetail = rowEnter.append("td").attr("class", "cell-detail community-detail");
-      communityDetail.each(showCommunityDetails);
-      communityLinks.append("div").attr("class", "community-missing").call(_t.append("success.missing")).append("a").attr("class", "link-out").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/osmlab/osm-community-index/issues").append("span").call(_t.append("success.tell_us"));
-    }
-    function showCommunityDetails(d2) {
-      let selection2 = select_default2(this);
-      let communityID = d2.id;
-      selection2.append("div").attr("class", "community-name").html(d2.resolved.nameHTML);
-      selection2.append("div").attr("class", "community-description").html(d2.resolved.descriptionHTML);
-      if (d2.resolved.extendedDescriptionHTML || d2.languageCodes && d2.languageCodes.length) {
-        selection2.append("div").call(
-          uiDisclosure(context, "community-more-".concat(d2.id), false).expanded(false).updatePreference(false).label(() => _t.append("success.more")).content(showMore)
-        );
-      }
-      let nextEvents = (d2.events || []).map((event) => {
-        event.date = parseEventDate(event.when);
-        return event;
-      }).filter((event) => {
-        const t2 = event.date.getTime();
-        const now3 = (/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0);
-        return !isNaN(t2) && t2 >= now3;
-      }).sort((a2, b2) => {
-        return a2.date < b2.date ? -1 : a2.date > b2.date ? 1 : 0;
-      }).slice(0, MAXEVENTS);
-      if (nextEvents.length) {
-        selection2.append("div").call(
-          uiDisclosure(context, "community-events-".concat(d2.id), false).expanded(false).updatePreference(false).label(_t.html("success.events")).content(showNextEvents)
-        ).select(".hide-toggle").append("span").attr("class", "badge-text").text(nextEvents.length);
+    function dragOffset(d3_event) {
+      if (d3_event.button !== 0) return;
+      var origin = [d3_event.clientX, d3_event.clientY];
+      var pointerId = d3_event.pointerId || "mouse";
+      context.container().append("div").attr("class", "nudge-surface");
+      select_default2(window).on(_pointerPrefix + "move.drag-bg-offset", pointermove).on(_pointerPrefix + "up.drag-bg-offset", pointerup);
+      if (_pointerPrefix === "pointer") {
+        select_default2(window).on("pointercancel.drag-bg-offset", pointerup);
       }
-      function showMore(selection3) {
-        let more = selection3.selectAll(".community-more").data([0]);
-        let moreEnter = more.enter().append("div").attr("class", "community-more");
-        if (d2.resolved.extendedDescriptionHTML) {
-          moreEnter.append("div").attr("class", "community-extended-description").html(d2.resolved.extendedDescriptionHTML);
-        }
-        if (d2.languageCodes && d2.languageCodes.length) {
-          const languageList = d2.languageCodes.map((code) => _mainLocalizer.languageName(code)).join(", ");
-          moreEnter.append("div").attr("class", "community-languages").call(_t.append("success.languages", { languages: languageList }));
-        }
+      function pointermove(d3_event2) {
+        if (pointerId !== (d3_event2.pointerId || "mouse")) return;
+        var latest = [d3_event2.clientX, d3_event2.clientY];
+        var d2 = [
+          -(origin[0] - latest[0]) / 4,
+          -(origin[1] - latest[1]) / 4
+        ];
+        origin = latest;
+        nudge(d2);
       }
-      function showNextEvents(selection3) {
-        let events = selection3.append("div").attr("class", "community-events");
-        let item = events.selectAll(".community-event").data(nextEvents);
-        let itemEnter = item.enter().append("div").attr("class", "community-event");
-        itemEnter.append("div").attr("class", "community-event-name").append("a").attr("target", "_blank").attr("href", (d4) => d4.url).text((d4) => {
-          let name = d4.name;
-          if (d4.i18n && d4.id) {
-            name = _t("community.".concat(communityID, ".events.").concat(d4.id, ".name"), { default: name });
-          }
-          return name;
-        });
-        itemEnter.append("div").attr("class", "community-event-when").text((d4) => {
-          let options2 = { weekday: "short", day: "numeric", month: "short", year: "numeric" };
-          if (d4.date.getHours() || d4.date.getMinutes()) {
-            options2.hour = "numeric";
-            options2.minute = "numeric";
-          }
-          return d4.date.toLocaleString(_mainLocalizer.localeCode(), options2);
-        });
-        itemEnter.append("div").attr("class", "community-event-where").text((d4) => {
-          let where = d4.where;
-          if (d4.i18n && d4.id) {
-            where = _t("community.".concat(communityID, ".events.").concat(d4.id, ".where"), { default: where });
-          }
-          return where;
-        });
-        itemEnter.append("div").attr("class", "community-event-description").text((d4) => {
-          let description = d4.description;
-          if (d4.i18n && d4.id) {
-            description = _t("community.".concat(communityID, ".events.").concat(d4.id, ".description"), { default: description });
-          }
-          return description;
-        });
+      function pointerup(d3_event2) {
+        if (pointerId !== (d3_event2.pointerId || "mouse")) return;
+        if (d3_event2.button !== 0) return;
+        context.container().selectAll(".nudge-surface").remove();
+        select_default2(window).on(".drag-bg-offset", null);
       }
     }
-    success.changeset = function(val) {
-      if (!arguments.length)
-        return _changeset2;
-      _changeset2 = val;
-      return success;
-    };
-    success.location = function(val) {
-      if (!arguments.length)
-        return _location;
-      _location = val;
-      return success;
-    };
-    return utilRebind(success, dispatch14, "on");
-  }
-
-  // modules/modes/save.js
-  function modeSave(context) {
-    var mode = { id: "save" };
-    var keybinding = utilKeybinding("modeSave");
-    var commit = uiCommit(context).on("cancel", cancel);
-    var _conflictsUi;
-    var _location;
-    var _success;
-    var uploader = context.uploader().on("saveStarted.modeSave", function() {
-      keybindingOff();
-    }).on("willAttemptUpload.modeSave", prepareForSuccess).on("progressChanged.modeSave", showProgress).on("resultNoChanges.modeSave", function() {
-      cancel();
-    }).on("resultErrors.modeSave", showErrors).on("resultConflicts.modeSave", showConflicts).on("resultSuccess.modeSave", showSuccess);
-    function cancel() {
-      context.enter(modeBrowse(context));
-    }
-    function showProgress(num, total) {
-      var modal = context.container().select(".loading-modal .modal-section");
-      var progress = modal.selectAll(".progress").data([0]);
-      progress.enter().append("div").attr("class", "progress").merge(progress).text(_t("save.conflict_progress", { num, total }));
-    }
-    function showConflicts(changeset, conflicts, origChanges) {
-      var selection2 = context.container().select(".sidebar").append("div").attr("class", "sidebar-component");
-      context.container().selectAll(".main-content").classed("active", true).classed("inactive", false);
-      _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on("cancel", function() {
-        context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
-        selection2.remove();
-        keybindingOn();
-        uploader.cancelConflictResolution();
-      }).on("save", function() {
-        context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
-        selection2.remove();
-        uploader.processResolvedConflicts(changeset);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".nudge-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "nudge-container");
+      containerEnter.append("div").attr("class", "nudge-instructions").call(_t.append("background.offset"));
+      var nudgeWrapEnter = containerEnter.append("div").attr("class", "nudge-controls-wrap");
+      var nudgeEnter = nudgeWrapEnter.append("div").attr("class", "nudge-outer-rect").on(_pointerPrefix + "down", dragOffset);
+      nudgeEnter.append("div").attr("class", "nudge-inner-rect").append("input").attr("type", "text").attr("aria-label", _t("background.offset_label")).on("change", inputOffset);
+      nudgeWrapEnter.append("div").selectAll("button").data(_directions).enter().append("button").attr("title", function(d2) {
+        return _t("background.nudge.".concat(d2[0]));
+      }).attr("class", function(d2) {
+        return d2[0] + " nudge";
+      }).on("click", function(d3_event, d2) {
+        nudge(d2[1]);
       });
-      selection2.call(_conflictsUi);
-    }
-    function showErrors(errors) {
-      keybindingOn();
-      var selection2 = uiConfirm(context.container());
-      selection2.select(".modal-section.header").append("h3").text(_t("save.error"));
-      addErrors(selection2, errors);
-      selection2.okButton();
-    }
-    function addErrors(selection2, data) {
-      var message = selection2.select(".modal-section.message-text");
-      var items = message.selectAll(".error-container").data(data);
-      var enter = items.enter().append("div").attr("class", "error-container");
-      enter.append("a").attr("class", "error-description").attr("href", "#").classed("hide-toggle", true).text(function(d2) {
-        return d2.msg || _t("save.unknown_error_details");
-      }).on("click", function(d3_event) {
+      nudgeWrapEnter.append("button").attr("title", _t("background.reset")).attr("class", "nudge-reset disabled").on("click", function(d3_event) {
         d3_event.preventDefault();
-        var error = select_default2(this);
-        var detail = select_default2(this.nextElementSibling);
-        var exp2 = error.classed("expanded");
-        detail.style("display", exp2 ? "none" : "block");
-        error.classed("expanded", !exp2);
-      });
-      var details = enter.append("div").attr("class", "error-detail-container").style("display", "none");
-      details.append("ul").attr("class", "error-detail-list").selectAll("li").data(function(d2) {
-        return d2.details || [];
-      }).enter().append("li").attr("class", "error-detail-item").text(function(d2) {
-        return d2;
-      });
-      items.exit().remove();
-    }
-    function showSuccess(changeset) {
-      commit.reset();
-      var ui = _success.changeset(changeset).location(_location).on("cancel", function() {
-        context.ui().sidebar.hide();
-      });
-      context.enter(modeBrowse(context).sidebar(ui));
-    }
-    function keybindingOn() {
-      select_default2(document).call(keybinding.on("\u238B", cancel, true));
-    }
-    function keybindingOff() {
-      select_default2(document).call(keybinding.unbind);
-    }
-    function prepareForSuccess() {
-      _success = uiSuccess(context);
-      _location = null;
-      if (!services.geocoder)
-        return;
-      services.geocoder.reverse(context.map().center(), function(err, result) {
-        if (err || !result || !result.address)
-          return;
-        var addr = result.address;
-        var place = addr && (addr.town || addr.city || addr.county) || "";
-        var region = addr && (addr.state || addr.country) || "";
-        var separator = place && region ? _t("success.thank_you_where.separator") : "";
-        _location = _t(
-          "success.thank_you_where.format",
-          { place, separator, region }
-        );
-      });
-    }
-    mode.selectedIDs = function() {
-      return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
-    };
-    mode.enter = function() {
-      context.ui().sidebar.expand();
-      function done() {
-        context.ui().sidebar.show(commit);
-      }
-      keybindingOn();
-      context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
-      var osm = context.connection();
-      if (!osm) {
-        cancel();
-        return;
-      }
-      if (osm.authenticated()) {
-        done();
-      } else {
-        osm.authenticate(function(err) {
-          if (err) {
-            cancel();
-          } else {
-            done();
-          }
-        });
-      }
-    };
-    mode.exit = function() {
-      keybindingOff();
-      context.container().selectAll(".main-content").classed("active", true).classed("inactive", false);
-      context.ui().sidebar.hide();
-    };
-    return mode;
-  }
-
-  // modules/ui/improveOSM_comments.js
-  function uiImproveOsmComments() {
-    let _qaItem;
-    function issueComments(selection2) {
-      let comments = selection2.selectAll(".comments-container").data([0]);
-      comments = comments.enter().append("div").attr("class", "comments-container").merge(comments);
-      services.improveOSM.getComments(_qaItem).then((d2) => {
-        if (!d2.comments)
-          return;
-        const commentEnter = comments.selectAll(".comment").data(d2.comments).enter().append("div").attr("class", "comment");
-        commentEnter.append("div").attr("class", "comment-avatar").call(svgIcon("#iD-icon-avatar", "comment-avatar-icon"));
-        const mainEnter = commentEnter.append("div").attr("class", "comment-main");
-        const metadataEnter = mainEnter.append("div").attr("class", "comment-metadata");
-        metadataEnter.append("div").attr("class", "comment-author").each(function(d4) {
-          const osm = services.osm;
-          let selection3 = select_default2(this);
-          if (osm && d4.username) {
-            selection3 = selection3.append("a").attr("class", "comment-author-link").attr("href", osm.userURL(d4.username)).attr("target", "_blank");
-          }
-          selection3.text((d5) => d5.username);
-        });
-        metadataEnter.append("div").attr("class", "comment-date").html((d4) => _t.html("note.status.commented", { when: localeDateString2(d4.timestamp) }));
-        mainEnter.append("div").attr("class", "comment-text").append("p").text((d4) => d4.text);
-      }).catch((err) => {
-        console.log(err);
-      });
-    }
-    function localeDateString2(s2) {
-      if (!s2)
-        return null;
-      const options2 = { day: "numeric", month: "short", year: "numeric" };
-      const d2 = new Date(s2 * 1e3);
-      if (isNaN(d2.getTime()))
-        return null;
-      return d2.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+        resetOffset();
+      }).call(svgIcon("#iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")));
+      updateValue();
     }
-    issueComments.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return issueComments;
-    };
-    return issueComments;
+    context.background().on("change.backgroundOffset-update", updateValue);
+    return section;
   }
 
-  // modules/ui/improveOSM_details.js
-  function uiImproveOsmDetails(context) {
-    let _qaItem;
-    function issueDetail(d2) {
-      if (d2.desc)
-        return d2.desc;
-      const issueKey = d2.issueKey;
-      d2.replacements = d2.replacements || {};
-      d2.replacements.default = { html: _t.html("inspector.unknown") };
-      return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".description"), d2.replacements);
-    }
-    function improveOsmDetails(selection2) {
-      const details = selection2.selectAll(".error-details").data(
-        _qaItem ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      details.exit().remove();
-      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
-      const descriptionEnter = detailsEnter.append("div").attr("class", "qa-details-subsection");
-      descriptionEnter.append("h4").call(_t.append("QA.keepRight.detail_description"));
-      descriptionEnter.append("div").attr("class", "qa-details-description-text").html(issueDetail);
-      let relatedEntities = [];
-      descriptionEnter.selectAll(".error_entity_link, .error_object_link").attr("href", "#").each(function() {
-        const link3 = select_default2(this);
-        const isObjectLink = link3.classed("error_object_link");
-        const entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
-        const entity = context.hasEntity(entityID);
-        relatedEntities.push(entityID);
-        link3.on("mouseenter", () => {
-          utilHighlightEntities([entityID], true, context);
-        }).on("mouseleave", () => {
-          utilHighlightEntities([entityID], false, context);
-        }).on("click", (d3_event) => {
-          d3_event.preventDefault();
-          utilHighlightEntities([entityID], false, context);
-          const osmlayer = context.layers().layer("osm");
-          if (!osmlayer.enabled()) {
-            osmlayer.enabled(true);
-          }
-          context.map().centerZoom(_qaItem.loc, 20);
-          if (entity) {
-            context.enter(modeSelect(context, [entityID]));
-          } else {
-            context.loadEntity(entityID, (err, result) => {
-              if (err)
-                return;
-              const entity2 = result.data.find((e3) => e3.id === entityID);
-              if (entity2)
-                context.enter(modeSelect(context, [entityID]));
-            });
-          }
-        });
-        if (entity) {
-          let name = utilDisplayName(entity);
-          if (!name && !isObjectLink) {
-            const preset = _mainPresetIndex.match(entity, context.graph());
-            name = preset && !preset.isFallback() && preset.name();
-          }
-          if (name) {
-            this.innerText = name;
-          }
+  // modules/ui/sections/overlay_list.js
+  function uiSectionOverlayList(context) {
+    var section = uiSection("overlay-list", context).label(() => _t.append("background.overlays")).disclosureContent(renderDisclosureContent);
+    var _overlayList = select_default2(null);
+    function setTooltips(selection2) {
+      selection2.each(function(d2, i3, nodes) {
+        var item = select_default2(this).select("label");
+        var span = item.select("span");
+        var placement = i3 < nodes.length / 2 ? "bottom" : "top";
+        var description = d2.description();
+        var isOverflowing = span.property("clientWidth") !== span.property("scrollWidth");
+        item.call(uiTooltip().destroyAny);
+        if (description || isOverflowing) {
+          item.call(
+            uiTooltip().placement(placement).title(() => description || d2.name())
+          );
         }
       });
-      context.features().forceVisible(relatedEntities);
-      context.map().pan([0, 0]);
-    }
-    improveOsmDetails.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return improveOsmDetails;
-    };
-    return improveOsmDetails;
-  }
-
-  // modules/ui/improveOSM_header.js
-  function uiImproveOsmHeader() {
-    let _qaItem;
-    function issueTitle(d2) {
-      const issueKey = d2.issueKey;
-      d2.replacements = d2.replacements || {};
-      d2.replacements.default = { html: _t.html("inspector.unknown") };
-      return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".title"), d2.replacements);
-    }
-    function improveOsmHeader(selection2) {
-      const header = selection2.selectAll(".qa-header").data(
-        _qaItem ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      header.exit().remove();
-      const headerEnter = header.enter().append("div").attr("class", "qa-header");
-      const svgEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d2) => d2.id < 0).append("svg").attr("width", "20px").attr("height", "30px").attr("viewbox", "0 0 20 30").attr("class", (d2) => "preset-icon-28 qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.itemType));
-      svgEnter.append("polygon").attr("fill", "currentColor").attr("class", "qaItem-fill").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
-      svgEnter.append("use").attr("class", "icon-annotation").attr("width", "12px").attr("height", "12px").attr("transform", "translate(4, 5.5)").attr("xlink:href", (d2) => d2.icon ? "#" + d2.icon : "");
-      headerEnter.append("div").attr("class", "qa-header-label").html(issueTitle);
-    }
-    improveOsmHeader.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return improveOsmHeader;
-    };
-    return improveOsmHeader;
-  }
-
-  // modules/ui/improveOSM_editor.js
-  function uiImproveOsmEditor(context) {
-    const dispatch14 = dispatch_default("change");
-    const qaDetails = uiImproveOsmDetails(context);
-    const qaComments = uiImproveOsmComments(context);
-    const qaHeader = uiImproveOsmHeader(context);
-    let _qaItem;
-    function improveOsmEditor(selection2) {
-      const headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("QA.improveOSM.title"));
-      let body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      const editor = body.selectAll(".qa-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(qaComments.issue(_qaItem)).call(improveOsmSaveSection);
     }
-    function improveOsmSaveSection(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      const isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
-      let saveSection = selection2.selectAll(".qa-save").data(
-        isShown ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      saveSection.exit().remove();
-      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
-      saveSectionEnter.append("h4").attr("class", ".qa-save-header").call(_t.append("note.newComment"));
-      saveSectionEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("QA.keepRight.comment_placeholder")).attr("maxlength", 1e3).property("value", (d2) => d2.newComment).call(utilNoAuto).on("input", changeInput).on("blur", changeInput);
-      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
-      function changeInput() {
-        const input = select_default2(this);
-        let val = input.property("value").trim();
-        if (val === "") {
-          val = void 0;
-        }
-        _qaItem = _qaItem.update({ newComment: val });
-        const qaService = services.improveOSM;
-        if (qaService) {
-          qaService.replaceItem(_qaItem);
-        }
-        saveSection.call(qaSaveButtons);
+    function updateLayerSelections(selection2) {
+      function active(d2) {
+        return context.background().showsLayer(d2);
       }
+      selection2.selectAll("li").classed("active", active).call(setTooltips).selectAll("input").property("checked", active);
     }
-    function qaSaveButtons(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d2) => d2.status + d2.id);
-      buttonSection.exit().remove();
-      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
-      buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("QA.keepRight.save_comment"));
-      buttonEnter.append("button").attr("class", "button close-button action");
-      buttonEnter.append("button").attr("class", "button ignore-button action");
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.select(".comment-button").attr("disabled", (d2) => d2.newComment ? null : true).on("click.comment", function(d3_event, d2) {
-        this.blur();
-        const qaService = services.improveOSM;
-        if (qaService) {
-          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
-        }
+    function chooseOverlay(d3_event, d2) {
+      d3_event.preventDefault();
+      context.background().toggleOverlayLayer(d2);
+      _overlayList.call(updateLayerSelections);
+      document.activeElement.blur();
+    }
+    function drawListItems(layerList, type2, change, filter2) {
+      var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter2);
+      var layerLinks = layerList.selectAll("li").data(sources, function(d2) {
+        return d2.name();
       });
-      buttonSection.select(".close-button").html((d2) => {
-        const andComment = d2.newComment ? "_comment" : "";
-        return _t.html("QA.keepRight.close".concat(andComment));
-      }).on("click.close", function(d3_event, d2) {
-        this.blur();
-        const qaService = services.improveOSM;
-        if (qaService) {
-          d2.newStatus = "SOLVED";
-          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
-        }
+      layerLinks.exit().remove();
+      var enter = layerLinks.enter().append("li");
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", "layers").on("change", change);
+      label.append("span").each(function(d2) {
+        d2.label()(select_default2(this));
       });
-      buttonSection.select(".ignore-button").html((d2) => {
-        const andComment = d2.newComment ? "_comment" : "";
-        return _t.html("QA.keepRight.ignore".concat(andComment));
-      }).on("click.ignore", function(d3_event, d2) {
-        this.blur();
-        const qaService = services.improveOSM;
-        if (qaService) {
-          d2.newStatus = "INVALID";
-          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
-        }
+      layerList.selectAll("li").sort(sortSources);
+      layerList.call(updateLayerSelections);
+      function sortSources(a2, b2) {
+        return a2.best() && !b2.best() ? -1 : b2.best() && !a2.best() ? 1 : descending(a2.area(), b2.area()) || ascending(a2.name(), b2.name()) || 0;
+      }
+    }
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".layer-overlay-list").data([0]);
+      _overlayList = container.enter().append("ul").attr("class", "layer-list layer-overlay-list").attr("dir", "auto").merge(container);
+      _overlayList.call(drawListItems, "checkbox", chooseOverlay, function(d2) {
+        return !d2.isHidden() && d2.overlay;
       });
     }
-    improveOsmEditor.error = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return improveOsmEditor;
-    };
-    return utilRebind(improveOsmEditor, dispatch14, "on");
+    context.map().on(
+      "move.overlay_list",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
   }
 
-  // modules/ui/keepRight_details.js
-  function uiKeepRightDetails(context) {
-    let _qaItem;
-    function issueDetail(d2) {
-      const { itemType, parentIssueType } = d2;
-      const unknown = { html: _t.html("inspector.unknown") };
-      let replacements = d2.replacements || {};
-      replacements.default = unknown;
-      if (_mainLocalizer.hasTextForStringId("QA.keepRight.errorTypes.".concat(itemType, ".title"))) {
-        return _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
-      } else {
-        return _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
-      }
-    }
-    function keepRightDetails(selection2) {
-      const details = selection2.selectAll(".error-details").data(
-        _qaItem ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      details.exit().remove();
-      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
-      const descriptionEnter = detailsEnter.append("div").attr("class", "qa-details-subsection");
-      descriptionEnter.append("h4").call(_t.append("QA.keepRight.detail_description"));
-      descriptionEnter.append("div").attr("class", "qa-details-description-text").html(issueDetail);
-      let relatedEntities = [];
-      descriptionEnter.selectAll(".error_entity_link, .error_object_link").attr("href", "#").each(function() {
-        const link3 = select_default2(this);
-        const isObjectLink = link3.classed("error_object_link");
-        const entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
-        const entity = context.hasEntity(entityID);
-        relatedEntities.push(entityID);
-        link3.on("mouseenter", () => {
-          utilHighlightEntities([entityID], true, context);
-        }).on("mouseleave", () => {
-          utilHighlightEntities([entityID], false, context);
-        }).on("click", (d3_event) => {
-          d3_event.preventDefault();
-          utilHighlightEntities([entityID], false, context);
-          const osmlayer = context.layers().layer("osm");
-          if (!osmlayer.enabled()) {
-            osmlayer.enabled(true);
-          }
-          context.map().centerZoomEase(_qaItem.loc, 20);
-          if (entity) {
-            context.enter(modeSelect(context, [entityID]));
-          } else {
-            context.loadEntity(entityID, (err, result) => {
-              if (err)
-                return;
-              const entity2 = result.data.find((e3) => e3.id === entityID);
-              if (entity2)
-                context.enter(modeSelect(context, [entityID]));
-            });
-          }
+  // modules/ui/panes/background.js
+  function uiPaneBackground(context) {
+    var backgroundPane = uiPane("background", context).key(_t("background.key")).label(_t.append("background.title")).description(_t.append("background.description")).iconName("iD-icon-layers").sections([
+      uiSectionBackgroundList(context),
+      uiSectionOverlayList(context),
+      uiSectionBackgroundDisplayOptions(context),
+      uiSectionBackgroundOffset(context)
+    ]);
+    return backgroundPane;
+  }
+
+  // modules/ui/panes/help.js
+  function uiPaneHelp(context) {
+    var docKeys = [
+      ["help", [
+        "welcome",
+        "open_data_h",
+        "open_data",
+        "before_start_h",
+        "before_start",
+        "open_source_h",
+        "open_source",
+        "open_source_attribution",
+        "open_source_help"
+      ]],
+      ["overview", [
+        "navigation_h",
+        "navigation_drag",
+        "navigation_zoom",
+        "features_h",
+        "features",
+        "nodes_ways"
+      ]],
+      ["editing", [
+        "select_h",
+        "select_left_click",
+        "select_right_click",
+        "select_space",
+        "multiselect_h",
+        "multiselect",
+        "multiselect_shift_click",
+        "multiselect_lasso",
+        "undo_redo_h",
+        "undo_redo",
+        "save_h",
+        "save",
+        "save_validation",
+        "upload_h",
+        "upload",
+        "backups_h",
+        "backups",
+        "keyboard_h",
+        "keyboard"
+      ]],
+      ["feature_editor", [
+        "intro",
+        "definitions",
+        "type_h",
+        "type",
+        "type_picker",
+        "fields_h",
+        "fields_all_fields",
+        "fields_example",
+        "fields_add_field",
+        "tags_h",
+        "tags_all_tags",
+        "tags_resources"
+      ]],
+      ["points", [
+        "intro",
+        "add_point_h",
+        "add_point",
+        "add_point_finish",
+        "move_point_h",
+        "move_point",
+        "delete_point_h",
+        "delete_point",
+        "delete_point_command"
+      ]],
+      ["lines", [
+        "intro",
+        "add_line_h",
+        "add_line",
+        "add_line_draw",
+        "add_line_continue",
+        "add_line_finish",
+        "modify_line_h",
+        "modify_line_dragnode",
+        "modify_line_addnode",
+        "connect_line_h",
+        "connect_line",
+        "connect_line_display",
+        "connect_line_drag",
+        "connect_line_tag",
+        "disconnect_line_h",
+        "disconnect_line_command",
+        "move_line_h",
+        "move_line_command",
+        "move_line_connected",
+        "delete_line_h",
+        "delete_line",
+        "delete_line_command"
+      ]],
+      ["areas", [
+        "intro",
+        "point_or_area_h",
+        "point_or_area",
+        "add_area_h",
+        "add_area_command",
+        "add_area_draw",
+        "add_area_continue",
+        "add_area_finish",
+        "square_area_h",
+        "square_area_command",
+        "modify_area_h",
+        "modify_area_dragnode",
+        "modify_area_addnode",
+        "delete_area_h",
+        "delete_area",
+        "delete_area_command"
+      ]],
+      ["relations", [
+        "intro",
+        "edit_relation_h",
+        "edit_relation",
+        "edit_relation_add",
+        "edit_relation_delete",
+        "maintain_relation_h",
+        "maintain_relation",
+        "relation_types_h",
+        "multipolygon_h",
+        "multipolygon",
+        "multipolygon_create",
+        "multipolygon_merge",
+        "turn_restriction_h",
+        "turn_restriction",
+        "turn_restriction_field",
+        "turn_restriction_editing",
+        "route_h",
+        "route",
+        "route_add",
+        "boundary_h",
+        "boundary",
+        "boundary_add"
+      ]],
+      ["operations", [
+        "intro",
+        "intro_2",
+        "straighten",
+        "orthogonalize",
+        "circularize",
+        "move",
+        "rotate",
+        "reflect",
+        "continue",
+        "reverse",
+        "disconnect",
+        "split",
+        "extract",
+        "merge",
+        "delete",
+        "downgrade",
+        "copy_paste"
+      ]],
+      ["notes", [
+        "intro",
+        "add_note_h",
+        "add_note",
+        "place_note",
+        "move_note",
+        "update_note_h",
+        "update_note",
+        "save_note_h",
+        "save_note"
+      ]],
+      ["imagery", [
+        "intro",
+        "sources_h",
+        "choosing",
+        "sources",
+        "offsets_h",
+        "offset",
+        "offset_change"
+      ]],
+      ["streetlevel", [
+        "intro",
+        "using_h",
+        "using",
+        "photos",
+        "viewer"
+      ]],
+      ["gps", [
+        "intro",
+        "survey",
+        "using_h",
+        "using",
+        "tracing",
+        "upload"
+      ]],
+      ["qa", [
+        "intro",
+        "tools_h",
+        "tools",
+        "issues_h",
+        "issues"
+      ]]
+    ];
+    var headings = {
+      "help.help.open_data_h": 3,
+      "help.help.before_start_h": 3,
+      "help.help.open_source_h": 3,
+      "help.overview.navigation_h": 3,
+      "help.overview.features_h": 3,
+      "help.editing.select_h": 3,
+      "help.editing.multiselect_h": 3,
+      "help.editing.undo_redo_h": 3,
+      "help.editing.save_h": 3,
+      "help.editing.upload_h": 3,
+      "help.editing.backups_h": 3,
+      "help.editing.keyboard_h": 3,
+      "help.feature_editor.type_h": 3,
+      "help.feature_editor.fields_h": 3,
+      "help.feature_editor.tags_h": 3,
+      "help.points.add_point_h": 3,
+      "help.points.move_point_h": 3,
+      "help.points.delete_point_h": 3,
+      "help.lines.add_line_h": 3,
+      "help.lines.modify_line_h": 3,
+      "help.lines.connect_line_h": 3,
+      "help.lines.disconnect_line_h": 3,
+      "help.lines.move_line_h": 3,
+      "help.lines.delete_line_h": 3,
+      "help.areas.point_or_area_h": 3,
+      "help.areas.add_area_h": 3,
+      "help.areas.square_area_h": 3,
+      "help.areas.modify_area_h": 3,
+      "help.areas.delete_area_h": 3,
+      "help.relations.edit_relation_h": 3,
+      "help.relations.maintain_relation_h": 3,
+      "help.relations.relation_types_h": 2,
+      "help.relations.multipolygon_h": 3,
+      "help.relations.turn_restriction_h": 3,
+      "help.relations.route_h": 3,
+      "help.relations.boundary_h": 3,
+      "help.notes.add_note_h": 3,
+      "help.notes.update_note_h": 3,
+      "help.notes.save_note_h": 3,
+      "help.imagery.sources_h": 3,
+      "help.imagery.offsets_h": 3,
+      "help.streetlevel.using_h": 3,
+      "help.gps.using_h": 3,
+      "help.qa.tools_h": 3,
+      "help.qa.issues_h": 3
+    };
+    var docs = docKeys.map(function(key) {
+      var helpkey = "help." + key[0];
+      var helpPaneReplacements = { version: context.version };
+      var text = key[1].reduce(function(all, part) {
+        var subkey = helpkey + "." + part;
+        var depth = headings[subkey];
+        var hhh = depth ? Array(depth + 1).join("#") + " " : "";
+        return all + hhh + helpHtml(subkey, helpPaneReplacements) + "\n\n";
+      }, "");
+      return {
+        title: _t.html(helpkey + ".title"),
+        content: marked(text.trim()).replace(/<code>/g, "<kbd>").replace(/<\/code>/g, "</kbd>")
+      };
+    });
+    var helpPane = uiPane("help", context).key(_t("help.key")).label(_t.append("help.title")).description(_t.append("help.title")).iconName("iD-icon-help");
+    helpPane.renderContent = function(content) {
+      function clickHelp(d2, i3) {
+        var rtl = _mainLocalizer.textDirection() === "rtl";
+        content.property("scrollTop", 0);
+        helpPane.selection().select(".pane-heading h2").html(d2.title);
+        body.html(d2.content);
+        body.selectAll("a").attr("target", "_blank");
+        menuItems.classed("selected", function(m2) {
+          return m2.title === d2.title;
         });
-        if (entity) {
-          let name = utilDisplayName(entity);
-          if (!name && !isObjectLink) {
-            const preset = _mainPresetIndex.match(entity, context.graph());
-            name = preset && !preset.isFallback() && preset.name();
+        nav.html("");
+        if (rtl) {
+          nav.call(drawNext).call(drawPrevious);
+        } else {
+          nav.call(drawPrevious).call(drawNext);
+        }
+        function drawNext(selection2) {
+          if (i3 < docs.length - 1) {
+            var nextLink = selection2.append("a").attr("href", "#").attr("class", "next").on("click", function(d3_event) {
+              d3_event.preventDefault();
+              clickHelp(docs[i3 + 1], i3 + 1);
+            });
+            nextLink.append("span").html(docs[i3 + 1].title).call(svgIcon(rtl ? "#iD-icon-backward" : "#iD-icon-forward", "inline"));
           }
-          if (name) {
-            this.innerText = name;
+        }
+        function drawPrevious(selection2) {
+          if (i3 > 0) {
+            var prevLink = selection2.append("a").attr("href", "#").attr("class", "previous").on("click", function(d3_event) {
+              d3_event.preventDefault();
+              clickHelp(docs[i3 - 1], i3 - 1);
+            });
+            prevLink.call(svgIcon(rtl ? "#iD-icon-forward" : "#iD-icon-backward", "inline")).append("span").html(docs[i3 - 1].title);
           }
         }
+      }
+      function clickWalkthrough(d3_event) {
+        d3_event.preventDefault();
+        if (context.inIntro()) return;
+        context.container().call(uiIntro(context));
+        context.ui().togglePanes();
+      }
+      function clickShortcuts(d3_event) {
+        d3_event.preventDefault();
+        context.container().call(context.ui().shortcuts, true);
+      }
+      var toc = content.append("ul").attr("class", "toc");
+      var menuItems = toc.selectAll("li").data(docs).enter().append("li").append("a").attr("role", "button").attr("href", "#").html(function(d2) {
+        return d2.title;
+      }).on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        clickHelp(d2, docs.indexOf(d2));
       });
-      context.features().forceVisible(relatedEntities);
-      context.map().pan([0, 0]);
-    }
-    keepRightDetails.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return keepRightDetails;
+      var shortcuts = toc.append("li").attr("class", "shortcuts").call(
+        uiTooltip().title(() => _t.append("shortcuts.tooltip")).keys(["?"]).placement("top")
+      ).append("a").attr("href", "#").on("click", clickShortcuts);
+      shortcuts.append("div").call(_t.append("shortcuts.title"));
+      var walkthrough = toc.append("li").attr("class", "walkthrough").append("a").attr("href", "#").on("click", clickWalkthrough);
+      walkthrough.append("svg").attr("class", "logo logo-walkthrough").append("use").attr("xlink:href", "#iD-logo-walkthrough");
+      walkthrough.append("div").call(_t.append("splash.walkthrough"));
+      var helpContent = content.append("div").attr("class", "left-content");
+      var body = helpContent.append("div").attr("class", "body");
+      var nav = helpContent.append("div").attr("class", "nav");
+      clickHelp(docs[0], 0);
     };
-    return keepRightDetails;
+    return helpPane;
   }
 
-  // modules/ui/keepRight_header.js
-  function uiKeepRightHeader() {
-    let _qaItem;
-    function issueTitle(d2) {
-      const { itemType, parentIssueType } = d2;
-      const unknown = _t.html("inspector.unknown");
-      let replacements = d2.replacements || {};
-      replacements.default = { html: unknown };
-      if (_mainLocalizer.hasTextForStringId("QA.keepRight.errorTypes.".concat(itemType, ".title"))) {
-        return _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
-      } else {
-        return _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
-      }
+  // modules/ui/sections/validation_issues.js
+  function uiSectionValidationIssues(id2, severity, context) {
+    var _issues = [];
+    var section = uiSection(id2, context).label(function() {
+      if (!_issues) return "";
+      var issueCountText = _issues.length > 1e3 ? "1000+" : String(_issues.length);
+      return _t.append("inspector.title_count", { title: _t("issues." + severity + "s.list_title"), count: issueCountText });
+    }).disclosureContent(renderDisclosureContent).shouldDisplay(function() {
+      return _issues && _issues.length;
+    });
+    function getOptions() {
+      return {
+        what: corePreferences("validate-what") || "edited",
+        where: corePreferences("validate-where") || "all"
+      };
     }
-    function keepRightHeader(selection2) {
-      const header = selection2.selectAll(".qa-header").data(
-        _qaItem ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      header.exit().remove();
-      const headerEnter = header.enter().append("div").attr("class", "qa-header");
-      const iconEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d2) => d2.id < 0);
-      iconEnter.append("div").attr("class", (d2) => "preset-icon-28 qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.parentIssueType)).call(svgIcon("#iD-icon-bolt", "qaItem-fill"));
-      headerEnter.append("div").attr("class", "qa-header-label").html(issueTitle);
+    function reloadIssues() {
+      _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
     }
-    keepRightHeader.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return keepRightHeader;
-    };
-    return keepRightHeader;
-  }
-
-  // modules/ui/view_on_keepRight.js
-  function uiViewOnKeepRight() {
-    let _qaItem;
-    function viewOnKeepRight(selection2) {
-      let url;
-      if (services.keepRight && _qaItem instanceof QAItem) {
-        url = services.keepRight.issueURL(_qaItem);
-      }
-      const link3 = selection2.selectAll(".view-on-keepRight").data(url ? [url] : []);
-      link3.exit().remove();
-      const linkEnter = link3.enter().append("a").attr("class", "view-on-keepRight").attr("target", "_blank").attr("rel", "noopener").attr("href", (d2) => d2).call(svgIcon("#iD-icon-out-link", "inline"));
-      linkEnter.append("span").call(_t.append("inspector.view_on_keepRight"));
+    function renderDisclosureContent(selection2) {
+      var center = context.map().center();
+      var graph = context.graph();
+      var issues = _issues.map(function withDistance(issue) {
+        var extent = issue.extent(graph);
+        var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
+        return Object.assign(issue, { dist });
+      }).sort(function byDistance(a2, b2) {
+        return a2.dist - b2.dist;
+      });
+      issues = issues.slice(0, 1e3);
+      selection2.call(drawIssuesList, issues);
     }
-    viewOnKeepRight.what = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return viewOnKeepRight;
-    };
-    return viewOnKeepRight;
+    function drawIssuesList(selection2, issues) {
+      var list2 = selection2.selectAll(".issues-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "layer-list issues-list " + severity + "s-list").merge(list2);
+      var items = list2.selectAll("li").data(issues, function(d2) {
+        return d2.key;
+      });
+      items.exit().remove();
+      var itemsEnter = items.enter().append("li").attr("class", function(d2) {
+        return "issue severity-" + d2.severity;
+      });
+      var labelsEnter = itemsEnter.append("button").attr("class", "issue-label").on("click", function(d3_event, d2) {
+        context.validator().focusIssue(d2);
+      }).on("mouseover", function(d3_event, d2) {
+        utilHighlightEntities(d2.entityIds, true, context);
+      }).on("mouseout", function(d3_event, d2) {
+        utilHighlightEntities(d2.entityIds, false, context);
+      });
+      var textEnter = labelsEnter.append("span").attr("class", "issue-text");
+      textEnter.append("span").attr("class", "issue-icon").each(function(d2) {
+        var iconName = "#iD-icon-" + (d2.severity === "warning" ? "alert" : "error");
+        select_default2(this).call(svgIcon(iconName));
+      });
+      textEnter.append("span").attr("class", "issue-message");
+      items = items.merge(itemsEnter).order();
+      items.selectAll(".issue-message").text("").each(function(d2) {
+        return d2.message(context)(select_default2(this));
+      });
+    }
+    context.validator().on("validated.uiSectionValidationIssues" + id2, function() {
+      window.requestIdleCallback(function() {
+        reloadIssues();
+        section.reRender();
+      });
+    });
+    context.map().on(
+      "move.uiSectionValidationIssues" + id2,
+      debounce_default(function() {
+        window.requestIdleCallback(function() {
+          if (getOptions().where === "visible") {
+            reloadIssues();
+          }
+          section.reRender();
+        });
+      }, 1e3)
+    );
+    return section;
   }
 
-  // modules/ui/keepRight_editor.js
-  function uiKeepRightEditor(context) {
-    const dispatch14 = dispatch_default("change");
-    const qaDetails = uiKeepRightDetails(context);
-    const qaHeader = uiKeepRightHeader(context);
-    let _qaItem;
-    function keepRightEditor(selection2) {
-      const headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("QA.keepRight.title"));
-      let body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      const editor = body.selectAll(".qa-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
-      const footer = selection2.selectAll(".footer").data([0]);
-      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnKeepRight(context).what(_qaItem));
-    }
-    function keepRightSaveSection(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      const isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
-      let saveSection = selection2.selectAll(".qa-save").data(
-        isShown ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      saveSection.exit().remove();
-      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
-      saveSectionEnter.append("h4").attr("class", ".qa-save-header").call(_t.append("QA.keepRight.comment"));
-      saveSectionEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("QA.keepRight.comment_placeholder")).attr("maxlength", 1e3).property("value", (d2) => d2.newComment || d2.comment).call(utilNoAuto).on("input", changeInput).on("blur", changeInput);
-      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
-      function changeInput() {
-        const input = select_default2(this);
-        let val = input.property("value").trim();
-        if (val === _qaItem.comment) {
-          val = void 0;
-        }
-        _qaItem = _qaItem.update({ newComment: val });
-        const qaService = services.keepRight;
-        if (qaService) {
-          qaService.replaceItem(_qaItem);
-        }
-        saveSection.call(qaSaveButtons);
-      }
-    }
-    function qaSaveButtons(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d2) => d2.status + d2.id);
-      buttonSection.exit().remove();
-      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
-      buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("QA.keepRight.save_comment"));
-      buttonEnter.append("button").attr("class", "button close-button action");
-      buttonEnter.append("button").attr("class", "button ignore-button action");
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.select(".comment-button").attr("disabled", (d2) => d2.newComment ? null : true).on("click.comment", function(d3_event, d2) {
-        this.blur();
-        const qaService = services.keepRight;
-        if (qaService) {
-          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
-        }
+  // modules/ui/sections/validation_options.js
+  function uiSectionValidationOptions(context) {
+    var section = uiSection("issues-options", context).content(renderContent);
+    function renderContent(selection2) {
+      var container = selection2.selectAll(".issues-options-container").data([0]);
+      container = container.enter().append("div").attr("class", "issues-options-container").merge(container);
+      var data = [
+        { key: "what", values: ["edited", "all"] },
+        { key: "where", values: ["visible", "all"] }
+      ];
+      var options2 = container.selectAll(".issues-option").data(data, function(d2) {
+        return d2.key;
       });
-      buttonSection.select(".close-button").html((d2) => {
-        const andComment = d2.newComment ? "_comment" : "";
-        return _t.html("QA.keepRight.close".concat(andComment));
-      }).on("click.close", function(d3_event, d2) {
-        this.blur();
-        const qaService = services.keepRight;
-        if (qaService) {
-          d2.newStatus = "ignore_t";
-          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
-        }
+      var optionsEnter = options2.enter().append("div").attr("class", function(d2) {
+        return "issues-option issues-option-" + d2.key;
       });
-      buttonSection.select(".ignore-button").html((d2) => {
-        const andComment = d2.newComment ? "_comment" : "";
-        return _t.html("QA.keepRight.ignore".concat(andComment));
-      }).on("click.ignore", function(d3_event, d2) {
-        this.blur();
-        const qaService = services.keepRight;
-        if (qaService) {
-          d2.newStatus = "ignore";
-          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
-        }
+      optionsEnter.append("div").attr("class", "issues-option-title").html(function(d2) {
+        return _t.html("issues.options." + d2.key + ".title");
+      });
+      var valuesEnter = optionsEnter.selectAll("label").data(function(d2) {
+        return d2.values.map(function(val) {
+          return { value: val, key: d2.key };
+        });
+      }).enter().append("label");
+      valuesEnter.append("input").attr("type", "radio").attr("name", function(d2) {
+        return "issues-option-" + d2.key;
+      }).attr("value", function(d2) {
+        return d2.value;
+      }).property("checked", function(d2) {
+        return getOptions()[d2.key] === d2.value;
+      }).on("change", function(d3_event, d2) {
+        updateOptionValue(d3_event, d2.key, d2.value);
+      });
+      valuesEnter.append("span").html(function(d2) {
+        return _t.html("issues.options." + d2.key + "." + d2.value);
       });
     }
-    keepRightEditor.error = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return keepRightEditor;
-    };
-    return utilRebind(keepRightEditor, dispatch14, "on");
+    function getOptions() {
+      return {
+        what: corePreferences("validate-what") || "edited",
+        // 'all', 'edited'
+        where: corePreferences("validate-where") || "all"
+        // 'all', 'visible'
+      };
+    }
+    function updateOptionValue(d3_event, d2, val) {
+      if (!val && d3_event && d3_event.target) {
+        val = d3_event.target.value;
+      }
+      corePreferences("validate-" + d2, val);
+      context.validator().validate();
+    }
+    return section;
   }
 
-  // modules/ui/osmose_details.js
-  function uiOsmoseDetails(context) {
-    let _qaItem;
-    function issueString(d2, type2) {
-      if (!d2)
-        return "";
-      const s2 = services.osmose.getStrings(d2.itemType);
-      return type2 in s2 ? s2[type2] : "";
+  // modules/ui/sections/validation_rules.js
+  function uiSectionValidationRules(context) {
+    var MINSQUARE = 0;
+    var MAXSQUARE = 20;
+    var DEFAULTSQUARE = 5;
+    var section = uiSection("issues-rules", context).disclosureContent(renderDisclosureContent).label(() => _t.append("issues.rules.title"));
+    var _ruleKeys = context.validator().getRuleKeys().filter(function(key) {
+      return key !== "maprules";
+    }).sort(function(key1, key2) {
+      return _t("issues." + key1 + ".title") < _t("issues." + key2 + ".title") ? -1 : 1;
+    });
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".issues-rulelist-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "issues-rulelist-container");
+      containerEnter.append("ul").attr("class", "layer-list issue-rules-list");
+      var ruleLinks = containerEnter.append("div").attr("class", "issue-rules-links section-footer");
+      ruleLinks.append("a").attr("class", "issue-rules-link").attr("role", "button").attr("href", "#").call(_t.append("issues.disable_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.validator().disableRules(_ruleKeys);
+      });
+      ruleLinks.append("a").attr("class", "issue-rules-link").attr("role", "button").attr("href", "#").call(_t.append("issues.enable_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.validator().disableRules([]);
+      });
+      container = container.merge(containerEnter);
+      container.selectAll(".issue-rules-list").call(drawListItems, _ruleKeys, "checkbox", "rule", toggleRule, isRuleEnabled);
     }
-    function osmoseDetails(selection2) {
-      const details = selection2.selectAll(".error-details").data(
-        _qaItem ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      details.exit().remove();
-      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
-      if (issueString(_qaItem, "detail")) {
-        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
-        div.append("h4").call(_t.append("QA.keepRight.detail_description"));
-        div.append("p").attr("class", "qa-details-description-text").html((d2) => issueString(d2, "detail")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
-      }
-      const detailsDiv = detailsEnter.append("div").attr("class", "qa-details-subsection");
-      const elemsDiv = detailsEnter.append("div").attr("class", "qa-details-subsection");
-      if (issueString(_qaItem, "fix")) {
-        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
-        div.append("h4").call(_t.append("QA.osmose.fix_title"));
-        div.append("p").html((d2) => issueString(d2, "fix")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
-      }
-      if (issueString(_qaItem, "trap")) {
-        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
-        div.append("h4").call(_t.append("QA.osmose.trap_title"));
-        div.append("p").html((d2) => issueString(d2, "trap")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+    function drawListItems(selection2, data, type2, name, change, active) {
+      var items = selection2.selectAll("li").data(data);
+      items.exit().remove();
+      var enter = items.enter().append("li");
+      if (name === "rule") {
+        enter.call(
+          uiTooltip().title(function(d2) {
+            return _t.append("issues." + d2 + ".tip");
+          }).placement("top")
+        );
       }
-      const thisItem = _qaItem;
-      services.osmose.loadIssueDetail(_qaItem).then((d2) => {
-        if (!d2.elems || d2.elems.length === 0)
-          return;
-        if (context.selectedErrorID() !== thisItem.id && context.container().selectAll(".qaItem.osmose.hover.itemId-".concat(thisItem.id)).empty())
-          return;
-        if (d2.detail) {
-          detailsDiv.append("h4").call(_t.append("QA.osmose.detail_title"));
-          detailsDiv.append("p").html((d4) => d4.detail).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
+      label.append("span").html(function(d2) {
+        var params = {};
+        if (d2 === "unsquare_way") {
+          params.val = { html: '<span class="square-degrees"></span>' };
         }
-        elemsDiv.append("h4").call(_t.append("QA.osmose.elems_title"));
-        elemsDiv.append("ul").selectAll("li").data(d2.elems).enter().append("li").append("a").attr("href", "#").attr("class", "error_entity_link").text((d4) => d4).each(function() {
-          const link3 = select_default2(this);
-          const entityID = this.textContent;
-          const entity = context.hasEntity(entityID);
-          link3.on("mouseenter", () => {
-            utilHighlightEntities([entityID], true, context);
-          }).on("mouseleave", () => {
-            utilHighlightEntities([entityID], false, context);
-          }).on("click", (d3_event) => {
-            d3_event.preventDefault();
-            utilHighlightEntities([entityID], false, context);
-            const osmlayer = context.layers().layer("osm");
-            if (!osmlayer.enabled()) {
-              osmlayer.enabled(true);
-            }
-            context.map().centerZoom(d2.loc, 20);
-            if (entity) {
-              context.enter(modeSelect(context, [entityID]));
-            } else {
-              context.loadEntity(entityID, (err, result) => {
-                if (err)
-                  return;
-                const entity2 = result.data.find((e3) => e3.id === entityID);
-                if (entity2)
-                  context.enter(modeSelect(context, [entityID]));
-              });
-            }
-          });
-          if (entity) {
-            let name = utilDisplayName(entity);
-            if (!name) {
-              const preset = _mainPresetIndex.match(entity, context.graph());
-              name = preset && !preset.isFallback() && preset.name();
-            }
-            if (name) {
-              this.innerText = name;
-            }
-          }
-        });
-        context.features().forceVisible(d2.elems);
-        context.map().pan([0, 0]);
-      }).catch((err) => {
-        console.log(err);
+        return _t.html("issues." + d2 + ".title", params);
       });
+      items = items.merge(enter);
+      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
+      var degStr = corePreferences("validate-square-degrees");
+      if (degStr === null) {
+        degStr = DEFAULTSQUARE.toString();
+      }
+      var span = items.selectAll(".square-degrees");
+      var input = span.selectAll(".square-degrees-input").data([0]);
+      input.enter().append("input").attr("type", "number").attr("min", MINSQUARE.toString()).attr("max", MAXSQUARE.toString()).attr("step", "0.5").attr("class", "square-degrees-input").call(utilNoAuto).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        this.select();
+      }).on("keyup", function(d3_event) {
+        if (d3_event.keyCode === 13) {
+          this.blur();
+          this.select();
+        }
+      }).on("blur", changeSquare).merge(input).property("value", degStr);
     }
-    osmoseDetails.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return osmoseDetails;
-    };
-    return osmoseDetails;
-  }
-
-  // modules/ui/osmose_header.js
-  function uiOsmoseHeader() {
-    let _qaItem;
-    function issueTitle(d2) {
-      const unknown = _t("inspector.unknown");
-      if (!d2)
-        return unknown;
-      const s2 = services.osmose.getStrings(d2.itemType);
-      return "title" in s2 ? s2.title : unknown;
+    function changeSquare() {
+      var input = select_default2(this);
+      var degStr = utilGetSetValue(input).trim();
+      var degNum = Number(degStr);
+      if (!isFinite(degNum)) {
+        degNum = DEFAULTSQUARE;
+      } else if (degNum > MAXSQUARE) {
+        degNum = MAXSQUARE;
+      } else if (degNum < MINSQUARE) {
+        degNum = MINSQUARE;
+      }
+      degNum = Math.round(degNum * 10) / 10;
+      degStr = degNum.toString();
+      input.property("value", degStr);
+      corePreferences("validate-square-degrees", degStr);
+      context.validator().revalidateUnsquare();
     }
-    function osmoseHeader(selection2) {
-      const header = selection2.selectAll(".qa-header").data(
-        _qaItem ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      header.exit().remove();
-      const headerEnter = header.enter().append("div").attr("class", "qa-header");
-      const svgEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d2) => d2.id < 0).append("svg").attr("width", "20px").attr("height", "30px").attr("viewbox", "0 0 20 30").attr("class", (d2) => "preset-icon-28 qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.itemType));
-      svgEnter.append("polygon").attr("fill", (d2) => services.osmose.getColor(d2.item)).attr("class", "qaItem-fill").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
-      svgEnter.append("use").attr("class", "icon-annotation").attr("width", "12px").attr("height", "12px").attr("transform", "translate(4, 5.5)").attr("xlink:href", (d2) => d2.icon ? "#" + d2.icon : "");
-      headerEnter.append("div").attr("class", "qa-header-label").text(issueTitle);
+    function isRuleEnabled(d2) {
+      return context.validator().isRuleEnabled(d2);
     }
-    osmoseHeader.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return osmoseHeader;
-    };
-    return osmoseHeader;
-  }
-
-  // modules/ui/view_on_osmose.js
-  function uiViewOnOsmose() {
-    let _qaItem;
-    function viewOnOsmose(selection2) {
-      let url;
-      if (services.osmose && _qaItem instanceof QAItem) {
-        url = services.osmose.itemURL(_qaItem);
-      }
-      const link3 = selection2.selectAll(".view-on-osmose").data(url ? [url] : []);
-      link3.exit().remove();
-      const linkEnter = link3.enter().append("a").attr("class", "view-on-osmose").attr("target", "_blank").attr("rel", "noopener").attr("href", (d2) => d2).call(svgIcon("#iD-icon-out-link", "inline"));
-      linkEnter.append("span").call(_t.append("inspector.view_on_osmose"));
+    function toggleRule(d3_event, d2) {
+      context.validator().toggleRule(d2);
     }
-    viewOnOsmose.what = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return viewOnOsmose;
-    };
-    return viewOnOsmose;
+    context.validator().on("validated.uiSectionValidationRules", function() {
+      window.requestIdleCallback(section.reRender);
+    });
+    return section;
   }
 
-  // modules/ui/osmose_editor.js
-  function uiOsmoseEditor(context) {
-    const dispatch14 = dispatch_default("change");
-    const qaDetails = uiOsmoseDetails(context);
-    const qaHeader = uiOsmoseHeader(context);
-    let _qaItem;
-    function osmoseEditor(selection2) {
-      const header = selection2.selectAll(".header").data([0]);
-      const headerEnter = header.enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("QA.osmose.title"));
-      let body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      let editor = body.selectAll(".qa-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
-      const footer = selection2.selectAll(".footer").data([0]);
-      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnOsmose(context).what(_qaItem));
+  // modules/ui/sections/validation_status.js
+  function uiSectionValidationStatus(context) {
+    var section = uiSection("issues-status", context).content(renderContent).shouldDisplay(function() {
+      var issues = context.validator().getIssues(getOptions());
+      return issues.length === 0;
+    });
+    function getOptions() {
+      return {
+        what: corePreferences("validate-what") || "edited",
+        where: corePreferences("validate-where") || "all"
+      };
     }
-    function osmoseSaveSection(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      const isShown = _qaItem && isSelected;
-      let saveSection = selection2.selectAll(".qa-save").data(
-        isShown ? [_qaItem] : [],
-        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
-      );
-      saveSection.exit().remove();
-      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
-      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
+    function renderContent(selection2) {
+      var box = selection2.selectAll(".box").data([0]);
+      var boxEnter = box.enter().append("div").attr("class", "box");
+      boxEnter.append("div").call(svgIcon("#iD-icon-apply", "pre-text"));
+      var noIssuesMessage = boxEnter.append("span");
+      noIssuesMessage.append("strong").attr("class", "message");
+      noIssuesMessage.append("br");
+      noIssuesMessage.append("span").attr("class", "details");
+      renderIgnoredIssuesReset(selection2);
+      setNoIssuesText(selection2);
     }
-    function qaSaveButtons(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d2) => d2.status + d2.id);
-      buttonSection.exit().remove();
-      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
-      buttonEnter.append("button").attr("class", "button close-button action");
-      buttonEnter.append("button").attr("class", "button ignore-button action");
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.select(".close-button").call(_t.append("QA.keepRight.close")).on("click.close", function(d3_event, d2) {
-        this.blur();
-        const qaService = services.osmose;
-        if (qaService) {
-          d2.newStatus = "done";
-          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
-        }
-      });
-      buttonSection.select(".ignore-button").call(_t.append("QA.keepRight.ignore")).on("click.ignore", function(d3_event, d2) {
-        this.blur();
-        const qaService = services.osmose;
-        if (qaService) {
-          d2.newStatus = "false";
-          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
-        }
+    function renderIgnoredIssuesReset(selection2) {
+      var ignoredIssues = context.validator().getIssues({ what: "all", where: "all", includeDisabledRules: true, includeIgnored: "only" });
+      var resetIgnored = selection2.selectAll(".reset-ignored").data(ignoredIssues.length ? [0] : []);
+      resetIgnored.exit().remove();
+      var resetIgnoredEnter = resetIgnored.enter().append("div").attr("class", "reset-ignored section-footer");
+      resetIgnoredEnter.append("a").attr("href", "#");
+      resetIgnored = resetIgnored.merge(resetIgnoredEnter);
+      resetIgnored.select("a").html(_t.html("inspector.title_count", { title: { html: _t.html("issues.reset_ignored") }, count: ignoredIssues.length }));
+      resetIgnored.on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.validator().resetIgnoredIssues();
       });
     }
-    osmoseEditor.error = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return osmoseEditor;
-    };
-    return utilRebind(osmoseEditor, dispatch14, "on");
-  }
-
-  // modules/modes/select_error.js
-  function modeSelectError(context, selectedErrorID, selectedErrorService) {
-    var mode = {
-      id: "select-error",
-      button: "browse"
-    };
-    var keybinding = utilKeybinding("select-error");
-    var errorService = services[selectedErrorService];
-    var errorEditor;
-    switch (selectedErrorService) {
-      case "improveOSM":
-        errorEditor = uiImproveOsmEditor(context).on("change", function() {
-          context.map().pan([0, 0]);
-          var error = checkSelectedID();
-          if (!error)
+    function setNoIssuesText(selection2) {
+      var opts = getOptions();
+      function checkForHiddenIssues(cases) {
+        for (var type2 in cases) {
+          var hiddenOpts = cases[type2];
+          var hiddenIssues = context.validator().getIssues(hiddenOpts);
+          if (hiddenIssues.length) {
+            selection2.select(".box .details").html("").call(_t.append(
+              "issues.no_issues.hidden_issues." + type2,
+              { count: hiddenIssues.length.toString() }
+            ));
             return;
-          context.ui().sidebar.show(errorEditor.error(error));
+          }
+        }
+        selection2.select(".box .details").html("").call(_t.append("issues.no_issues.hidden_issues.none"));
+      }
+      var messageType;
+      if (opts.what === "edited" && opts.where === "visible") {
+        messageType = "edits_in_view";
+        checkForHiddenIssues({
+          elsewhere: { what: "edited", where: "all" },
+          everything_else: { what: "all", where: "visible" },
+          disabled_rules: { what: "edited", where: "visible", includeDisabledRules: "only" },
+          everything_else_elsewhere: { what: "all", where: "all" },
+          disabled_rules_elsewhere: { what: "edited", where: "all", includeDisabledRules: "only" },
+          ignored_issues: { what: "edited", where: "visible", includeIgnored: "only" },
+          ignored_issues_elsewhere: { what: "edited", where: "all", includeIgnored: "only" }
         });
-        break;
-      case "keepRight":
-        errorEditor = uiKeepRightEditor(context).on("change", function() {
-          context.map().pan([0, 0]);
-          var error = checkSelectedID();
-          if (!error)
-            return;
-          context.ui().sidebar.show(errorEditor.error(error));
+      } else if (opts.what === "edited" && opts.where === "all") {
+        messageType = "edits";
+        checkForHiddenIssues({
+          everything_else: { what: "all", where: "all" },
+          disabled_rules: { what: "edited", where: "all", includeDisabledRules: "only" },
+          ignored_issues: { what: "edited", where: "all", includeIgnored: "only" }
         });
-        break;
-      case "osmose":
-        errorEditor = uiOsmoseEditor(context).on("change", function() {
-          context.map().pan([0, 0]);
-          var error = checkSelectedID();
-          if (!error)
-            return;
-          context.ui().sidebar.show(errorEditor.error(error));
+      } else if (opts.what === "all" && opts.where === "visible") {
+        messageType = "everything_in_view";
+        checkForHiddenIssues({
+          elsewhere: { what: "all", where: "all" },
+          disabled_rules: { what: "all", where: "visible", includeDisabledRules: "only" },
+          disabled_rules_elsewhere: { what: "all", where: "all", includeDisabledRules: "only" },
+          ignored_issues: { what: "all", where: "visible", includeIgnored: "only" },
+          ignored_issues_elsewhere: { what: "all", where: "all", includeIgnored: "only" }
+        });
+      } else if (opts.what === "all" && opts.where === "all") {
+        messageType = "everything";
+        checkForHiddenIssues({
+          disabled_rules: { what: "all", where: "all", includeDisabledRules: "only" },
+          ignored_issues: { what: "all", where: "all", includeIgnored: "only" }
         });
-        break;
-    }
-    var behaviors = [
-      behaviorBreathe(context),
-      behaviorHover(context),
-      behaviorSelect(context),
-      behaviorLasso(context),
-      modeDragNode(context).behavior,
-      modeDragNote(context).behavior
-    ];
-    function checkSelectedID() {
-      if (!errorService)
-        return;
-      var error = errorService.getError(selectedErrorID);
-      if (!error) {
-        context.enter(modeBrowse(context));
       }
-      return error;
-    }
-    mode.zoomToSelected = function() {
-      if (!errorService)
-        return;
-      var error = errorService.getError(selectedErrorID);
-      if (error) {
-        context.map().centerZoomEase(error.loc, 20);
+      if (opts.what === "edited" && context.history().difference().summary().length === 0) {
+        messageType = "no_edits";
       }
-    };
-    mode.enter = function() {
-      var error = checkSelectedID();
-      if (!error)
-        return;
-      behaviors.forEach(context.install);
-      keybinding.on(_t("inspector.zoom_to.key"), mode.zoomToSelected).on("\u238B", esc, true);
-      select_default2(document).call(keybinding);
-      selectError();
-      var sidebar = context.ui().sidebar;
-      sidebar.show(errorEditor.error(error));
-      context.map().on("drawn.select-error", selectError);
-      function selectError(d3_event, drawn) {
-        if (!checkSelectedID())
-          return;
-        var selection2 = context.surface().selectAll(".itemId-" + selectedErrorID + "." + selectedErrorService);
-        if (selection2.empty()) {
-          var source = d3_event && d3_event.type === "zoom" && d3_event.sourceEvent;
-          if (drawn && source && (source.type === "pointermove" || source.type === "mousemove" || source.type === "touchmove")) {
-            context.enter(modeBrowse(context));
-          }
-        } else {
-          selection2.classed("selected", true);
-          context.selectedErrorID(selectedErrorID);
-        }
-      }
-      function esc() {
-        if (context.container().select(".combobox").size())
-          return;
-        context.enter(modeBrowse(context));
-      }
-    };
-    mode.exit = function() {
-      behaviors.forEach(context.uninstall);
-      select_default2(document).call(keybinding.unbind);
-      context.surface().selectAll(".qaItem.selected").classed("selected hover", false);
-      context.map().on("drawn.select-error", null);
-      context.ui().sidebar.hide();
-      context.selectedErrorID(null);
-      context.features().forceVisible([]);
-    };
-    return mode;
+      selection2.select(".box .message").html("").call(_t.append("issues.no_issues.message." + messageType));
+    }
+    context.validator().on("validated.uiSectionValidationStatus", function() {
+      window.requestIdleCallback(section.reRender);
+    });
+    context.map().on(
+      "move.uiSectionValidationStatus",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
   }
 
-  // modules/ui/feature_list.js
-  function uiFeatureList(context) {
-    var _geocodeResults;
-    function featureList(selection2) {
-      var header = selection2.append("div").attr("class", "header fillL");
-      header.append("h2").call(_t.append("inspector.feature_list"));
-      var searchWrap = selection2.append("div").attr("class", "search-header");
-      searchWrap.call(svgIcon("#iD-icon-search", "pre-text"));
-      var search = searchWrap.append("input").attr("placeholder", _t("inspector.search")).attr("type", "search").call(utilNoAuto).on("keypress", keypress).on("keydown", keydown).on("input", inputevent);
-      var listWrap = selection2.append("div").attr("class", "inspector-body");
-      var list2 = listWrap.append("div").attr("class", "feature-list");
-      context.on("exit.feature-list", clearSearch);
-      context.map().on("drawn.feature-list", mapDrawn);
-      context.keybinding().on(uiCmd("\u2318F"), focusSearch);
-      function focusSearch(d3_event) {
-        var mode = context.mode() && context.mode().id;
-        if (mode !== "browse")
-          return;
-        d3_event.preventDefault();
-        search.node().focus();
-      }
-      function keydown(d3_event) {
-        if (d3_event.keyCode === 27) {
-          search.node().blur();
-        }
-      }
-      function keypress(d3_event) {
-        var q2 = search.property("value"), items = list2.selectAll(".feature-list-item");
-        if (d3_event.keyCode === 13 && // ↩ Return
-        q2.length && items.size()) {
-          click(d3_event, items.datum());
-        }
-      }
-      function inputevent() {
-        _geocodeResults = void 0;
-        drawList();
-      }
-      function clearSearch() {
-        search.property("value", "");
-        drawList();
-      }
-      function mapDrawn(e3) {
-        if (e3.full) {
-          drawList();
+  // modules/ui/panes/issues.js
+  function uiPaneIssues(context) {
+    var issuesPane = uiPane("issues", context).key(_t("issues.key")).label(_t.append("issues.title")).description(_t.append("issues.title")).iconName("iD-icon-alert").sections([
+      uiSectionValidationOptions(context),
+      uiSectionValidationStatus(context),
+      uiSectionValidationIssues("issues-errors", "error", context),
+      uiSectionValidationIssues("issues-warnings", "warning", context),
+      uiSectionValidationRules(context)
+    ]);
+    return issuesPane;
+  }
+
+  // modules/ui/settings/custom_data.js
+  function uiSettingsCustomData(context) {
+    var dispatch14 = dispatch_default("change");
+    function render(selection2) {
+      var dataLayer = context.layers().layer("data");
+      var _origSettings = {
+        fileList: dataLayer && dataLayer.fileList() || null,
+        url: corePreferences("settings-custom-data-url")
+      };
+      var _currSettings = {
+        fileList: dataLayer && dataLayer.fileList() || null
+        // url: prefs('settings-custom-data-url')
+      };
+      var modal = uiConfirm(selection2).okButton();
+      modal.classed("settings-modal settings-custom-data", true);
+      modal.select(".modal-section.header").append("h3").call(_t.append("settings.custom_data.header"));
+      var textSection = modal.select(".modal-section.message-text");
+      textSection.append("pre").attr("class", "instructions-file").call(_t.append("settings.custom_data.file.instructions"));
+      textSection.append("input").attr("class", "field-file").attr("type", "file").attr("accept", ".gpx,.kml,.geojson,.json,application/gpx+xml,application/vnd.google-earth.kml+xml,application/geo+json,application/json").property("files", _currSettings.fileList).on("change", function(d3_event) {
+        var files = d3_event.target.files;
+        if (files && files.length) {
+          _currSettings.url = "";
+          textSection.select(".field-url").property("value", "");
+          _currSettings.fileList = files;
+        } else {
+          _currSettings.fileList = null;
         }
+      });
+      textSection.append("h4").call(_t.append("settings.custom_data.or"));
+      textSection.append("pre").attr("class", "instructions-url").call(_t.append("settings.custom_data.url.instructions"));
+      textSection.append("textarea").attr("class", "field-url").attr("placeholder", _t("settings.custom_data.url.placeholder")).call(utilNoAuto).property("value", _currSettings.url);
+      var buttonSection = modal.select(".modal-section.buttons");
+      buttonSection.insert("button", ".ok-button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
+      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
+      buttonSection.select(".ok-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
+      function isSaveDisabled() {
+        return null;
       }
-      function features() {
-        var result = [];
-        var graph = context.graph();
-        var visibleCenter = context.map().extent().center();
-        var q2 = search.property("value").toLowerCase();
-        if (!q2)
-          return result;
-        var locationMatch = sexagesimal.pair(q2.toUpperCase()) || dmsMatcher(q2);
-        if (locationMatch) {
-          var loc = [Number(locationMatch[0]), Number(locationMatch[1])];
-          result.push({
-            id: -1,
-            geometry: "point",
-            type: _t("inspector.location"),
-            name: dmsCoordinatePair([loc[1], loc[0]]),
-            location: loc
-          });
-        }
-        var idMatch = !locationMatch && q2.match(/(?:^|\W)(node|way|relation|note|[nwr])\W{0,2}0*([1-9]\d*)(?:\W|$)/i);
-        if (idMatch) {
-          var elemType = idMatch[1] === "note" ? idMatch[1] : idMatch[1].charAt(0);
-          var elemId = idMatch[2];
-          result.push({
-            id: elemType + elemId,
-            geometry: elemType === "n" ? "point" : elemType === "w" ? "line" : elemType === "note" ? "note" : "relation",
-            type: elemType === "n" ? _t("inspector.node") : elemType === "w" ? _t("inspector.way") : elemType === "note" ? _t("note.note") : _t("inspector.relation"),
-            name: elemId
-          });
-        }
-        var allEntities = graph.entities;
-        var localResults = [];
-        for (var id2 in allEntities) {
-          var entity = allEntities[id2];
-          if (!entity)
-            continue;
-          var name = utilDisplayName(entity) || "";
-          if (name.toLowerCase().indexOf(q2) < 0)
-            continue;
-          var matched = _mainPresetIndex.match(entity, graph);
-          var type2 = matched && matched.name() || utilDisplayType(entity.id);
-          var extent = entity.extent(graph);
-          var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
-          localResults.push({
-            id: entity.id,
-            entity,
-            geometry: entity.geometry(graph),
-            type: type2,
-            name,
-            distance
-          });
-          if (localResults.length > 100)
-            break;
-        }
-        localResults = localResults.sort(function byDistance(a2, b2) {
-          return a2.distance - b2.distance;
-        });
-        result = result.concat(localResults);
-        (_geocodeResults || []).forEach(function(d2) {
-          if (d2.osm_type && d2.osm_id) {
-            var id3 = osmEntity.id.fromOSM(d2.osm_type, d2.osm_id);
-            var tags = {};
-            tags[d2.class] = d2.type;
-            var attrs = { id: id3, type: d2.osm_type, tags };
-            if (d2.osm_type === "way") {
-              attrs.nodes = ["a", "a"];
-            }
-            var tempEntity = osmEntity(attrs);
-            var tempGraph = coreGraph([tempEntity]);
-            var matched2 = _mainPresetIndex.match(tempEntity, tempGraph);
-            var type3 = matched2 && matched2.name() || utilDisplayType(id3);
-            result.push({
-              id: tempEntity.id,
-              geometry: tempEntity.geometry(tempGraph),
-              type: type3,
-              name: d2.display_name,
-              extent: new geoExtent(
-                [Number(d2.boundingbox[3]), Number(d2.boundingbox[0])],
-                [Number(d2.boundingbox[2]), Number(d2.boundingbox[1])]
-              )
-            });
-          }
-        });
-        if (q2.match(/^[0-9]+$/)) {
-          result.push({
-            id: "n" + q2,
-            geometry: "point",
-            type: _t("inspector.node"),
-            name: q2
-          });
-          result.push({
-            id: "w" + q2,
-            geometry: "line",
-            type: _t("inspector.way"),
-            name: q2
-          });
-          result.push({
-            id: "r" + q2,
-            geometry: "relation",
-            type: _t("inspector.relation"),
-            name: q2
-          });
-          result.push({
-            id: "note" + q2,
-            geometry: "note",
-            type: _t("note.note"),
-            name: q2
-          });
-        }
-        return result;
+      function clickCancel() {
+        textSection.select(".field-url").property("value", _origSettings.url);
+        corePreferences("settings-custom-data-url", _origSettings.url);
+        this.blur();
+        modal.close();
       }
-      function drawList() {
-        var value = search.property("value");
-        var results = features();
-        list2.classed("filtered", value.length);
-        var resultsIndicator = list2.selectAll(".no-results-item").data([0]).enter().append("button").property("disabled", true).attr("class", "no-results-item").call(svgIcon("#iD-icon-alert", "pre-text"));
-        resultsIndicator.append("span").attr("class", "entity-name");
-        list2.selectAll(".no-results-item .entity-name").html("").call(_t.append("geocoder.no_results_worldwide"));
-        if (services.geocoder) {
-          list2.selectAll(".geocode-item").data([0]).enter().append("button").attr("class", "geocode-item secondary-action").on("click", geocoderSearch).append("div").attr("class", "label").append("span").attr("class", "entity-name").call(_t.append("geocoder.search"));
+      function clickSave() {
+        _currSettings.url = textSection.select(".field-url").property("value").trim();
+        if (_currSettings.url) {
+          _currSettings.fileList = null;
         }
-        list2.selectAll(".no-results-item").style("display", value.length && !results.length ? "block" : "none");
-        list2.selectAll(".geocode-item").style("display", value && _geocodeResults === void 0 ? "block" : "none");
-        list2.selectAll(".feature-list-item").data([-1]).remove();
-        var items = list2.selectAll(".feature-list-item").data(results, function(d2) {
-          return d2.id;
-        });
-        var enter = items.enter().insert("button", ".geocode-item").attr("class", "feature-list-item").on("mouseover", mouseover).on("mouseout", mouseout).on("click", click);
-        var label = enter.append("div").attr("class", "label");
-        label.each(function(d2) {
-          select_default2(this).call(svgIcon("#iD-icon-" + d2.geometry, "pre-text"));
-        });
-        label.append("span").attr("class", "entity-type").text(function(d2) {
-          return d2.type;
-        });
-        label.append("span").attr("class", "entity-name").classed("has-colour", (d2) => d2.entity && d2.entity.type === "relation" && d2.entity.tags.colour && isColourValid(d2.entity.tags.colour)).style("border-color", (d2) => d2.entity && d2.entity.type === "relation" && d2.entity.tags.colour).text(function(d2) {
-          return d2.name;
-        });
-        enter.style("opacity", 0).transition().style("opacity", 1);
-        items.order();
-        items.exit().remove();
-      }
-      function mouseover(d3_event, d2) {
-        if (d2.id === -1)
-          return;
-        utilHighlightEntities([d2.id], true, context);
-      }
-      function mouseout(d3_event, d2) {
-        if (d2.id === -1)
-          return;
-        utilHighlightEntities([d2.id], false, context);
-      }
-      function click(d3_event, d2) {
-        d3_event.preventDefault();
-        if (d2.location) {
-          context.map().centerZoomEase([d2.location[1], d2.location[0]], 19);
-        } else if (d2.entity) {
-          utilHighlightEntities([d2.id], false, context);
-          context.enter(modeSelect(context, [d2.entity.id]));
-          context.map().zoomToEase(d2.entity);
-        } else if (d2.geometry === "note") {
-          const noteId = d2.id.replace(/\D/g, "");
-          context.loadNote(noteId, (err, result) => {
-            if (err)
-              return;
-            const entity = result.data.find((e3) => e3.id === noteId);
-            if (entity) {
-              const note = services.osm.getNote(noteId);
-              context.map().centerZoom(note.loc, 15);
-              const noteLayer = context.layers().layer("notes");
-              noteLayer.enabled(true);
-              context.enter(modeSelectNote(context, noteId));
-            }
-          });
-        } else {
-          context.zoomToEntity(d2.id);
+        if (_currSettings.fileList) {
+          _currSettings.url = "";
         }
-      }
-      function geocoderSearch() {
-        services.geocoder.search(search.property("value"), function(err, resp) {
-          _geocodeResults = resp || [];
-          drawList();
-        });
+        corePreferences("settings-custom-data-url", _currSettings.url);
+        this.blur();
+        modal.close();
+        dispatch14.call("change", this, _currSettings);
       }
     }
-    return featureList;
+    return utilRebind(render, dispatch14, "on");
   }
 
-  // modules/ui/preset_list.js
-  function uiPresetList(context) {
-    var dispatch14 = dispatch_default("cancel", "choose");
-    var _entityIDs;
-    var _currLoc;
-    var _currentPresets;
-    var _autofocus = false;
-    function presetList(selection2) {
-      if (!_entityIDs)
-        return;
-      var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
-      selection2.html("");
-      var messagewrap = selection2.append("div").attr("class", "header fillL");
-      var message = messagewrap.append("h2").call(_t.append("inspector.choose"));
-      var direction = _mainLocalizer.textDirection() === "rtl" ? "backward" : "forward";
-      messagewrap.append("button").attr("class", "preset-choose").attr("title", _entityIDs.length === 1 ? _t("inspector.edit") : _t("inspector.edit_features")).on("click", function() {
-        dispatch14.call("cancel", this);
-      }).call(svgIcon("#iD-icon-".concat(direction)));
-      function initialKeydown(d3_event) {
-        if (search.property("value").length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes["\u232B"] || d3_event.keyCode === utilKeybinding.keyCodes["\u2326"])) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          operationDelete(context, _entityIDs)();
-        } else if (search.property("value").length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          context.undo();
-        } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
-          select_default2(this).on("keydown", keydown);
-          keydown.call(this, d3_event);
-        }
-      }
-      function keydown(d3_event) {
-        if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"] && // if insertion point is at the end of the string
-        search.node().selectionStart === search.property("value").length) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          var buttons = list2.selectAll(".preset-list-button");
-          if (!buttons.empty())
-            buttons.nodes()[0].focus();
-        }
+  // modules/ui/sections/data_layers.js
+  function uiSectionDataLayers(context) {
+    var settingsCustomData = uiSettingsCustomData(context).on("change", customChanged);
+    var layers = context.layers();
+    var section = uiSection("data-layers", context).label(() => _t.append("map_data.data_layers")).disclosureContent(renderDisclosureContent);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".data-layer-container").data([0]);
+      container.enter().append("div").attr("class", "data-layer-container").merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems).call(drawPanelItems);
+    }
+    function showsLayer(which) {
+      var layer = layers.layer(which);
+      if (layer) {
+        return layer.enabled();
       }
-      function keypress(d3_event) {
-        var value = search.property("value");
-        if (d3_event.keyCode === 13 && // ↩ Return
-        value.length) {
-          list2.selectAll(".preset-list-item:first-child").each(function(d2) {
-            d2.choose.call(this);
-          });
+      return false;
+    }
+    function setLayer(which, enabled) {
+      var mode = context.mode();
+      if (mode && /^draw/.test(mode.id)) return;
+      var layer = layers.layer(which);
+      if (layer) {
+        layer.enabled(enabled);
+        if (!enabled && (which === "osm" || which === "notes")) {
+          context.enter(modeBrowse(context));
         }
       }
-      function inputevent() {
-        var value = search.property("value");
-        list2.classed("filtered", value.length);
-        var results, messageText;
-        if (value.length) {
-          results = presets.search(value, entityGeometries()[0], _currLoc);
-          messageText = _t.html("inspector.results", {
-            n: results.collection.length,
-            search: value
-          });
+    }
+    function toggleLayer(which) {
+      setLayer(which, !showsLayer(which));
+    }
+    function drawOsmItems(selection2) {
+      var osmKeys = ["osm", "notes"];
+      var osmLayers = layers.all().filter(function(obj) {
+        return osmKeys.indexOf(obj.id) !== -1;
+      });
+      var ul = selection2.selectAll(".layer-list-osm").data([0]);
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-osm").merge(ul);
+      var li = ul.selectAll(".list-item").data(osmLayers);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        return "list-item list-item-" + d2.id;
+      });
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        if (d2.id === "osm") {
+          select_default2(this).call(
+            uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).keys([uiCmd("\u2325" + _t("area_fill.wireframe.key"))]).placement("bottom")
+          );
         } else {
-          var entityPresets2 = _entityIDs.map((entityID) => _mainPresetIndex.match(context.graph().entity(entityID), context.graph()));
-          results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc, entityPresets2);
-          messageText = _t.html("inspector.choose");
+          select_default2(this).call(
+            uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).placement("bottom")
+          );
         }
-        list2.call(drawList, results);
-        message.html(messageText);
-      }
-      var searchWrap = selection2.append("div").attr("class", "search-header");
-      searchWrap.call(svgIcon("#iD-icon-search", "pre-text"));
-      var search = searchWrap.append("input").attr("class", "preset-search-input").attr("placeholder", _t("inspector.search")).attr("type", "search").call(utilNoAuto).on("keydown", initialKeydown).on("keypress", keypress).on("input", debounce_default(inputevent));
-      if (_autofocus) {
-        search.node().focus();
-        setTimeout(function() {
-          search.node().focus();
-        }, 0);
-      }
-      var listWrap = selection2.append("div").attr("class", "inspector-body");
-      var entityPresets = _entityIDs.map((entityID) => _mainPresetIndex.match(context.graph().entity(entityID), context.graph()));
-      var list2 = listWrap.append("div").attr("class", "preset-list").call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc, entityPresets));
-      context.features().on("change.preset-list", updateForFeatureHiddenState);
+      });
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
+        toggleLayer(d2.id);
+      });
+      labelEnter.append("span").html(function(d2) {
+        return _t.html("map_data.layers." + d2.id + ".title");
+      });
+      li.merge(liEnter).classed("active", function(d2) {
+        return d2.layer.enabled();
+      }).selectAll("input").property("checked", function(d2) {
+        return d2.layer.enabled();
+      });
     }
-    function drawList(list2, presets) {
-      presets = presets.matchAllGeometry(entityGeometries());
-      var collection = presets.collection.reduce(function(collection2, preset) {
-        if (!preset)
-          return collection2;
-        if (preset.members) {
-          if (preset.members.collection.filter(function(preset2) {
-            return preset2.addable();
-          }).length > 1) {
-            collection2.push(CategoryItem(preset));
-          }
-        } else if (preset.addable()) {
-          collection2.push(PresetItem(preset));
-        }
-        return collection2;
-      }, []);
-      var items = list2.selectAll(".preset-list-item").data(collection, function(d2) {
-        return d2.preset.id;
+    function drawQAItems(selection2) {
+      var qaKeys = ["keepRight", "osmose"];
+      var qaLayers = layers.all().filter(function(obj) {
+        return qaKeys.indexOf(obj.id) !== -1;
+      });
+      var ul = selection2.selectAll(".layer-list-qa").data([0]);
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-qa").merge(ul);
+      var li = ul.selectAll(".list-item").data(qaLayers);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        return "list-item list-item-" + d2.id;
+      });
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).placement("bottom")
+        );
+      });
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
+        toggleLayer(d2.id);
+      });
+      labelEnter.append("span").each(function(d2) {
+        _t.append("map_data.layers." + d2.id + ".title")(select_default2(this));
+      });
+      li.merge(liEnter).classed("active", function(d2) {
+        return d2.layer.enabled();
+      }).selectAll("input").property("checked", function(d2) {
+        return d2.layer.enabled();
       });
-      items.order();
-      items.exit().remove();
-      items.enter().append("div").attr("class", function(item) {
-        return "preset-list-item preset-" + item.preset.id.replace("/", "-");
-      }).classed("current", function(item) {
-        return _currentPresets.indexOf(item.preset) !== -1;
-      }).each(function(item) {
-        select_default2(this).call(item);
-      }).style("opacity", 0).transition().style("opacity", 1);
-      updateForFeatureHiddenState();
     }
-    function itemKeydown(d3_event) {
-      var item = select_default2(this.closest(".preset-list-item"));
-      var parentItem = select_default2(item.node().parentNode.closest(".preset-list-item"));
-      if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"]) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        var nextItem = select_default2(item.node().nextElementSibling);
-        if (nextItem.empty()) {
-          if (!parentItem.empty()) {
-            nextItem = select_default2(parentItem.node().nextElementSibling);
-          }
-        } else if (select_default2(this).classed("expanded")) {
-          nextItem = item.select(".subgrid .preset-list-item:first-child");
-        }
-        if (!nextItem.empty()) {
-          nextItem.select(".preset-list-button").node().focus();
-        }
-      } else if (d3_event.keyCode === utilKeybinding.keyCodes["\u2191"]) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        var previousItem = select_default2(item.node().previousElementSibling);
-        if (previousItem.empty()) {
-          if (!parentItem.empty()) {
-            previousItem = parentItem;
-          }
-        } else if (previousItem.select(".preset-list-button").classed("expanded")) {
-          previousItem = previousItem.select(".subgrid .preset-list-item:last-child");
+    function drawVectorItems(selection2) {
+      var dataLayer = layers.layer("data");
+      var vtData = [
+        {
+          name: "Detroit Neighborhoods/Parks",
+          src: "neighborhoods-parks",
+          tooltip: "Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.",
+          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmur6x34562qp9iv1u3ksf-54hev,jonahadkins.cjksmqxdx33jj2wp90xd9x2md-4e5y2/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
+        },
+        {
+          name: "Detroit Composite POIs",
+          src: "composite-poi",
+          tooltip: "Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.",
+          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmm6a02sli31myxhsr7zf3-2sw8h/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
+        },
+        {
+          name: "Detroit All-The-Places POIs",
+          src: "alltheplaces-poi",
+          tooltip: "Public domain business location data created by web scrapers.",
+          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmswgk340g2vo06p1w9w0j-8fjjc/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
         }
-        if (!previousItem.empty()) {
-          previousItem.select(".preset-list-button").node().focus();
-        } else {
-          var search = select_default2(this.closest(".preset-list-pane")).select(".preset-search-input");
-          search.node().focus();
+      ];
+      var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
+      var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
+      var container = selection2.selectAll(".vectortile-container").data(showVectorItems ? [0] : []);
+      container.exit().remove();
+      var containerEnter = container.enter().append("div").attr("class", "vectortile-container");
+      containerEnter.append("h4").attr("class", "vectortile-header").text("Detroit Vector Tiles (Beta)");
+      containerEnter.append("ul").attr("class", "layer-list layer-list-vectortile");
+      containerEnter.append("div").attr("class", "vectortile-footer").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/osmus/detroit-mapping-challenge").append("span").text("About these layers");
+      container = container.merge(containerEnter);
+      var ul = container.selectAll(".layer-list-vectortile");
+      var li = ul.selectAll(".list-item").data(vtData);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        return "list-item list-item-" + d2.src;
+      });
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        select_default2(this).call(
+          uiTooltip().title(d2.tooltip).placement("top")
+        );
+      });
+      labelEnter.append("input").attr("type", "radio").attr("name", "vectortile").on("change", selectVTLayer);
+      labelEnter.append("span").text(function(d2) {
+        return d2.name;
+      });
+      li.merge(liEnter).classed("active", isVTLayerSelected).selectAll("input").property("checked", isVTLayerSelected);
+      function isVTLayerSelected(d2) {
+        return dataLayer && dataLayer.template() === d2.template;
+      }
+      function selectVTLayer(d3_event, d2) {
+        corePreferences("settings-custom-data-url", d2.template);
+        if (dataLayer) {
+          dataLayer.template(d2.template, d2.src);
+          dataLayer.enabled(true);
         }
-      } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2192" : "\u2190"]) {
+      }
+    }
+    function drawCustomDataItems(selection2) {
+      var dataLayer = layers.layer("data");
+      var hasData = dataLayer && dataLayer.hasData();
+      var showsData = hasData && dataLayer.enabled();
+      var ul = selection2.selectAll(".layer-list-data").data(dataLayer ? [0] : []);
+      ul.exit().remove();
+      var ulEnter = ul.enter().append("ul").attr("class", "layer-list layer-list-data");
+      var liEnter = ulEnter.append("li").attr("class", "list-item-data");
+      var labelEnter = liEnter.append("label").call(
+        uiTooltip().title(() => _t.append("map_data.layers.custom.tooltip")).placement("top")
+      );
+      labelEnter.append("input").attr("type", "checkbox").on("change", function() {
+        toggleLayer("data");
+      });
+      labelEnter.append("span").call(_t.append("map_data.layers.custom.title"));
+      liEnter.append("button").attr("class", "open-data-options").call(
+        uiTooltip().title(() => _t.append("settings.custom_data.tooltip")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
         d3_event.preventDefault();
-        d3_event.stopPropagation();
-        if (!parentItem.empty()) {
-          parentItem.select(".preset-list-button").node().focus();
-        }
-      } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2190" : "\u2192"]) {
+        editCustom();
+      }).call(svgIcon("#iD-icon-more"));
+      liEnter.append("button").attr("class", "zoom-to-data").call(
+        uiTooltip().title(() => _t.append("map_data.layers.custom.zoom")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        if (select_default2(this).classed("disabled")) return;
         d3_event.preventDefault();
         d3_event.stopPropagation();
-        item.datum().choose.call(select_default2(this).node());
-      }
+        dataLayer.fitZoom();
+      }).call(svgIcon("#iD-icon-framed-dot", "monochrome"));
+      ul = ul.merge(ulEnter);
+      ul.selectAll(".list-item-data").classed("active", showsData).selectAll("label").classed("deemphasize", !hasData).selectAll("input").property("disabled", !hasData).property("checked", showsData);
+      ul.selectAll("button.zoom-to-data").classed("disabled", !hasData);
     }
-    function CategoryItem(preset) {
-      var box, sublist, shown = false;
-      function item(selection2) {
-        var wrap2 = selection2.append("div").attr("class", "preset-list-button-wrap category");
-        function click() {
-          var isExpanded = select_default2(this).classed("expanded");
-          var iconName = isExpanded ? _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward" : "#iD-icon-down";
-          select_default2(this).classed("expanded", !isExpanded).attr("title", !isExpanded ? _t("icons.collapse") : _t("icons.expand"));
-          select_default2(this).selectAll("div.label-inner svg.icon use").attr("href", iconName);
-          item.choose();
-        }
-        var geometries = entityGeometries();
-        var button = wrap2.append("button").attr("class", "preset-list-button").attr("title", _t("icons.expand")).classed("expanded", false).call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on("click", click).on("keydown", function(d3_event) {
-          if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2190" : "\u2192"]) {
-            d3_event.preventDefault();
-            d3_event.stopPropagation();
-            if (!select_default2(this).classed("expanded")) {
-              click.call(this, d3_event);
-            }
-          } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2192" : "\u2190"]) {
-            d3_event.preventDefault();
-            d3_event.stopPropagation();
-            if (select_default2(this).classed("expanded")) {
-              click.call(this, d3_event);
-            }
-          } else {
-            itemKeydown.call(this, d3_event);
-          }
-        });
-        var label = button.append("div").attr("class", "label").append("div").attr("class", "label-inner");
-        label.append("div").attr("class", "namepart").call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward", "inline")).append("span").call(preset.nameLabel()).append("span").text("\u2026");
-        box = selection2.append("div").attr("class", "subgrid").style("max-height", "0px").style("opacity", 0);
-        box.append("div").attr("class", "arrow");
-        sublist = box.append("div").attr("class", "preset-list fillL3");
-      }
-      item.choose = function() {
-        if (!box || !sublist)
-          return;
-        if (shown) {
-          shown = false;
-          box.transition().duration(200).style("opacity", "0").style("max-height", "0px").style("padding-bottom", "0px");
-        } else {
-          shown = true;
-          var members = preset.members.matchAllGeometry(entityGeometries());
-          sublist.call(drawList, members);
-          box.transition().duration(200).style("opacity", "1").style("max-height", 200 + members.collection.length * 190 + "px").style("padding-bottom", "10px");
-        }
-      };
-      item.preset = preset;
-      return item;
+    function editCustom() {
+      context.container().call(settingsCustomData);
     }
-    function PresetItem(preset) {
-      function item(selection2) {
-        var wrap2 = selection2.append("div").attr("class", "preset-list-button-wrap");
-        var geometries = entityGeometries();
-        var button = wrap2.append("button").attr("class", "preset-list-button").call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on("click", item.choose).on("keydown", itemKeydown);
-        var label = button.append("div").attr("class", "label").append("div").attr("class", "label-inner");
-        var nameparts = [
-          preset.nameLabel(),
-          preset.subtitleLabel()
-        ].filter(Boolean);
-        label.selectAll(".namepart").data(nameparts, (d2) => d2.stringId).enter().append("div").attr("class", "namepart").text("").each(function(d2) {
-          d2(select_default2(this));
-        });
-        wrap2.call(item.reference.button);
-        selection2.call(item.reference.body);
+    function customChanged(d2) {
+      var dataLayer = layers.layer("data");
+      if (d2 && d2.url) {
+        dataLayer.url(d2.url);
+      } else if (d2 && d2.fileList) {
+        dataLayer.fileList(d2.fileList);
       }
-      item.choose = function() {
-        if (select_default2(this).classed("disabled"))
-          return;
-        if (!context.inIntro()) {
-          _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
-        }
-        context.perform(
-          function(graph) {
-            for (var i3 in _entityIDs) {
-              var entityID = _entityIDs[i3];
-              var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
-              graph = actionChangePreset(entityID, oldPreset, preset)(graph);
-            }
-            return graph;
-          },
-          _t("operations.change_tags.annotation")
-        );
-        context.validator().validate();
-        dispatch14.call("choose", this, preset);
-      };
-      item.help = function(d3_event) {
-        d3_event.stopPropagation();
-        item.reference.toggle();
-      };
-      item.preset = preset;
-      item.reference = uiTagReference(preset.reference(), context);
-      return item;
     }
-    function updateForFeatureHiddenState() {
-      if (!_entityIDs.every(context.hasEntity))
-        return;
-      var geometries = entityGeometries();
-      var button = context.container().selectAll(".preset-list .preset-list-button");
-      button.call(uiTooltip().destroyAny);
-      button.each(function(item, index) {
-        var hiddenPresetFeaturesId;
-        for (var i3 in geometries) {
-          hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i3]);
-          if (hiddenPresetFeaturesId)
-            break;
-        }
-        var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
-        select_default2(this).classed("disabled", isHiddenPreset);
-        if (isHiddenPreset) {
-          var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
-          select_default2(this).call(
-            uiTooltip().title(() => _t.append("inspector.hidden_preset." + (isAutoHidden ? "zoom" : "manual"), {
-              features: _t("feature." + hiddenPresetFeaturesId + ".description")
-            })).placement(index < 2 ? "bottom" : "top")
-          );
-        }
+    function drawPanelItems(selection2) {
+      var panelsListEnter = selection2.selectAll(".md-extras-list").data([0]).enter().append("ul").attr("class", "layer-list md-extras-list");
+      var historyPanelLabelEnter = panelsListEnter.append("li").attr("class", "history-panel-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("map_data.history_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.history.key"))]).placement("top")
+      );
+      historyPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        context.ui().info.toggle("history");
       });
-    }
-    presetList.autofocus = function(val) {
-      if (!arguments.length)
-        return _autofocus;
-      _autofocus = val;
-      return presetList;
-    };
-    presetList.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      _currLoc = null;
-      if (_entityIDs && _entityIDs.length) {
-        const extent = _entityIDs.reduce(function(extent2, entityID) {
-          var entity = context.graph().entity(entityID);
-          return extent2.extend(entity.extent(context.graph()));
-        }, geoExtent());
-        _currLoc = extent.center();
-        var presets = _entityIDs.map(function(entityID) {
-          return _mainPresetIndex.match(context.entity(entityID), context.graph());
-        });
-        presetList.presets(presets);
-      }
-      return presetList;
-    };
-    presetList.presets = function(val) {
-      if (!arguments.length)
-        return _currentPresets;
-      _currentPresets = val;
-      return presetList;
-    };
-    function entityGeometries() {
-      var counts = {};
-      for (var i3 in _entityIDs) {
-        var entityID = _entityIDs[i3];
-        var entity = context.entity(entityID);
-        var geometry = entity.geometry(context.graph());
-        if (geometry === "vertex" && entity.isOnAddressLine(context.graph())) {
-          geometry = "point";
-        }
-        if (!counts[geometry])
-          counts[geometry] = 0;
-        counts[geometry] += 1;
-      }
-      return Object.keys(counts).sort(function(geom1, geom2) {
-        return counts[geom2] - counts[geom1];
+      historyPanelLabelEnter.append("span").call(_t.append("map_data.history_panel.title"));
+      var measurementPanelLabelEnter = panelsListEnter.append("li").attr("class", "measurement-panel-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("map_data.measurement_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.measurement.key"))]).placement("top")
+      );
+      measurementPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        context.ui().info.toggle("measurement");
       });
+      measurementPanelLabelEnter.append("span").call(_t.append("map_data.measurement_panel.title"));
     }
-    return utilRebind(presetList, dispatch14, "on");
+    context.layers().on("change.uiSectionDataLayers", section.reRender);
+    context.map().on(
+      "move.uiSectionDataLayers",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
   }
 
-  // modules/ui/inspector.js
-  function uiInspector(context) {
-    var presetList = uiPresetList(context);
-    var entityEditor = uiEntityEditor(context);
-    var wrap2 = select_default2(null), presetPane = select_default2(null), editorPane = select_default2(null);
-    var _state = "select";
-    var _entityIDs;
-    var _newFeature = false;
-    function inspector(selection2) {
-      presetList.entityIDs(_entityIDs).autofocus(_newFeature).on("choose", inspector.setPreset).on("cancel", function() {
-        inspector.setPreset();
+  // modules/ui/sections/map_features.js
+  function uiSectionMapFeatures(context) {
+    var _features = context.features().keys();
+    var section = uiSection("map-features", context).label(() => _t.append("map_data.map_features")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".layer-feature-list-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "layer-feature-list-container");
+      containerEnter.append("ul").attr("class", "layer-list layer-feature-list");
+      var footer = containerEnter.append("div").attr("class", "feature-list-links section-footer");
+      footer.append("a").attr("class", "feature-list-link").attr("role", "button").attr("href", "#").call(_t.append("issues.disable_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.features().disableAll();
       });
-      entityEditor.state(_state).entityIDs(_entityIDs).on("choose", inspector.showList);
-      wrap2 = selection2.selectAll(".panewrap").data([0]);
-      var enter = wrap2.enter().append("div").attr("class", "panewrap");
-      enter.append("div").attr("class", "preset-list-pane pane");
-      enter.append("div").attr("class", "entity-editor-pane pane");
-      wrap2 = wrap2.merge(enter);
-      presetPane = wrap2.selectAll(".preset-list-pane");
-      editorPane = wrap2.selectAll(".entity-editor-pane");
-      function shouldDefaultToPresetList() {
-        if (_state !== "select")
-          return false;
-        if (_entityIDs.length !== 1)
-          return false;
-        var entityID = _entityIDs[0];
-        var entity = context.hasEntity(entityID);
-        if (!entity)
-          return false;
-        if (entity.hasNonGeometryTags())
-          return false;
-        if (_newFeature)
-          return true;
-        if (entity.geometry(context.graph()) !== "vertex")
-          return false;
-        if (context.graph().parentRelations(entity).length)
-          return false;
-        if (context.validator().getEntityIssues(entityID).length)
-          return false;
-        if (entity.isHighwayIntersection(context.graph()))
-          return false;
-        return true;
-      }
-      if (shouldDefaultToPresetList()) {
-        wrap2.style("right", "-100%");
-        editorPane.classed("hide", true);
-        presetPane.classed("hide", false).call(presetList);
-      } else {
-        wrap2.style("right", "0%");
-        presetPane.classed("hide", true);
-        editorPane.classed("hide", false).call(entityEditor);
-      }
-      var footer = selection2.selectAll(".footer").data([0]);
-      footer = footer.enter().append("div").attr("class", "footer").merge(footer);
-      footer.call(
-        uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0]))
-      );
+      footer.append("a").attr("class", "feature-list-link").attr("role", "button").attr("href", "#").call(_t.append("issues.enable_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.features().enableAll();
+      });
+      container = container.merge(containerEnter);
+      container.selectAll(".layer-feature-list").call(drawListItems, _features, "checkbox", "feature", clickFeature, showsFeature);
     }
-    inspector.showList = function(presets) {
-      presetPane.classed("hide", false);
-      wrap2.transition().styleTween("right", function() {
-        return value_default("0%", "-100%");
-      }).on("end", function() {
-        editorPane.classed("hide", true);
+    function drawListItems(selection2, data, type2, name, change, active) {
+      var items = selection2.selectAll("li").data(data);
+      items.exit().remove();
+      var enter = items.enter().append("li").call(
+        uiTooltip().title(function(d2) {
+          var tip = _t.append(name + "." + d2 + ".tooltip");
+          if (autoHiddenFeature(d2)) {
+            var msg = showsLayer("osm") ? _t.append("map_data.autohidden") : _t.append("map_data.osmhidden");
+            return (selection3) => {
+              selection3.call(tip);
+              selection3.append("div").call(msg);
+            };
+          }
+          return tip;
+        }).placement("top")
+      );
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
+      label.append("span").html(function(d2) {
+        return _t.html(name + "." + d2 + ".description");
       });
-      if (presets) {
-        presetList.presets(presets);
-      }
-      presetPane.call(presetList.autofocus(true));
-    };
-    inspector.setPreset = function(preset) {
-      if (preset && preset.id === "type/multipolygon") {
-        presetPane.call(presetList.autofocus(true));
-      } else {
-        editorPane.classed("hide", false);
-        wrap2.transition().styleTween("right", function() {
-          return value_default("-100%", "0%");
-        }).on("end", function() {
-          presetPane.classed("hide", true);
-        });
-        if (preset) {
-          entityEditor.presets([preset]);
-        }
-        editorPane.call(entityEditor);
-      }
-    };
-    inspector.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      _state = val;
-      entityEditor.state(_state);
-      context.container().selectAll(".field-help-body").remove();
-      return inspector;
-    };
-    inspector.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return inspector;
-    };
-    inspector.newFeature = function(val) {
-      if (!arguments.length)
-        return _newFeature;
-      _newFeature = val;
-      return inspector;
-    };
-    return inspector;
-  }
-
-  // modules/ui/lasso.js
-  function uiLasso(context) {
-    var group, polygon2;
-    lasso.coordinates = [];
-    function lasso(selection2) {
-      context.container().classed("lasso", true);
-      group = selection2.append("g").attr("class", "lasso hide");
-      polygon2 = group.append("path").attr("class", "lasso-path");
-      group.call(uiToggle(true));
+      items = items.merge(enter);
+      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", autoHiddenFeature);
     }
-    function draw() {
-      if (polygon2) {
-        polygon2.data([lasso.coordinates]).attr("d", function(d2) {
-          return "M" + d2.join(" L") + " Z";
-        });
-      }
+    function autoHiddenFeature(d2) {
+      return context.features().autoHidden(d2);
     }
-    lasso.extent = function() {
-      return lasso.coordinates.reduce(function(extent, point2) {
-        return extent.extend(geoExtent(point2));
-      }, geoExtent());
-    };
-    lasso.p = function(_2) {
-      if (!arguments.length)
-        return lasso;
-      lasso.coordinates.push(_2);
-      draw();
-      return lasso;
-    };
-    lasso.close = function() {
-      if (group) {
-        group.call(uiToggle(false, function() {
-          select_default2(this).remove();
-        }));
-      }
-      context.container().classed("lasso", false);
-    };
-    return lasso;
-  }
-
-  // modules/ui/source_switch.js
-  function uiSourceSwitch(context) {
-    var keys2;
-    function click(d3_event) {
-      d3_event.preventDefault();
-      var osm = context.connection();
-      if (!osm)
-        return;
-      if (context.inIntro())
-        return;
-      if (context.history().hasChanges() && !window.confirm(_t("source_switch.lose_changes")))
-        return;
-      var isLive = select_default2(this).classed("live");
-      isLive = !isLive;
-      context.enter(modeBrowse(context));
-      context.history().clearSaved();
-      context.flush();
-      select_default2(this).html(isLive ? _t.html("source_switch.live") : _t.html("source_switch.dev")).classed("live", isLive).classed("chip", isLive);
-      osm.switch(isLive ? keys2[0] : keys2[1]);
+    function showsFeature(d2) {
+      return context.features().enabled(d2);
     }
-    var sourceSwitch = function(selection2) {
-      selection2.append("a").attr("href", "#").call(_t.append("source_switch.live")).attr("class", "live chip").on("click", click);
-    };
-    sourceSwitch.keys = function(_2) {
-      if (!arguments.length)
-        return keys2;
-      keys2 = _2;
-      return sourceSwitch;
-    };
-    return sourceSwitch;
+    function clickFeature(d3_event, d2) {
+      context.features().toggle(d2);
+    }
+    function showsLayer(id2) {
+      var layer = context.layers().layer(id2);
+      return layer && layer.enabled();
+    }
+    context.features().on("change.map_features", section.reRender);
+    return section;
   }
 
-  // modules/ui/spinner.js
-  function uiSpinner(context) {
-    var osm = context.connection();
-    return function(selection2) {
-      var img = selection2.append("img").attr("src", context.imagePath("loader-black.gif")).style("opacity", 0);
-      if (osm) {
-        osm.on("loading.spinner", function() {
-          img.transition().style("opacity", 1);
-        }).on("loaded.spinner", function() {
-          img.transition().style("opacity", 0);
-        });
-      }
-    };
-  }
-
-  // modules/ui/sections/privacy.js
-  function uiSectionPrivacy(context) {
-    let section = uiSection("preferences-third-party", context).label(() => _t.append("preferences.privacy.title")).disclosureContent(renderDisclosureContent);
+  // modules/ui/sections/map_style_options.js
+  function uiSectionMapStyleOptions(context) {
+    var section = uiSection("fill-area", context).label(() => _t.append("map_data.style_options")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
     function renderDisclosureContent(selection2) {
-      selection2.selectAll(".privacy-options-list").data([0]).enter().append("ul").attr("class", "layer-list privacy-options-list");
-      let thirdPartyIconsEnter = selection2.select(".privacy-options-list").selectAll(".privacy-third-party-icons-item").data([corePreferences("preferences.privacy.thirdpartyicons") || "true"]).enter().append("li").attr("class", "privacy-third-party-icons-item").append("label").call(
-        uiTooltip().title(() => _t.append("preferences.privacy.third_party_icons.tooltip")).placement("bottom")
+      var container = selection2.selectAll(".layer-fill-list").data([0]);
+      container.enter().append("ul").attr("class", "layer-list layer-fill-list").merge(container).call(drawListItems, context.map().areaFillOptions, "radio", "area_fill", setFill, isActiveFill);
+      var container2 = selection2.selectAll(".layer-visual-diff-list").data([0]);
+      container2.enter().append("ul").attr("class", "layer-list layer-visual-diff-list").merge(container2).call(drawListItems, ["highlight_edits"], "checkbox", "visual_diff", toggleHighlightEdited, function() {
+        return context.surface().classed("highlight-edited");
+      });
+    }
+    function drawListItems(selection2, data, type2, name, change, active) {
+      var items = selection2.selectAll("li").data(data);
+      items.exit().remove();
+      var enter = items.enter().append("li").call(
+        uiTooltip().title(function(d2) {
+          return _t.append(name + "." + d2 + ".tooltip");
+        }).keys(function(d2) {
+          var key = d2 === "wireframe" ? _t("area_fill.wireframe.key") : null;
+          if (d2 === "highlight_edits") key = _t("map_data.highlight_edits.key");
+          return key ? [key] : null;
+        }).placement("top")
       );
-      thirdPartyIconsEnter.append("input").attr("type", "checkbox").on("change", (d3_event, d2) => {
-        d3_event.preventDefault();
-        corePreferences("preferences.privacy.thirdpartyicons", d2 === "true" ? "false" : "true");
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
+      label.append("span").html(function(d2) {
+        return _t.html(name + "." + d2 + ".description");
       });
-      thirdPartyIconsEnter.append("span").call(_t.append("preferences.privacy.third_party_icons.description"));
-      selection2.selectAll(".privacy-third-party-icons-item").classed("active", (d2) => d2 === "true").select("input").property("checked", (d2) => d2 === "true");
-      selection2.selectAll(".privacy-link").data([0]).enter().append("div").attr("class", "privacy-link").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/openstreetmap/iD/blob/release/PRIVACY.md").append("span").call(_t.append("preferences.privacy.privacy_link"));
+      items = items.merge(enter);
+      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
     }
-    corePreferences.onChange("preferences.privacy.thirdpartyicons", section.reRender);
+    function isActiveFill(d2) {
+      return context.map().activeAreaFill() === d2;
+    }
+    function toggleHighlightEdited(d3_event) {
+      d3_event.preventDefault();
+      context.map().toggleHighlightEdited();
+    }
+    function setFill(d3_event, d2) {
+      context.map().activeAreaFill(d2);
+    }
+    context.map().on("changeHighlighting.ui_style, changeAreaFill.ui_style", section.reRender);
     return section;
   }
 
-  // modules/ui/splash.js
-  function uiSplash(context) {
-    return (selection2) => {
-      if (context.history().hasRestorableChanges())
-        return;
-      let updateMessage = "";
-      const sawPrivacyVersion = corePreferences("sawPrivacyVersion");
-      let showSplash = !corePreferences("sawSplash");
-      if (sawPrivacyVersion !== context.privacyVersion) {
-        updateMessage = _t("splash.privacy_update");
-        showSplash = true;
-      }
-      if (!showSplash)
-        return;
-      corePreferences("sawSplash", true);
-      corePreferences("sawPrivacyVersion", context.privacyVersion);
-      _mainFileFetcher.get("intro_graph");
-      let modalSelection = uiModal(selection2);
-      modalSelection.select(".modal").attr("class", "modal-splash modal");
-      let introModal = modalSelection.select(".content").append("div").attr("class", "fillL");
-      introModal.append("div").attr("class", "modal-section").append("h3").call(_t.append("splash.welcome"));
-      let modalSection = introModal.append("div").attr("class", "modal-section");
-      modalSection.append("p").html(_t.html("splash.text", {
-        version: context.version,
-        website: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/develop/CHANGELOG.md#whats-new">' + _t.html("splash.changelog") + "</a>" },
-        github: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/issues">github.com</a>' }
-      }));
-      modalSection.append("p").html(_t.html("splash.privacy", {
-        updateMessage,
-        privacyLink: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t("splash.privacy_policy") + "</a>" }
-      }));
-      uiSectionPrivacy(context).label(() => _t.append("splash.privacy_settings")).render(modalSection);
-      let buttonWrap = introModal.append("div").attr("class", "modal-actions");
-      let walkthrough = buttonWrap.append("button").attr("class", "walkthrough").on("click", () => {
-        context.container().call(uiIntro(context));
-        modalSelection.close();
-      });
-      walkthrough.append("svg").attr("class", "logo logo-walkthrough").append("use").attr("xlink:href", "#iD-logo-walkthrough");
-      walkthrough.append("div").call(_t.append("splash.walkthrough"));
-      let startEditing = buttonWrap.append("button").attr("class", "start-editing").on("click", modalSelection.close);
-      startEditing.append("svg").attr("class", "logo logo-features").append("use").attr("xlink:href", "#iD-logo-features");
-      startEditing.append("div").call(_t.append("splash.start"));
-      modalSelection.select("button.close").attr("class", "hide");
-    };
-  }
-
-  // modules/ui/status.js
-  function uiStatus(context) {
-    var osm = context.connection();
-    return function(selection2) {
-      if (!osm)
-        return;
-      function update(err, apiStatus) {
-        selection2.html("");
-        if (err) {
-          if (apiStatus === "connectionSwitched") {
-            return;
-          } else if (apiStatus === "rateLimited") {
-            selection2.call(_t.append("osm_api_status.message.rateLimit")).append("a").attr("href", "#").attr("class", "api-status-login").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("login")).on("click.login", function(d3_event) {
-              d3_event.preventDefault();
-              osm.authenticate();
-            });
-          } else {
-            var throttledRetry = throttle_default(function() {
-              context.loadTiles(context.projection);
-              osm.reloadApiStatus();
-            }, 2e3);
-            selection2.call(_t.append("osm_api_status.message.error", { suffix: " " })).append("a").attr("href", "#").call(_t.append("osm_api_status.retry")).on("click.retry", function(d3_event) {
-              d3_event.preventDefault();
-              throttledRetry();
-            });
-          }
-        } else if (apiStatus === "readonly") {
-          selection2.call(_t.append("osm_api_status.message.readonly"));
-        } else if (apiStatus === "offline") {
-          selection2.call(_t.append("osm_api_status.message.offline"));
+  // modules/ui/settings/local_photos.js
+  function uiSettingsLocalPhotos(context) {
+    var dispatch14 = dispatch_default("change");
+    var photoLayer = context.layers().layer("local-photos");
+    var modal;
+    function render(selection2) {
+      modal = uiConfirm(selection2).okButton();
+      modal.classed("settings-modal settings-local-photos", true);
+      modal.select(".modal-section.header").append("h3").call(_t.append("local_photos.header"));
+      modal.select(".modal-section.message-text").append("div").classed("local-photos", true);
+      var instructionsSection = modal.select(".modal-section.message-text .local-photos").append("div").classed("instructions", true);
+      instructionsSection.append("p").classed("instructions-local-photos", true).call(_t.append("local_photos.file.instructions"));
+      instructionsSection.append("input").classed("field-file", true).attr("type", "file").attr("multiple", "multiple").attr("accept", ".jpg,.jpeg,.png,image/png,image/jpeg").style("visibility", "hidden").attr("id", "local-photo-files").on("change", function(d3_event) {
+        var files = d3_event.target.files;
+        if (files && files.length) {
+          photoList.select("ul").append("li").classed("placeholder", true).append("div");
+          dispatch14.call("change", this, files);
         }
-        selection2.attr("class", "api-status " + (err ? "error" : apiStatus));
-      }
-      osm.on("apiStatusChange.uiStatus", update);
-      context.history().on("storage_error", () => {
-        selection2.selectAll("span.local-storage-full").remove();
-        selection2.append("span").attr("class", "local-storage-full").call(_t.append("osm_api_status.message.local_storage_full"));
-        selection2.classed("error", true);
+        d3_event.target.value = null;
       });
-      window.setInterval(function() {
-        osm.reloadApiStatus();
-      }, 9e4);
-      osm.reloadApiStatus();
-    };
-  }
-
-  // modules/ui/version.js
-  var sawVersion = null;
-  var isNewVersion = false;
-  var isNewUser = false;
-  function uiVersion(context) {
-    var currVersion = context.version;
-    var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
-    if (sawVersion === null && matchedVersion !== null) {
-      if (corePreferences("sawVersion")) {
-        isNewUser = false;
-        isNewVersion = corePreferences("sawVersion") !== currVersion && currVersion.indexOf("-") === -1;
-      } else {
-        isNewUser = true;
-        isNewVersion = true;
-      }
-      corePreferences("sawVersion", currVersion);
-      sawVersion = currVersion;
+      instructionsSection.append("label").attr("for", "local-photo-files").classed("button", true).call(_t.append("local_photos.file.label"));
+      const photoList = modal.select(".modal-section.message-text .local-photos").append("div").append("div").classed("list-local-photos", true);
+      photoList.append("ul");
+      updatePhotoList(photoList.select("ul"));
+      context.layers().on("change", () => updatePhotoList(photoList.select("ul")));
     }
-    return function(selection2) {
-      selection2.append("a").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD").text(currVersion);
-      if (isNewVersion && !isNewUser) {
-        selection2.append("a").attr("class", "badge").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new").call(svgIcon("#maki-gift")).call(
-          uiTooltip().title(() => _t.append("version.whats_new", { version: currVersion })).placement("top").scrollContainer(context.container().select(".main-footer-wrap"))
-        );
+    function updatePhotoList(container) {
+      var _a3;
+      function locationUnavailable(d2) {
+        return !(isArray_default(d2.loc) && isNumber_default(d2.loc[0]) && isNumber_default(d2.loc[1]));
       }
-    };
+      container.selectAll("li.placeholder").remove();
+      let selection2 = container.selectAll("li").data((_a3 = photoLayer.getPhotos()) != null ? _a3 : [], (d2) => d2.id);
+      selection2.exit().remove();
+      const selectionEnter = selection2.enter().append("li");
+      selectionEnter.append("span").classed("filename", true);
+      selectionEnter.append("button").classed("form-field-button zoom-to-data", true).attr("title", _t("local_photos.zoom_single")).call(svgIcon("#iD-icon-framed-dot"));
+      selectionEnter.append("button").classed("form-field-button no-geolocation", true).call(svgIcon("#iD-icon-alert")).call(
+        uiTooltip().title(() => _t.append("local_photos.no_geolocation.tooltip")).placement("left")
+      );
+      selectionEnter.append("button").classed("form-field-button remove", true).attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
+      selection2 = selection2.merge(selectionEnter);
+      selection2.classed("invalid", locationUnavailable);
+      selection2.select("span.filename").text((d2) => d2.name).attr("title", (d2) => d2.name);
+      selection2.select("span.filename").on("click", (d3_event, d2) => {
+        photoLayer.openPhoto(d3_event, d2, false);
+      });
+      selection2.select("button.zoom-to-data").on("click", (d3_event, d2) => {
+        photoLayer.openPhoto(d3_event, d2, true);
+      });
+      selection2.select("button.remove").on("click", (d3_event, d2) => {
+        photoLayer.removePhoto(d2.id);
+        updatePhotoList(container);
+      });
+    }
+    return utilRebind(render, dispatch14, "on");
   }
 
-  // modules/ui/zoom.js
-  function uiZoom(context) {
-    var zooms = [{
-      id: "zoom-in",
-      icon: "iD-icon-plus",
-      title: _t.append("zoom.in"),
-      action: zoomIn,
-      disabled: function() {
-        return !context.map().canZoomIn();
-      },
-      disabledTitle: _t.append("zoom.disabled.in"),
-      key: "+"
-    }, {
-      id: "zoom-out",
-      icon: "iD-icon-minus",
-      title: _t.append("zoom.out"),
-      action: zoomOut,
-      disabled: function() {
-        return !context.map().canZoomOut();
-      },
-      disabledTitle: _t.append("zoom.disabled.out"),
-      key: "-"
-    }];
-    function zoomIn(d3_event) {
-      if (d3_event.shiftKey)
-        return;
-      d3_event.preventDefault();
-      context.map().zoomIn();
-    }
-    function zoomOut(d3_event) {
-      if (d3_event.shiftKey)
-        return;
-      d3_event.preventDefault();
-      context.map().zoomOut();
-    }
-    function zoomInFurther(d3_event) {
-      if (d3_event.shiftKey)
-        return;
-      d3_event.preventDefault();
-      context.map().zoomInFurther();
-    }
-    function zoomOutFurther(d3_event) {
-      if (d3_event.shiftKey)
-        return;
-      d3_event.preventDefault();
-      context.map().zoomOutFurther();
+  // modules/ui/sections/photo_overlays.js
+  function uiSectionPhotoOverlays(context) {
+    var settingsLocalPhotos = uiSettingsLocalPhotos(context).on("change", localPhotosChanged);
+    var layers = context.layers();
+    var section = uiSection("photo-overlays", context).label(() => _t.append("photo_overlays.title")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".photo-overlay-container").data([0]);
+      container.enter().append("div").attr("class", "photo-overlay-container").merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter).call(drawLocalPhotos);
     }
-    return function(selection2) {
-      var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(function(d2) {
-        if (d2.disabled()) {
-          return d2.disabledTitle;
+    function drawPhotoItems(selection2) {
+      var photoKeys = context.photos().overlayLayerIDs();
+      var photoLayers = layers.all().filter(function(obj) {
+        return photoKeys.indexOf(obj.id) !== -1;
+      });
+      var data = photoLayers.filter(function(obj) {
+        if (!obj.layer.supported()) return false;
+        if (layerEnabled(obj)) return true;
+        if (typeof obj.layer.validHere === "function") {
+          return obj.layer.validHere(context.map().extent(), context.map().zoom());
         }
-        return d2.title;
-      }).keys(function(d2) {
-        return [d2.key];
+        return true;
       });
-      var lastPointerUpType;
-      var buttons = selection2.selectAll("button").data(zooms).enter().append("button").attr("class", function(d2) {
-        return d2.id;
-      }).on("pointerup.editor", function(d3_event) {
-        lastPointerUpType = d3_event.pointerType;
-      }).on("click.editor", function(d3_event, d2) {
-        if (!d2.disabled()) {
-          d2.action(d3_event);
-        } else if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
-          context.ui().flash.duration(2e3).iconName("#" + d2.icon).iconClass("disabled").label(d2.disabledTitle)();
+      function layerSupported(d2) {
+        return d2.layer && d2.layer.supported();
+      }
+      function layerEnabled(d2) {
+        return layerSupported(d2) && d2.layer.enabled();
+      }
+      function layerRendered(d2) {
+        var _a3, _b3, _c;
+        return (_c = (_b3 = (_a3 = d2.layer).rendered) == null ? void 0 : _b3.call(_a3, context.map().zoom())) != null ? _c : true;
+      }
+      var ul = selection2.selectAll(".layer-list-photos").data([0]);
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-photos").merge(ul);
+      var li = ul.selectAll(".list-item-photos").data(data, (d2) => d2.id);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        var classes = "list-item-photos list-item-" + d2.id;
+        if (d2.id === "mapillary-signs" || d2.id === "mapillary-map-features") {
+          classes += " indented";
         }
-        lastPointerUpType = null;
-      }).call(tooltipBehavior);
-      buttons.each(function(d2) {
-        select_default2(this).call(svgIcon("#" + d2.icon, "light"));
+        return classes;
       });
-      utilKeybinding.plusKeys.forEach(function(key) {
-        context.keybinding().on([key], zoomIn);
-        context.keybinding().on([uiCmd("\u2325" + key)], zoomInFurther);
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        var titleID;
+        if (d2.id === "mapillary-signs") titleID = "mapillary.signs.tooltip";
+        else if (d2.id === "mapillary") titleID = "mapillary_images.tooltip";
+        else if (d2.id === "kartaview") titleID = "kartaview_images.tooltip";
+        else titleID = d2.id.replace(/-/g, "_") + ".tooltip";
+        select_default2(this).call(
+          uiTooltip().title(() => {
+            if (!layerRendered(d2)) {
+              return _t.append("street_side.minzoom_tooltip");
+            } else {
+              return _t.append(titleID);
+            }
+          }).placement("top")
+        );
       });
-      utilKeybinding.minusKeys.forEach(function(key) {
-        context.keybinding().on([key], zoomOut);
-        context.keybinding().on([uiCmd("\u2325" + key)], zoomOutFurther);
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
+        toggleLayer(d2.id);
       });
-      function updateButtonStates() {
-        buttons.classed("disabled", function(d2) {
-          return d2.disabled();
-        }).each(function() {
-          var selection3 = select_default2(this);
-          if (!selection3.select(".tooltip.in").empty()) {
-            selection3.call(tooltipBehavior.updateContent);
-          }
-        });
-      }
-      updateButtonStates();
-      context.map().on("move.uiZoom", updateButtonStates);
-    };
-  }
-
-  // modules/ui/sections/raw_tag_editor.js
-  function uiSectionRawTagEditor(id2, context) {
-    var section = uiSection(id2, context).classes("raw-tag-editor").label(function() {
-      var count = Object.keys(_tags).filter(function(d2) {
-        return d2;
-      }).length;
-      return _t.append("inspector.title_count", { title: _t("inspector.tags"), count });
-    }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
-    var taginfo = services.taginfo;
-    var dispatch14 = dispatch_default("change");
-    var availableViews = [
-      { id: "list", icon: "#fas-th-list" },
-      { id: "text", icon: "#fas-i-cursor" }
-    ];
-    let _discardTags = {};
-    _mainFileFetcher.get("discarded").then((d2) => {
-      _discardTags = d2;
-    }).catch(() => {
-    });
-    var _tagView = corePreferences("raw-tag-editor-view") || "list";
-    var _readOnlyTags = [];
-    var _orderedKeys = [];
-    var _showBlank = false;
-    var _pendingChange = null;
-    var _state;
-    var _presets;
-    var _tags;
-    var _entityIDs;
-    var _didInteract = false;
-    function interacted() {
-      _didInteract = true;
-    }
-    function renderDisclosureContent(wrap2) {
-      _orderedKeys = _orderedKeys.filter(function(key) {
-        return _tags[key] !== void 0;
+      labelEnter.append("span").html(function(d2) {
+        var id2 = d2.id;
+        if (id2 === "mapillary-signs") id2 = "photo_overlays.traffic_signs";
+        return _t.html(id2.replace(/-/g, "_") + ".title");
       });
-      var all = Object.keys(_tags).sort();
-      var missingKeys = utilArrayDifference(all, _orderedKeys);
-      for (var i3 in missingKeys) {
-        _orderedKeys.push(missingKeys[i3]);
+      li.merge(liEnter).classed("active", layerEnabled).selectAll("input").property("disabled", (d2) => !layerRendered(d2)).property("checked", layerEnabled);
+    }
+    function drawPhotoTypeItems(selection2) {
+      var data = context.photos().allPhotoTypes();
+      function typeEnabled(d2) {
+        return context.photos().showsPhotoType(d2);
       }
-      var rowData = _orderedKeys.map(function(key, i4) {
-        return { index: i4, key, value: _tags[key] };
+      var ul = selection2.selectAll(".layer-list-photo-types").data([0]);
+      ul.exit().remove();
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-photo-types").merge(ul);
+      var li = ul.selectAll(".list-item-photo-types").data(context.photos().shouldFilterByPhotoType() ? data : []);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        return "list-item-photo-types list-item-" + d2;
       });
-      if (!rowData.length || _showBlank) {
-        _showBlank = false;
-        rowData.push({ index: rowData.length, key: "", value: "" });
-      }
-      var options2 = wrap2.selectAll(".raw-tag-options").data([0]);
-      options2.exit().remove();
-      var optionsEnter = options2.enter().insert("div", ":first-child").attr("class", "raw-tag-options").attr("role", "tablist");
-      var optionEnter = optionsEnter.selectAll(".raw-tag-option").data(availableViews, function(d2) {
-        return d2.id;
-      }).enter();
-      optionEnter.append("button").attr("class", function(d2) {
-        return "raw-tag-option raw-tag-option-" + d2.id + (_tagView === d2.id ? " selected" : "");
-      }).attr("aria-selected", function(d2) {
-        return _tagView === d2.id;
-      }).attr("role", "tab").attr("title", function(d2) {
-        return _t("icons." + d2.id);
-      }).on("click", function(d3_event, d2) {
-        _tagView = d2.id;
-        corePreferences("raw-tag-editor-view", d2.id);
-        wrap2.selectAll(".raw-tag-option").classed("selected", function(datum2) {
-          return datum2 === d2;
-        }).attr("aria-selected", function(datum2) {
-          return datum2 === d2;
-        });
-        wrap2.selectAll(".tag-text").classed("hide", d2.id !== "text").each(setTextareaHeight);
-        wrap2.selectAll(".tag-list, .add-row").classed("hide", d2.id !== "list");
-      }).each(function(d2) {
-        select_default2(this).call(svgIcon(d2.icon));
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("photo_overlays.photo_type." + d2 + ".tooltip")).placement("top")
+        );
       });
-      var textData = rowsToText(rowData);
-      var textarea = wrap2.selectAll(".tag-text").data([0]);
-      textarea = textarea.enter().append("textarea").attr("class", "tag-text" + (_tagView !== "text" ? " hide" : "")).call(utilNoAuto).attr("placeholder", _t("inspector.key_value")).attr("spellcheck", "false").merge(textarea);
-      textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on("input", setTextareaHeight).on("focus", interacted).on("blur", textChanged).on("change", textChanged);
-      var list2 = wrap2.selectAll(".tag-list").data([0]);
-      list2 = list2.enter().append("ul").attr("class", "tag-list" + (_tagView !== "list" ? " hide" : "")).merge(list2);
-      var addRowEnter = wrap2.selectAll(".add-row").data([0]).enter().append("div").attr("class", "add-row" + (_tagView !== "list" ? " hide" : ""));
-      addRowEnter.append("button").attr("class", "add-tag").attr("aria-label", _t("inspector.add_to_tag")).call(svgIcon("#iD-icon-plus", "light")).call(uiTooltip().title(() => _t.append("inspector.add_to_tag")).placement(_mainLocalizer.textDirection() === "ltr" ? "right" : "left")).on("click", addTag);
-      addRowEnter.append("div").attr("class", "space-value");
-      addRowEnter.append("div").attr("class", "space-buttons");
-      var items = list2.selectAll(".tag-row").data(rowData, function(d2) {
-        return d2.key;
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
+        context.photos().togglePhotoType(d2);
       });
-      items.exit().each(unbind).remove();
-      var itemsEnter = items.enter().append("li").attr("class", "tag-row").classed("readonly", isReadOnly);
-      var innerWrap = itemsEnter.append("div").attr("class", "inner-wrap");
-      innerWrap.append("div").attr("class", "key-wrap").append("input").property("type", "text").attr("class", "key").call(utilNoAuto).on("focus", interacted).on("blur", keyChange).on("change", keyChange);
-      innerWrap.append("div").attr("class", "value-wrap").append("input").property("type", "text").attr("class", "value").call(utilNoAuto).on("focus", interacted).on("blur", valueChange).on("change", valueChange).on("keydown.push-more", pushMore);
-      innerWrap.append("button").attr("class", "form-field-button remove").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
-      items = items.merge(itemsEnter).sort(function(a2, b2) {
-        return a2.index - b2.index;
+      labelEnter.append("span").html(function(d2) {
+        return _t.html("photo_overlays.photo_type." + d2 + ".title");
       });
-      items.each(function(d2) {
-        var row = select_default2(this);
-        var key = row.select("input.key");
-        var value = row.select("input.value");
-        if (_entityIDs && taginfo && _state !== "hover") {
-          bindTypeahead(key, value);
-        }
-        var referenceOptions = { key: d2.key };
-        if (typeof d2.value === "string") {
-          referenceOptions.value = d2.value;
-        }
-        var reference = uiTagReference(referenceOptions, context);
-        if (_state === "hover") {
-          reference.showing(false);
-        }
-        row.select(".inner-wrap").call(reference.button);
-        row.call(reference.body);
-        row.select("button.remove");
+      li.merge(liEnter).classed("active", typeEnabled).selectAll("input").property("checked", typeEnabled);
+    }
+    function drawDateFilter(selection2) {
+      var data = context.photos().dateFilters();
+      function filterEnabled(d2) {
+        return context.photos().dateFilterValue(d2);
+      }
+      var ul = selection2.selectAll(".layer-list-date-filter").data([0]);
+      ul.exit().remove();
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-date-filter").merge(ul);
+      var li = ul.selectAll(".list-item-date-filter").data(context.photos().shouldFilterByDate() ? data : []);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", "list-item-date-filter");
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("photo_overlays.date_filter." + d2 + ".tooltip")).placement("top")
+        );
       });
-      items.selectAll("input.key").attr("title", function(d2) {
-        return d2.key;
-      }).call(utilGetSetValue, function(d2) {
-        return d2.key;
-      }).attr("readonly", function(d2) {
-        return isReadOnly(d2) || null;
+      labelEnter.append("span").each(function(d2) {
+        _t.append("photo_overlays.date_filter." + d2 + ".title")(select_default2(this));
       });
-      items.selectAll("input.value").attr("title", function(d2) {
-        return Array.isArray(d2.value) ? d2.value.filter(Boolean).join("\n") : d2.value;
-      }).classed("mixed", function(d2) {
-        return Array.isArray(d2.value);
-      }).attr("placeholder", function(d2) {
-        return typeof d2.value === "string" ? null : _t("inspector.multiple_values");
-      }).call(utilGetSetValue, function(d2) {
-        return typeof d2.value === "string" ? d2.value : "";
-      }).attr("readonly", function(d2) {
-        return isReadOnly(d2) || null;
+      labelEnter.append("input").attr("type", "date").attr("class", "list-item-input").attr("placeholder", _t("units.year_month_day")).call(utilNoAuto).each(function(d2) {
+        utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d2) || "");
+      }).on("change", function(d3_event, d2) {
+        var value = utilGetSetValue(select_default2(this)).trim();
+        context.photos().setDateFilter(d2, value, true);
+        li.selectAll("input").each(function(d4) {
+          utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d4) || "");
+        });
       });
-      items.selectAll("button.remove").on(
-        ("PointerEvent" in window ? "pointer" : "mouse") + "down",
-        // 'click' fires too late - #5878
-        (d3_event, d2) => {
-          if (d3_event.button !== 0)
-            return;
-          removeTag(d3_event, d2);
-        }
-      );
+      li = li.merge(liEnter).classed("active", filterEnabled);
     }
-    function isReadOnly(d2) {
-      for (var i3 = 0; i3 < _readOnlyTags.length; i3++) {
-        if (d2.key.match(_readOnlyTags[i3]) !== null) {
-          return true;
-        }
+    function drawUsernameFilter(selection2) {
+      function filterEnabled() {
+        return context.photos().usernames();
+      }
+      var ul = selection2.selectAll(".layer-list-username-filter").data([0]);
+      ul.exit().remove();
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-username-filter").merge(ul);
+      var li = ul.selectAll(".list-item-username-filter").data(context.photos().shouldFilterByUsername() ? ["username-filter"] : []);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", "list-item-username-filter");
+      var labelEnter = liEnter.append("label").each(function() {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("photo_overlays.username_filter.tooltip")).placement("top")
+        );
+      });
+      labelEnter.append("span").call(_t.append("photo_overlays.username_filter.title"));
+      labelEnter.append("input").attr("type", "text").attr("class", "list-item-input").call(utilNoAuto).property("value", usernameValue).on("change", function() {
+        var value = select_default2(this).property("value");
+        context.photos().setUsernameFilter(value, true);
+        select_default2(this).property("value", usernameValue);
+      });
+      li.merge(liEnter).classed("active", filterEnabled);
+      function usernameValue() {
+        var usernames = context.photos().usernames();
+        if (usernames) return usernames.join("; ");
+        return usernames;
       }
-      return false;
-    }
-    function setTextareaHeight() {
-      if (_tagView !== "text")
-        return;
-      var selection2 = select_default2(this);
-      var matches = selection2.node().value.match(/\n/g);
-      var lineCount = 2 + Number(matches && matches.length);
-      var lineHeight = 20;
-      selection2.style("height", lineCount * lineHeight + "px");
     }
-    function stringify3(s2) {
-      return JSON.stringify(s2).slice(1, -1);
+    function toggleLayer(which) {
+      setLayer(which, !showsLayer(which));
     }
-    function unstringify(s2) {
-      var leading = "";
-      var trailing = "";
-      if (s2.length < 1 || s2.charAt(0) !== '"') {
-        leading = '"';
-      }
-      if (s2.length < 2 || s2.charAt(s2.length - 1) !== '"' || s2.charAt(s2.length - 1) === '"' && s2.charAt(s2.length - 2) === "\\") {
-        trailing = '"';
+    function showsLayer(which) {
+      var layer = layers.layer(which);
+      if (layer) {
+        return layer.enabled();
       }
-      return JSON.parse(leading + s2 + trailing);
+      return false;
     }
-    function rowsToText(rows) {
-      var str = rows.filter(function(row) {
-        return row.key && row.key.trim() !== "";
-      }).map(function(row) {
-        var rawVal = row.value;
-        if (typeof rawVal !== "string")
-          rawVal = "*";
-        var val = rawVal ? stringify3(rawVal) : "";
-        return stringify3(row.key) + "=" + val;
-      }).join("\n");
-      if (_state !== "hover" && str.length) {
-        return str + "\n";
+    function setLayer(which, enabled) {
+      var layer = layers.layer(which);
+      if (layer) {
+        layer.enabled(enabled);
       }
-      return str;
     }
-    function textChanged() {
-      var newText = this.value.trim();
-      var newTags = {};
-      newText.split("\n").forEach(function(row) {
-        var m2 = row.match(/^\s*([^=]+)=(.*)$/);
-        if (m2 !== null) {
-          var k2 = context.cleanTagKey(unstringify(m2[1].trim()));
-          var v2 = context.cleanTagValue(unstringify(m2[2].trim()));
-          newTags[k2] = v2;
-        }
-      });
-      var tagDiff = utilTagDiff(_tags, newTags);
-      if (!tagDiff.length)
-        return;
-      _pendingChange = _pendingChange || {};
-      tagDiff.forEach(function(change) {
-        if (isReadOnly({ key: change.key }))
-          return;
-        if (change.newVal === "*" && typeof change.oldVal !== "string")
-          return;
-        if (change.type === "-") {
-          _pendingChange[change.key] = void 0;
-        } else if (change.type === "+") {
-          _pendingChange[change.key] = change.newVal || "";
-        }
+    function drawLocalPhotos(selection2) {
+      var photoLayer = layers.layer("local-photos");
+      var hasData = photoLayer && photoLayer.hasData();
+      var showsData = hasData && photoLayer.enabled();
+      var ul = selection2.selectAll(".layer-list-local-photos").data(photoLayer ? [0] : []);
+      ul.exit().remove();
+      var ulEnter = ul.enter().append("ul").attr("class", "layer-list layer-list-local-photos");
+      var localPhotosEnter = ulEnter.append("li").attr("class", "list-item-local-photos");
+      var localPhotosLabelEnter = localPhotosEnter.append("label").call(uiTooltip().title(() => _t.append("local_photos.tooltip")));
+      localPhotosLabelEnter.append("input").attr("type", "checkbox").on("change", function() {
+        toggleLayer("local-photos");
       });
-      if (Object.keys(_pendingChange).length === 0) {
-        _pendingChange = null;
-        return;
-      }
-      scheduleChange();
+      localPhotosLabelEnter.call(_t.append("local_photos.header"));
+      localPhotosEnter.append("button").attr("class", "open-data-options").call(
+        uiTooltip().title(() => _t.append("local_photos.tooltip_edit")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        editLocalPhotos();
+      }).call(svgIcon("#iD-icon-more"));
+      localPhotosEnter.append("button").attr("class", "zoom-to-data").call(
+        uiTooltip().title(() => _t.append("local_photos.zoom")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        if (select_default2(this).classed("disabled")) return;
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        photoLayer.fitZoom();
+      }).call(svgIcon("#iD-icon-framed-dot", "monochrome"));
+      ul = ul.merge(ulEnter);
+      ul.selectAll(".list-item-local-photos").classed("active", showsData).selectAll("label").classed("deemphasize", !hasData).selectAll("input").property("disabled", !hasData).property("checked", showsData);
+      ul.selectAll("button.zoom-to-data").classed("disabled", !hasData);
     }
-    function pushMore(d3_event) {
-      if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll(".tag-list li:last-child input.value").node() === this && utilGetSetValue(select_default2(this))) {
-        addTag();
-      }
+    function editLocalPhotos() {
+      context.container().call(settingsLocalPhotos);
     }
-    function bindTypeahead(key, value) {
-      if (isReadOnly(key.datum()))
-        return;
-      if (Array.isArray(value.datum().value)) {
-        value.call(uiCombobox(context, "tag-value").minItems(1).fetcher(function(value2, callback) {
-          var keyString = utilGetSetValue(key);
-          if (!_tags[keyString])
-            return;
-          var data = _tags[keyString].map(function(tagValue) {
-            if (!tagValue) {
-              return {
-                value: " ",
-                title: _t("inspector.empty"),
-                display: (selection2) => selection2.text("").classed("virtual-option", true).call(_t.append("inspector.empty"))
-              };
-            }
-            return {
-              value: tagValue,
-              title: tagValue
-            };
-          });
-          callback(data);
-        }));
-        return;
-      }
-      var geometry = context.graph().geometry(_entityIDs[0]);
-      key.call(uiCombobox(context, "tag-key").fetcher(function(value2, callback) {
-        taginfo.keys({
-          debounce: true,
-          geometry,
-          query: value2
-        }, function(err, data) {
-          if (!err) {
-            const filtered = data.filter((d2) => _tags[d2.value] === void 0).filter((d2) => !(d2.value in _discardTags)).filter((d2) => !/_\d$/.test(d2)).filter((d2) => d2.value.toLowerCase().includes(value2.toLowerCase()));
-            callback(sort(value2, filtered));
-          }
+    function localPhotosChanged(d2) {
+      var localPhotosLayer = layers.layer("local-photos");
+      localPhotosLayer.fileList(d2);
+    }
+    context.layers().on("change.uiSectionPhotoOverlays", section.reRender);
+    context.photos().on("change.uiSectionPhotoOverlays", section.reRender);
+    context.map().on(
+      "move.photo_overlays",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
+  }
+
+  // modules/ui/panes/map_data.js
+  function uiPaneMapData(context) {
+    var mapDataPane = uiPane("map-data", context).key(_t("map_data.key")).label(_t.append("map_data.title")).description(_t.append("map_data.description")).iconName("iD-icon-data").sections([
+      uiSectionDataLayers(context),
+      uiSectionPhotoOverlays(context),
+      uiSectionMapStyleOptions(context),
+      uiSectionMapFeatures(context)
+    ]);
+    return mapDataPane;
+  }
+
+  // modules/ui/panes/preferences.js
+  function uiPanePreferences(context) {
+    let preferencesPane = uiPane("preferences", context).key(_t("preferences.key")).label(_t.append("preferences.title")).description(_t.append("preferences.description")).iconName("fas-user-cog").sections([
+      uiSectionPrivacy(context)
+    ]);
+    return preferencesPane;
+  }
+
+  // modules/ui/init.js
+  function uiInit(context) {
+    var _initCounter = 0;
+    var _needWidth = {};
+    var _lastPointerType;
+    function render(container) {
+      container.on("click.ui", function(d3_event) {
+        if (d3_event.button !== 0) return;
+        if (!d3_event.composedPath) return;
+        var isOkayTarget = d3_event.composedPath().some(function(node) {
+          return node.nodeType === 1 && // clicking <input> focuses it and/or changes a value
+          (node.nodeName === "INPUT" || // clicking <label> affects its <input> by default
+          node.nodeName === "LABEL" || // clicking <a> opens a hyperlink by default
+          node.nodeName === "A");
         });
-      }));
-      value.call(uiCombobox(context, "tag-value").fetcher(function(value2, callback) {
-        taginfo.values({
-          debounce: true,
-          key: utilGetSetValue(key),
-          geometry,
-          query: value2
-        }, function(err, data) {
-          if (!err) {
-            const filtered = data.filter((d2) => d2.value.toLowerCase().includes(value2.toLowerCase()));
-            callback(sort(value2, filtered));
-          }
+        if (isOkayTarget) return;
+        d3_event.preventDefault();
+      });
+      var detected = utilDetect();
+      if ("GestureEvent" in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
+      // but we only need to do this on desktop Safari anyway. – #7694
+      !detected.isMobileWebKit) {
+        container.on("gesturestart.ui gesturechange.ui gestureend.ui", function(d3_event) {
+          d3_event.preventDefault();
         });
-      }).caseSensitive(allowUpperCaseTagValues.test(utilGetSetValue(key))));
-      function sort(value2, data) {
-        var sameletter = [];
-        var other = [];
-        for (var i3 = 0; i3 < data.length; i3++) {
-          if (data[i3].value.substring(0, value2.length) === value2) {
-            sameletter.push(data[i3]);
-          } else {
-            other.push(data[i3]);
+      }
+      if ("PointerEvent" in window) {
+        select_default2(window).on("pointerdown.ui pointerup.ui", function(d3_event) {
+          var pointerType = d3_event.pointerType || "mouse";
+          if (_lastPointerType !== pointerType) {
+            _lastPointerType = pointerType;
+            container.attr("pointer", pointerType);
           }
+        }, true);
+      } else {
+        _lastPointerType = "mouse";
+        container.attr("pointer", "mouse");
+      }
+      container.attr("lang", _mainLocalizer.localeCode()).attr("dir", _mainLocalizer.textDirection());
+      container.call(uiFullScreen(context));
+      var map2 = context.map();
+      map2.redrawEnable(false);
+      map2.on("hitMinZoom.ui", function() {
+        ui.flash.iconName("#iD-icon-no").label(_t.append("cannot_zoom"))();
+      });
+      container.append("svg").attr("id", "ideditor-defs").call(ui.svgDefs);
+      container.append("div").attr("class", "sidebar").call(ui.sidebar);
+      var content = container.append("div").attr("class", "main-content active");
+      content.append("div").attr("class", "top-toolbar-wrap").append("div").attr("class", "top-toolbar fillD").call(uiTopToolbar(context));
+      content.append("div").attr("class", "main-map").attr("dir", "ltr").call(map2);
+      var overMap = content.append("div").attr("class", "over-map");
+      overMap.append("div").attr("class", "select-trap").text("t");
+      overMap.call(uiMapInMap(context)).call(uiNotice(context));
+      overMap.append("div").attr("class", "spinner").call(uiSpinner(context));
+      var controlsWrap = overMap.append("div").attr("class", "map-controls-wrap");
+      var controls = controlsWrap.append("div").attr("class", "map-controls");
+      controls.append("div").attr("class", "map-control zoombuttons").call(uiZoom(context));
+      controls.append("div").attr("class", "map-control zoom-to-selection-control").call(uiZoomToSelection(context));
+      controls.append("div").attr("class", "map-control geolocate-control").call(uiGeolocate(context));
+      controlsWrap.on("wheel.mapControls", function(d3_event) {
+        if (!d3_event.deltaX) {
+          controlsWrap.node().scrollTop += d3_event.deltaY;
         }
-        return sameletter.concat(other);
+      });
+      var panes = overMap.append("div").attr("class", "map-panes");
+      var uiPanes = [
+        uiPaneBackground(context),
+        uiPaneMapData(context),
+        uiPaneIssues(context),
+        uiPanePreferences(context),
+        uiPaneHelp(context)
+      ];
+      uiPanes.forEach(function(pane) {
+        controls.append("div").attr("class", "map-control map-pane-control " + pane.id + "-control").call(pane.renderToggleButton);
+        panes.call(pane.renderPane);
+      });
+      ui.info = uiInfo(context);
+      overMap.call(ui.info);
+      overMap.append("div").attr("class", "photoviewer").classed("al", true).classed("hide", true).call(ui.photoviewer);
+      overMap.append("div").attr("class", "attribution-wrap").attr("dir", "ltr").call(uiAttribution(context));
+      var about = content.append("div").attr("class", "map-footer");
+      about.append("div").attr("class", "api-status").call(uiStatus(context));
+      var footer = about.append("div").attr("class", "map-footer-bar fillD");
+      footer.append("div").attr("class", "flash-wrap footer-hide");
+      var footerWrap = footer.append("div").attr("class", "main-footer-wrap footer-show");
+      footerWrap.append("div").attr("class", "scale-block").call(uiScale(context));
+      var aboutList = footerWrap.append("div").attr("class", "info-block").append("ul").attr("class", "map-footer-list");
+      aboutList.append("li").attr("class", "user-list").call(uiContributors(context));
+      var apiConnections = context.connection().apiConnections();
+      if (apiConnections && apiConnections.length > 1) {
+        aboutList.append("li").attr("class", "source-switch").call(
+          uiSourceSwitch(context).keys(apiConnections)
+        );
       }
-    }
-    function unbind() {
-      var row = select_default2(this);
-      row.selectAll("input.key").call(uiCombobox.off, context);
-      row.selectAll("input.value").call(uiCombobox.off, context);
-    }
-    function keyChange(d3_event, d2) {
-      if (select_default2(this).attr("readonly"))
-        return;
-      var kOld = d2.key;
-      if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === void 0)
-        return;
-      var kNew = context.cleanTagKey(this.value.trim());
-      if (isReadOnly({ key: kNew })) {
-        this.value = kOld;
-        return;
+      aboutList.append("li").attr("class", "issues-info").call(uiIssuesInfo(context));
+      aboutList.append("li").attr("class", "feature-warning").call(uiFeatureInfo(context));
+      var issueLinks = aboutList.append("li");
+      issueLinks.append("a").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD/issues").attr("aria-label", _t("report_a_bug")).call(svgIcon("#iD-icon-bug", "light")).call(uiTooltip().title(() => _t.append("report_a_bug")).placement("top"));
+      issueLinks.append("a").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD/blob/develop/CONTRIBUTING.md#translating").attr("aria-label", _t("help_translate")).call(svgIcon("#iD-icon-translate", "light")).call(uiTooltip().title(() => _t.append("help_translate")).placement("top"));
+      aboutList.append("li").attr("class", "version").call(uiVersion(context));
+      if (!context.embed()) {
+        aboutList.call(uiAccount(context));
       }
-      if (kNew && kNew !== kOld && _tags[kNew] !== void 0) {
-        this.value = kOld;
-        section.selection().selectAll(".tag-list input.value").each(function(d4) {
-          if (d4.key === kNew) {
-            var input = select_default2(this).node();
-            input.focus();
-            input.select();
+      ui.onResize();
+      map2.redrawEnable(true);
+      ui.hash = behaviorHash(context);
+      ui.hash();
+      if (!ui.hash.hadLocation) {
+        map2.centerZoom([0, 0], 2);
+      }
+      window.onbeforeunload = function() {
+        return context.save();
+      };
+      window.onunload = function() {
+        context.history().unlock();
+      };
+      select_default2(window).on("resize.editor", function() {
+        ui.onResize();
+      });
+      var panPixels = 80;
+      context.keybinding().on("\u232B", function(d3_event) {
+        d3_event.preventDefault();
+      }).on([_t("sidebar.key"), "`", "\xB2", "@"], ui.sidebar.toggle).on("\u2190", pan([panPixels, 0])).on("\u2191", pan([0, panPixels])).on("\u2192", pan([-panPixels, 0])).on("\u2193", pan([0, -panPixels])).on(uiCmd("\u2325\u2190"), pan([map2.dimensions()[0], 0])).on(uiCmd("\u2325\u2191"), pan([0, map2.dimensions()[1]])).on(uiCmd("\u2325\u2192"), pan([-map2.dimensions()[0], 0])).on(uiCmd("\u2325\u2193"), pan([0, -map2.dimensions()[1]])).on(uiCmd("\u2318" + _t("background.key")), function quickSwitch(d3_event) {
+        if (d3_event) {
+          d3_event.stopImmediatePropagation();
+          d3_event.preventDefault();
+        }
+        var previousBackground = context.background().findSource(corePreferences("background-last-used-toggle"));
+        if (previousBackground) {
+          var currentBackground = context.background().baseLayerSource();
+          corePreferences("background-last-used-toggle", currentBackground.id);
+          corePreferences("background-last-used", previousBackground.id);
+          context.background().baseLayerSource(previousBackground);
+        }
+      }).on(_t("area_fill.wireframe.key"), function toggleWireframe(d3_event) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        context.map().toggleWireframe();
+      }).on(uiCmd("\u2325" + _t("area_fill.wireframe.key")), function toggleOsmData(d3_event) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        var mode = context.mode();
+        if (mode && /^draw/.test(mode.id)) return;
+        var layer = context.layers().layer("osm");
+        if (layer) {
+          layer.enabled(!layer.enabled());
+          if (!layer.enabled()) {
+            context.enter(modeBrowse(context));
           }
+        }
+      }).on(_t("map_data.highlight_edits.key"), function toggleHighlightEdited(d3_event) {
+        d3_event.preventDefault();
+        context.map().toggleHighlightEdited();
+      });
+      context.on("enter.editor", function(entered) {
+        container.classed("mode-" + entered.id, true);
+      }).on("exit.editor", function(exited) {
+        container.classed("mode-" + exited.id, false);
+      });
+      context.enter(modeBrowse(context));
+      if (!_initCounter++) {
+        if (!ui.hash.startWalkthrough) {
+          context.container().call(uiSplash(context)).call(uiRestore(context));
+        }
+        context.container().call(ui.shortcuts);
+      }
+      var osm = context.connection();
+      var auth = uiLoading(context).message(_t.html("loading_auth")).blocking(true);
+      if (osm && auth) {
+        osm.on("authLoading.ui", function() {
+          context.container().call(auth);
+        }).on("authDone.ui", function() {
+          auth.close();
         });
-        return;
       }
-      _pendingChange = _pendingChange || {};
-      if (kOld) {
-        if (kOld === kNew)
-          return;
-        _pendingChange[kNew] = _pendingChange[kOld] || { oldKey: kOld };
-        _pendingChange[kOld] = void 0;
-      } else {
-        let row = this.parentNode.parentNode;
-        let inputVal = select_default2(row).selectAll("input.value");
-        let vNew = context.cleanTagValue(utilGetSetValue(inputVal));
-        _pendingChange[kNew] = vNew;
-        utilGetSetValue(inputVal, vNew);
+      _initCounter++;
+      if (ui.hash.startWalkthrough) {
+        ui.hash.startWalkthrough = false;
+        context.container().call(uiIntro(context));
       }
-      var existingKeyIndex = _orderedKeys.indexOf(kOld);
-      if (existingKeyIndex !== -1)
-        _orderedKeys[existingKeyIndex] = kNew;
-      d2.key = kNew;
-      this.value = kNew;
-      scheduleChange();
-    }
-    function valueChange(d3_event, d2) {
-      if (isReadOnly(d2))
-        return;
-      if (typeof d2.value !== "string" && !this.value)
-        return;
-      if (_pendingChange && _pendingChange.hasOwnProperty(d2.key) && _pendingChange[d2.key] === void 0)
-        return;
-      _pendingChange = _pendingChange || {};
-      _pendingChange[d2.key] = context.cleanTagValue(this.value);
-      scheduleChange();
-    }
-    function removeTag(d3_event, d2) {
-      if (isReadOnly(d2))
-        return;
-      if (d2.key === "") {
-        _showBlank = false;
-        section.reRender();
-      } else {
-        _orderedKeys = _orderedKeys.filter(function(key) {
-          return key !== d2.key;
-        });
-        _pendingChange = _pendingChange || {};
-        _pendingChange[d2.key] = void 0;
-        scheduleChange();
+      function pan(d2) {
+        return function(d3_event) {
+          if (d3_event.shiftKey) return;
+          if (context.container().select(".combobox").size()) return;
+          d3_event.preventDefault();
+          context.map().pan(d2, 100);
+        };
       }
     }
-    function addTag() {
-      window.setTimeout(function() {
-        _showBlank = true;
-        section.reRender();
-        section.selection().selectAll(".tag-list li:last-child input.key").node().focus();
-      }, 20);
-    }
-    function scheduleChange() {
-      var entityIDs = _entityIDs;
-      window.setTimeout(function() {
-        if (!_pendingChange)
-          return;
-        dispatch14.call("change", this, entityIDs, _pendingChange);
-        _pendingChange = null;
-      }, 10);
-    }
-    section.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      if (_state !== val) {
-        _orderedKeys = [];
-        _state = val;
-      }
-      return section;
+    let ui = {};
+    let _loadPromise;
+    ui.ensureLoaded = () => {
+      if (_loadPromise) return _loadPromise;
+      return _loadPromise = Promise.all([
+        // must have strings and presets before loading the UI
+        _mainLocalizer.ensureLoaded(),
+        _mainPresetIndex.ensureLoaded()
+      ]).then(() => {
+        if (!context.container().empty()) render(context.container());
+      }).catch((err) => console.error(err));
     };
-    section.presets = function(val) {
-      if (!arguments.length)
-        return _presets;
-      _presets = val;
-      if (_presets && _presets.length && _presets[0].isFallback()) {
-        section.disclosureExpanded(true);
-      } else if (!_didInteract) {
-        section.disclosureExpanded(null);
-      }
-      return section;
+    ui.restart = function() {
+      context.keybinding().clear();
+      _loadPromise = null;
+      context.container().selectAll("*").remove();
+      ui.ensureLoaded();
     };
-    section.tags = function(val) {
-      if (!arguments.length)
-        return _tags;
-      _tags = val;
-      return section;
+    ui.lastPointerType = function() {
+      return _lastPointerType;
     };
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
-        _entityIDs = val;
-        _orderedKeys = [];
+    ui.svgDefs = svgDefs(context);
+    ui.flash = uiFlash(context);
+    ui.sidebar = uiSidebar(context);
+    ui.photoviewer = uiPhotoviewer(context);
+    ui.shortcuts = uiShortcuts(context);
+    ui.onResize = function(withPan) {
+      var map2 = context.map();
+      var mapDimensions = utilGetDimensions(context.container().select(".main-content"), true);
+      utilGetDimensions(context.container().select(".sidebar"), true);
+      if (withPan !== void 0) {
+        map2.redrawEnable(false);
+        map2.pan(withPan);
+        map2.redrawEnable(true);
       }
-      return section;
-    };
-    section.readOnlyTags = function(val) {
-      if (!arguments.length)
-        return _readOnlyTags;
-      _readOnlyTags = val;
-      return section;
-    };
-    return utilRebind(section, dispatch14, "on");
-  }
-
-  // modules/ui/data_editor.js
-  function uiDataEditor(context) {
-    var dataHeader = uiDataHeader();
-    var rawTagEditor = uiSectionRawTagEditor("custom-data-tag-editor", context).expandedByDefault(true).readOnlyTags([/./]);
-    var _datum;
-    function dataEditor(selection2) {
-      var header = selection2.selectAll(".header").data([0]);
-      var headerEnter = header.enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
-        context.enter(modeBrowse(context));
-      }).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("map_data.title"));
-      var body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      var editor = body.selectAll(".data-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section data-editor").merge(editor).call(dataHeader.datum(_datum));
-      var rte = body.selectAll(".raw-tag-editor").data([0]);
-      rte.enter().append("div").attr("class", "raw-tag-editor data-editor").merge(rte).call(
-        rawTagEditor.tags(_datum && _datum.properties || {}).state("hover").render
-      ).selectAll("textarea.tag-text").attr("readonly", true).classed("readonly", true);
-    }
-    dataEditor.datum = function(val) {
-      if (!arguments.length)
-        return _datum;
-      _datum = val;
-      return this;
+      map2.dimensions(mapDimensions);
+      ui.photoviewer.onMapResize();
+      ui.checkOverflow(".top-toolbar");
+      ui.checkOverflow(".map-footer-bar");
+      var resizeWindowEvent = document.createEvent("Event");
+      resizeWindowEvent.initEvent("resizeWindow", true, true);
+      document.dispatchEvent(resizeWindowEvent);
     };
-    return dataEditor;
-  }
-
-  // modules/ui/sidebar.js
-  function uiSidebar(context) {
-    var inspector = uiInspector(context);
-    var dataEditor = uiDataEditor(context);
-    var noteEditor = uiNoteEditor(context);
-    var improveOsmEditor = uiImproveOsmEditor(context);
-    var keepRightEditor = uiKeepRightEditor(context);
-    var osmoseEditor = uiOsmoseEditor(context);
-    var _current;
-    var _wasData = false;
-    var _wasNote = false;
-    var _wasQaItem = false;
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    function sidebar(selection2) {
-      var container = context.container();
-      var minWidth = 240;
-      var sidebarWidth;
-      var containerWidth;
-      var dragOffset;
-      selection2.style("min-width", minWidth + "px").style("max-width", "400px").style("width", "33.3333%");
-      var resizer = selection2.append("div").attr("class", "sidebar-resizer").on(_pointerPrefix + "down.sidebar-resizer", pointerdown);
-      var downPointerId, lastClientX, containerLocGetter;
-      function pointerdown(d3_event) {
-        if (downPointerId)
-          return;
-        if ("button" in d3_event && d3_event.button !== 0)
-          return;
-        downPointerId = d3_event.pointerId || "mouse";
-        lastClientX = d3_event.clientX;
-        containerLocGetter = utilFastMouse(container.node());
-        dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
-        sidebarWidth = selection2.node().getBoundingClientRect().width;
-        containerWidth = container.node().getBoundingClientRect().width;
-        var widthPct = sidebarWidth / containerWidth * 100;
-        selection2.style("width", widthPct + "%").style("max-width", "85%");
-        resizer.classed("dragging", true);
-        select_default2(window).on("touchmove.sidebar-resizer", function(d3_event2) {
-          d3_event2.preventDefault();
-        }, { passive: false }).on(_pointerPrefix + "move.sidebar-resizer", pointermove).on(_pointerPrefix + "up.sidebar-resizer pointercancel.sidebar-resizer", pointerup);
-      }
-      function pointermove(d3_event) {
-        if (downPointerId !== (d3_event.pointerId || "mouse"))
-          return;
-        d3_event.preventDefault();
-        var dx = d3_event.clientX - lastClientX;
-        lastClientX = d3_event.clientX;
-        var isRTL = _mainLocalizer.textDirection() === "rtl";
-        var scaleX = isRTL ? 0 : 1;
-        var xMarginProperty = isRTL ? "margin-right" : "margin-left";
-        var x2 = containerLocGetter(d3_event)[0] - dragOffset;
-        sidebarWidth = isRTL ? containerWidth - x2 : x2;
-        var isCollapsed = selection2.classed("collapsed");
-        var shouldCollapse = sidebarWidth < minWidth;
-        selection2.classed("collapsed", shouldCollapse);
-        if (shouldCollapse) {
-          if (!isCollapsed) {
-            selection2.style(xMarginProperty, "-400px").style("width", "400px");
-            context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
-          }
-        } else {
-          var widthPct = sidebarWidth / containerWidth * 100;
-          selection2.style(xMarginProperty, null).style("width", widthPct + "%");
-          if (isCollapsed) {
-            context.ui().onResize([-sidebarWidth * scaleX, 0]);
-          } else {
-            context.ui().onResize([-dx * scaleX, 0]);
-          }
-        }
-      }
-      function pointerup(d3_event) {
-        if (downPointerId !== (d3_event.pointerId || "mouse"))
-          return;
-        downPointerId = null;
-        resizer.classed("dragging", false);
-        select_default2(window).on("touchmove.sidebar-resizer", null).on(_pointerPrefix + "move.sidebar-resizer", null).on(_pointerPrefix + "up.sidebar-resizer pointercancel.sidebar-resizer", null);
+    ui.checkOverflow = function(selector, reset) {
+      if (reset) {
+        delete _needWidth[selector];
       }
-      var featureListWrap = selection2.append("div").attr("class", "feature-list-pane").call(uiFeatureList(context));
-      var inspectorWrap = selection2.append("div").attr("class", "inspector-hidden inspector-wrap");
-      var hoverModeSelect = function(targets) {
-        context.container().selectAll(".feature-list-item button").classed("hover", false);
-        if (context.selectedIDs().length > 1 && targets && targets.length) {
-          var elements = context.container().selectAll(".feature-list-item button").filter(function(node) {
-            return targets.indexOf(node) !== -1;
-          });
-          if (!elements.empty()) {
-            elements.classed("hover", true);
-          }
-        }
-      };
-      sidebar.hoverModeSelect = throttle_default(hoverModeSelect, 200);
-      function hover(targets) {
-        var datum2 = targets && targets.length && targets[0];
-        if (datum2 && datum2.__featurehash__) {
-          _wasData = true;
-          sidebar.show(dataEditor.datum(datum2));
-          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
-        } else if (datum2 instanceof osmNote) {
-          if (context.mode().id === "drag-note")
-            return;
-          _wasNote = true;
-          var osm = services.osm;
-          if (osm) {
-            datum2 = osm.getNote(datum2.id);
-          }
-          sidebar.show(noteEditor.note(datum2));
-          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
-        } else if (datum2 instanceof QAItem) {
-          _wasQaItem = true;
-          var errService = services[datum2.service];
-          if (errService) {
-            datum2 = errService.getError(datum2.id);
-          }
-          var errEditor;
-          if (datum2.service === "keepRight") {
-            errEditor = keepRightEditor;
-          } else if (datum2.service === "osmose") {
-            errEditor = osmoseEditor;
-          } else {
-            errEditor = improveOsmEditor;
-          }
-          context.container().selectAll(".qaItem." + datum2.service).classed("hover", function(d2) {
-            return d2.id === datum2.id;
-          });
-          sidebar.show(errEditor.error(datum2));
-          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
-        } else if (!_current && datum2 instanceof osmEntity) {
-          featureListWrap.classed("inspector-hidden", true);
-          inspectorWrap.classed("inspector-hidden", false).classed("inspector-hover", true);
-          if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum2.id]) || inspector.state() !== "hover") {
-            inspector.state("hover").entityIDs([datum2.id]).newFeature(false);
-            inspectorWrap.call(inspector);
-          }
-        } else if (!_current) {
-          featureListWrap.classed("inspector-hidden", false);
-          inspectorWrap.classed("inspector-hidden", true);
-          inspector.state("hide");
-        } else if (_wasData || _wasNote || _wasQaItem) {
-          _wasNote = false;
-          _wasData = false;
-          _wasQaItem = false;
-          context.container().selectAll(".note").classed("hover", false);
-          context.container().selectAll(".qaItem").classed("hover", false);
-          sidebar.hide();
+      var selection2 = context.container().select(selector);
+      if (selection2.empty()) return;
+      var scrollWidth = selection2.property("scrollWidth");
+      var clientWidth = selection2.property("clientWidth");
+      var needed = _needWidth[selector] || scrollWidth;
+      if (scrollWidth > clientWidth) {
+        selection2.classed("narrow", true);
+        if (!_needWidth[selector]) {
+          _needWidth[selector] = scrollWidth;
         }
+      } else if (scrollWidth >= needed) {
+        selection2.classed("narrow", false);
       }
-      sidebar.hover = throttle_default(hover, 200);
-      sidebar.intersects = function(extent) {
-        var rect = selection2.node().getBoundingClientRect();
-        return extent.intersects([
-          context.projection.invert([0, rect.height]),
-          context.projection.invert([rect.width, 0])
-        ]);
-      };
-      sidebar.select = function(ids, newFeature) {
-        sidebar.hide();
-        if (ids && ids.length) {
-          var entity = ids.length === 1 && context.entity(ids[0]);
-          if (entity && newFeature && selection2.classed("collapsed")) {
-            var extent = entity.extent(context.graph());
-            sidebar.expand(sidebar.intersects(extent));
-          }
-          featureListWrap.classed("inspector-hidden", true);
-          inspectorWrap.classed("inspector-hidden", false).classed("inspector-hover", false);
-          inspector.state("select").entityIDs(ids).newFeature(newFeature);
-          inspectorWrap.call(inspector);
-        } else {
-          inspector.state("hide");
-        }
-      };
-      sidebar.showPresetList = function() {
-        inspector.showList();
-      };
-      sidebar.show = function(component, element) {
-        featureListWrap.classed("inspector-hidden", true);
-        inspectorWrap.classed("inspector-hidden", true);
-        if (_current)
-          _current.remove();
-        _current = selection2.append("div").attr("class", "sidebar-component").call(component, element);
-      };
-      sidebar.hide = function() {
-        featureListWrap.classed("inspector-hidden", false);
-        inspectorWrap.classed("inspector-hidden", true);
-        if (_current)
-          _current.remove();
-        _current = null;
-      };
-      sidebar.expand = function(moveMap) {
-        if (selection2.classed("collapsed")) {
-          sidebar.toggle(moveMap);
-        }
-      };
-      sidebar.collapse = function(moveMap) {
-        if (!selection2.classed("collapsed")) {
-          sidebar.toggle(moveMap);
-        }
-      };
-      sidebar.toggle = function(moveMap) {
-        if (context.inIntro())
-          return;
-        var isCollapsed = selection2.classed("collapsed");
-        var isCollapsing = !isCollapsed;
-        var isRTL = _mainLocalizer.textDirection() === "rtl";
-        var scaleX = isRTL ? 0 : 1;
-        var xMarginProperty = isRTL ? "margin-right" : "margin-left";
-        sidebarWidth = selection2.node().getBoundingClientRect().width;
-        selection2.style("width", sidebarWidth + "px");
-        var startMargin, endMargin, lastMargin;
-        if (isCollapsing) {
-          startMargin = lastMargin = 0;
-          endMargin = -sidebarWidth;
+    };
+    ui.togglePanes = function(showPane) {
+      var hidePanes = context.container().selectAll(".map-pane.shown");
+      var side = _mainLocalizer.textDirection() === "ltr" ? "right" : "left";
+      hidePanes.classed("shown", false).classed("hide", true);
+      context.container().selectAll(".map-pane-control button").classed("active", false);
+      if (showPane) {
+        hidePanes.classed("shown", false).classed("hide", true).style(side, "-500px");
+        context.container().selectAll("." + showPane.attr("pane") + "-control button").classed("active", true);
+        showPane.classed("shown", true).classed("hide", false);
+        if (hidePanes.empty()) {
+          showPane.style(side, "-500px").transition().duration(200).style(side, "0px");
         } else {
-          startMargin = lastMargin = -sidebarWidth;
-          endMargin = 0;
-        }
-        if (!isCollapsing) {
-          selection2.classed("collapsed", isCollapsing);
+          showPane.style(side, "0px");
         }
-        selection2.transition().style(xMarginProperty, endMargin + "px").tween("panner", function() {
-          var i3 = number_default(startMargin, endMargin);
-          return function(t2) {
-            var dx = lastMargin - Math.round(i3(t2));
-            lastMargin = lastMargin - dx;
-            context.ui().onResize(moveMap ? void 0 : [dx * scaleX, 0]);
-          };
-        }).on("end", function() {
-          if (isCollapsing) {
-            selection2.classed("collapsed", isCollapsing);
-          }
-          if (!isCollapsing) {
-            var containerWidth2 = container.node().getBoundingClientRect().width;
-            var widthPct = sidebarWidth / containerWidth2 * 100;
-            selection2.style(xMarginProperty, null).style("width", widthPct + "%");
-          }
+      } else {
+        hidePanes.classed("shown", true).classed("hide", false).style(side, "0px").transition().duration(200).style(side, "-500px").on("end", function() {
+          select_default2(this).classed("shown", false).classed("hide", true);
         });
-      };
-      resizer.on("dblclick", function(d3_event) {
-        d3_event.preventDefault();
-        if (d3_event.sourceEvent) {
-          d3_event.sourceEvent.preventDefault();
-        }
-        sidebar.toggle();
-      });
-      context.map().on("crossEditableZoom.sidebar", function(within) {
-        if (!within && !selection2.select(".inspector-hover").empty()) {
-          hover([]);
-        }
-      });
-    }
-    sidebar.showPresetList = function() {
-    };
-    sidebar.hover = function() {
-    };
-    sidebar.hover.cancel = function() {
-    };
-    sidebar.intersects = function() {
-    };
-    sidebar.select = function() {
-    };
-    sidebar.show = function() {
-    };
-    sidebar.hide = function() {
+      }
     };
-    sidebar.expand = function() {
+    var _editMenu = uiEditMenu(context);
+    ui.editMenu = function() {
+      return _editMenu;
     };
-    sidebar.collapse = function() {
+    ui.showEditMenu = function(anchorPoint, triggerType, operations) {
+      ui.closeEditMenu();
+      if (!operations && context.mode().operations) operations = context.mode().operations();
+      if (!operations || !operations.length) return;
+      if (!context.map().editableDataEnabled()) return;
+      var surfaceNode = context.surface().node();
+      if (surfaceNode.focus) {
+        surfaceNode.focus();
+      }
+      operations.forEach(function(operation2) {
+        if (operation2.point) operation2.point(anchorPoint);
+      });
+      _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations);
+      context.map().supersurface.call(_editMenu);
     };
-    sidebar.toggle = function() {
+    ui.closeEditMenu = function() {
+      context.map().supersurface.select(".edit-menu").remove();
     };
-    return sidebar;
+    var _saveLoading = select_default2(null);
+    context.uploader().on("saveStarted.ui", function() {
+      _saveLoading = uiLoading(context).message(_t.html("save.uploading")).blocking(true);
+      context.container().call(_saveLoading);
+    }).on("saveEnded.ui", function() {
+      _saveLoading.close();
+      _saveLoading = select_default2(null);
+    });
+    marked.use({
+      mangle: false,
+      headerIds: false
+    });
+    return ui;
   }
 
-  // modules/ui/tools/modes.js
-  function uiToolDrawModes(context) {
-    var tool = {
-      id: "old_modes",
-      label: _t.append("toolbar.add_feature")
-    };
-    var modes = [
-      modeAddPoint(context, {
-        title: _t.append("modes.add_point.title"),
-        button: "point",
-        description: _t.append("modes.add_point.description"),
-        preset: _mainPresetIndex.item("point"),
-        key: "1"
-      }),
-      modeAddLine(context, {
-        title: _t.append("modes.add_line.title"),
-        button: "line",
-        description: _t.append("modes.add_line.description"),
-        preset: _mainPresetIndex.item("line"),
-        key: "2"
-      }),
-      modeAddArea(context, {
-        title: _t.append("modes.add_area.title"),
-        button: "area",
-        description: _t.append("modes.add_area.description"),
-        preset: _mainPresetIndex.item("area"),
-        key: "3"
-      })
-    ];
-    function enabled(_mode) {
-      return osmEditable();
-    }
-    function osmEditable() {
-      return context.editable();
-    }
-    modes.forEach(function(mode) {
-      context.keybinding().on(mode.key, function() {
-        if (!enabled(mode))
-          return;
-        if (mode.id === context.mode().id) {
-          context.enter(modeBrowse(context));
-        } else {
-          context.enter(mode);
+  // modules/ui/commit_warnings.js
+  function uiCommitWarnings(context) {
+    function commitWarnings(selection2) {
+      var issuesBySeverity = context.validator().getIssuesBySeverity({ what: "edited", where: "all", includeDisabledRules: true });
+      for (var severity in issuesBySeverity) {
+        var issues = issuesBySeverity[severity];
+        if (severity !== "error") {
+          issues = issues.filter(function(issue) {
+            return issue.type !== "help_request";
+          });
         }
-      });
-    });
-    tool.render = function(selection2) {
-      var wrap2 = selection2.append("div").attr("class", "joined").style("display", "flex");
-      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
-      context.map().on("move.modes", debouncedUpdate).on("drawn.modes", debouncedUpdate);
-      context.on("enter.modes", update);
-      update();
-      function update() {
-        var buttons = wrap2.selectAll("button.add-button").data(modes, function(d2) {
-          return d2.id;
+        var section = severity + "-section";
+        var issueItem = severity + "-item";
+        var container = selection2.selectAll("." + section).data(issues.length ? [0] : []);
+        container.exit().remove();
+        var containerEnter = container.enter().append("div").attr("class", "modal-section " + section + " fillL2");
+        containerEnter.append("h3").call(severity === "warning" ? _t.append("commit.warnings") : _t.append("commit.errors"));
+        containerEnter.append("ul").attr("class", "changeset-list");
+        container = containerEnter.merge(container);
+        var items = container.select("ul").selectAll("li").data(issues, function(d2) {
+          return d2.key;
         });
-        buttons.exit().remove();
-        var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
-          return d2.id + " add-button bar-button";
-        }).on("click.mode-buttons", function(d3_event, d2) {
-          if (!enabled(d2))
-            return;
-          var currMode = context.mode().id;
-          if (/^draw/.test(currMode))
-            return;
-          if (d2.id === currMode) {
-            context.enter(modeBrowse(context));
-          } else {
-            context.enter(d2);
+        items.exit().remove();
+        var itemsEnter = items.enter().append("li").attr("class", issueItem);
+        var buttons = itemsEnter.append("button").on("mouseover", function(d3_event, d2) {
+          if (d2.entityIds) {
+            context.surface().selectAll(
+              utilEntityOrMemberSelector(
+                d2.entityIds,
+                context.graph()
+              )
+            ).classed("hover", true);
           }
+        }).on("mouseout", function() {
+          context.surface().selectAll(".hover").classed("hover", false);
+        }).on("click", function(d3_event, d2) {
+          context.validator().focusIssue(d2);
+        });
+        buttons.call(svgIcon("#iD-icon-alert", "pre-text"));
+        buttons.append("strong").attr("class", "issue-message");
+        buttons.filter(function(d2) {
+          return d2.tooltip;
         }).call(
-          uiTooltip().placement("bottom").title(function(d2) {
-            return d2.description;
-          }).keys(function(d2) {
-            return [d2.key];
-          }).scrollContainer(context.container().select(".top-toolbar"))
+          uiTooltip().title(function(d2) {
+            return d2.tooltip;
+          }).placement("top")
         );
-        buttonsEnter.each(function(d2) {
-          select_default2(this).call(svgIcon("#iD-icon-" + d2.button));
-        });
-        buttonsEnter.append("span").attr("class", "label").text("").each(function(mode) {
-          mode.title(select_default2(this));
-        });
-        if (buttons.enter().size() || buttons.exit().size()) {
-          context.ui().checkOverflow(".top-toolbar", true);
-        }
-        buttons = buttons.merge(buttonsEnter).attr("aria-disabled", function(d2) {
-          return !enabled(d2);
-        }).classed("disabled", function(d2) {
-          return !enabled(d2);
-        }).attr("aria-pressed", function(d2) {
-          return context.mode() && context.mode().button === d2.button;
-        }).classed("active", function(d2) {
-          return context.mode() && context.mode().button === d2.button;
+        items = itemsEnter.merge(items);
+        items.selectAll(".issue-message").text("").each(function(d2) {
+          return d2.message(context)(select_default2(this));
         });
       }
-    };
-    return tool;
+    }
+    return commitWarnings;
   }
 
-  // modules/ui/tools/notes.js
-  function uiToolNotes(context) {
-    var tool = {
-      id: "notes",
-      label: _t.append("modes.add_note.label")
-    };
-    var mode = modeAddNote(context);
-    function enabled() {
-      return notesEnabled() && notesEditable();
-    }
-    function notesEnabled() {
-      var noteLayer = context.layers().layer("notes");
-      return noteLayer && noteLayer.enabled();
-    }
-    function notesEditable() {
-      var mode2 = context.mode();
-      return context.map().notesEditable() && mode2 && mode2.id !== "save";
+  // modules/ui/lasso.js
+  function uiLasso(context) {
+    var group, polygon2;
+    lasso.coordinates = [];
+    function lasso(selection2) {
+      context.container().classed("lasso", true);
+      group = selection2.append("g").attr("class", "lasso hide");
+      polygon2 = group.append("path").attr("class", "lasso-path");
+      group.call(uiToggle(true));
     }
-    context.keybinding().on(mode.key, function() {
-      if (!enabled())
-        return;
-      if (mode.id === context.mode().id) {
-        context.enter(modeBrowse(context));
-      } else {
-        context.enter(mode);
-      }
-    });
-    tool.render = function(selection2) {
-      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
-      context.map().on("move.notes", debouncedUpdate).on("drawn.notes", debouncedUpdate);
-      context.on("enter.notes", update);
-      update();
-      function update() {
-        var showNotes = notesEnabled();
-        var data = showNotes ? [mode] : [];
-        var buttons = selection2.selectAll("button.add-button").data(data, function(d2) {
-          return d2.id;
-        });
-        buttons.exit().remove();
-        var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
-          return d2.id + " add-button bar-button";
-        }).on("click.notes", function(d3_event, d2) {
-          if (!enabled())
-            return;
-          var currMode = context.mode().id;
-          if (/^draw/.test(currMode))
-            return;
-          if (d2.id === currMode) {
-            context.enter(modeBrowse(context));
-          } else {
-            context.enter(d2);
-          }
-        }).call(
-          uiTooltip().placement("bottom").title(function(d2) {
-            return d2.description;
-          }).keys(function(d2) {
-            return [d2.key];
-          }).scrollContainer(context.container().select(".top-toolbar"))
-        );
-        buttonsEnter.each(function(d2) {
-          select_default2(this).call(svgIcon(d2.icon || "#iD-icon-" + d2.button));
-        });
-        if (buttons.enter().size() || buttons.exit().size()) {
-          context.ui().checkOverflow(".top-toolbar", true);
-        }
-        buttons = buttons.merge(buttonsEnter).classed("disabled", function() {
-          return !enabled();
-        }).attr("aria-disabled", function() {
-          return !enabled();
-        }).classed("active", function(d2) {
-          return context.mode() && context.mode().button === d2.button;
-        }).attr("aria-pressed", function(d2) {
-          return context.mode() && context.mode().button === d2.button;
+    function draw() {
+      if (polygon2) {
+        polygon2.data([lasso.coordinates]).attr("d", function(d2) {
+          return "M" + d2.join(" L") + " Z";
         });
       }
+    }
+    lasso.extent = function() {
+      return lasso.coordinates.reduce(function(extent, point) {
+        return extent.extend(geoExtent(point));
+      }, geoExtent());
     };
-    tool.uninstall = function() {
-      context.on("enter.editor.notes", null).on("exit.editor.notes", null).on("enter.notes", null);
-      context.map().on("move.notes", null).on("drawn.notes", null);
+    lasso.p = function(_2) {
+      if (!arguments.length) return lasso;
+      lasso.coordinates.push(_2);
+      draw();
+      return lasso;
     };
-    return tool;
+    lasso.close = function() {
+      if (group) {
+        group.call(uiToggle(false, function() {
+          select_default2(this).remove();
+        }));
+      }
+      context.container().classed("lasso", false);
+    };
+    return lasso;
   }
 
-  // modules/ui/tools/save.js
-  function uiToolSave(context) {
-    var tool = {
-      id: "save",
-      label: _t.append("save.title")
-    };
-    var button = null;
-    var tooltipBehavior = null;
-    var history = context.history();
-    var key = uiCmd("\u2318S");
-    var _numChanges = 0;
-    function isSaving() {
-      var mode = context.mode();
-      return mode && mode.id === "save";
+  // node_modules/osm-community-index/lib/simplify.js
+  var import_diacritics2 = __toESM(require_diacritics(), 1);
+  function simplify(str) {
+    if (typeof str !== "string") return "";
+    return import_diacritics2.default.remove(
+      str.replace(/&/g, "and").replace(/(İ|i̇)/ig, "i").replace(/[\s\-=_!"#%'*{},.\/:;?\(\)\[\]@\\$\^*+<>«»~`’\u00a1\u00a7\u00b6\u00b7\u00bf\u037e\u0387\u055a-\u055f\u0589\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0af0\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f14\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1360-\u1368\u166d\u166e\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u1805\u1807-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cc0-\u1cc7\u1cd3\u2000-\u206f\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00-\u2e7f\u3001-\u3003\u303d\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uaaf0\uaaf1\uabeb\ufe10-\ufe16\ufe19\ufe30\ufe45\ufe46\ufe49-\ufe4c\ufe50-\ufe52\ufe54-\ufe57\ufe5f-\ufe61\ufe68\ufe6a\ufe6b\ufeff\uff01-\uff03\uff05-\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65]+/g, "").toLowerCase()
+    );
+  }
+
+  // node_modules/osm-community-index/lib/resolve_strings.js
+  function resolveStrings(item, defaults, localizerFn) {
+    let itemStrings = Object.assign({}, item.strings);
+    let defaultStrings = Object.assign({}, defaults[item.type]);
+    const anyToken = new RegExp(/(\{\w+\})/, "gi");
+    if (localizerFn) {
+      if (itemStrings.community) {
+        const communityID = simplify(itemStrings.community);
+        itemStrings.community = localizerFn("_communities.".concat(communityID));
+      }
+      ["name", "description", "extendedDescription"].forEach((prop) => {
+        if (defaultStrings[prop]) defaultStrings[prop] = localizerFn("_defaults.".concat(item.type, ".").concat(prop));
+        if (itemStrings[prop]) itemStrings[prop] = localizerFn("".concat(item.id, ".").concat(prop));
+      });
     }
-    function isDisabled() {
-      return _numChanges === 0 || isSaving();
+    let replacements = {
+      account: item.account,
+      community: itemStrings.community,
+      signupUrl: itemStrings.signupUrl,
+      url: itemStrings.url
+    };
+    if (!replacements.signupUrl) {
+      replacements.signupUrl = resolve(itemStrings.signupUrl || defaultStrings.signupUrl);
     }
-    function save(d3_event) {
-      d3_event.preventDefault();
-      if (!context.inIntro() && !isSaving() && history.hasChanges()) {
-        context.enter(modeSave(context));
-      }
+    if (!replacements.url) {
+      replacements.url = resolve(itemStrings.url || defaultStrings.url);
     }
-    function bgColor(numChanges) {
-      var step;
-      if (numChanges === 0) {
-        return null;
-      } else if (numChanges <= 50) {
-        step = numChanges / 50;
-        return rgb_default("#fff", "#ff8")(step);
-      } else {
-        step = Math.min((numChanges - 50) / 50, 1);
-        return rgb_default("#ff8", "#f88")(step);
+    let resolved = {
+      name: resolve(itemStrings.name || defaultStrings.name),
+      url: resolve(itemStrings.url || defaultStrings.url),
+      signupUrl: resolve(itemStrings.signupUrl || defaultStrings.signupUrl),
+      description: resolve(itemStrings.description || defaultStrings.description),
+      extendedDescription: resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription)
+    };
+    resolved.nameHTML = linkify(resolved.url, resolved.name);
+    resolved.urlHTML = linkify(resolved.url);
+    resolved.signupUrlHTML = linkify(resolved.signupUrl);
+    resolved.descriptionHTML = resolve(itemStrings.description || defaultStrings.description, true);
+    resolved.extendedDescriptionHTML = resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription, true);
+    return resolved;
+    function resolve(s2, addLinks) {
+      if (!s2) return void 0;
+      let result = s2;
+      for (let key in replacements) {
+        const token = "{".concat(key, "}");
+        const regex = new RegExp(token, "g");
+        if (regex.test(result)) {
+          let replacement = replacements[key];
+          if (!replacement) {
+            throw new Error("Cannot resolve token: ".concat(token));
+          } else {
+            if (addLinks && (key === "signupUrl" || key === "url")) {
+              replacement = linkify(replacement);
+            }
+            result = result.replace(regex, replacement);
+          }
+        }
       }
-    }
-    function updateCount() {
-      var val = history.difference().summary().length;
-      if (val === _numChanges)
-        return;
-      _numChanges = val;
-      if (tooltipBehavior) {
-        tooltipBehavior.title(() => _t.append(_numChanges > 0 ? "save.help" : "save.no_changes")).keys([key]);
+      const leftovers = result.match(anyToken);
+      if (leftovers) {
+        throw new Error("Cannot resolve tokens: ".concat(leftovers));
       }
-      if (button) {
-        button.classed("disabled", isDisabled()).style("background", bgColor(_numChanges));
-        button.select("span.count").text(_numChanges);
+      if (addLinks && item.type === "reddit") {
+        result = result.replace(/(\/r\/\w+\/*)/i, (match) => linkify(resolved.url, match));
       }
+      return result;
+    }
+    function linkify(url, text) {
+      if (!url) return void 0;
+      text = text || url;
+      return '<a target="_blank" href="'.concat(url, '">').concat(text, "</a>");
     }
-    tool.render = function(selection2) {
-      tooltipBehavior = uiTooltip().placement("bottom").title(() => _t.append("save.no_changes")).keys([key]).scrollContainer(context.container().select(".top-toolbar"));
-      var lastPointerUpType;
-      button = selection2.append("button").attr("class", "save disabled bar-button").on("pointerup", function(d3_event) {
-        lastPointerUpType = d3_event.pointerType;
-      }).on("click", function(d3_event) {
-        save(d3_event);
-        if (_numChanges === 0 && (lastPointerUpType === "touch" || lastPointerUpType === "pen")) {
-          context.ui().flash.duration(2e3).iconName("#iD-icon-save").iconClass("disabled").label(_t.append("save.no_changes"))();
-        }
-        lastPointerUpType = null;
-      }).call(tooltipBehavior);
-      button.call(svgIcon("#iD-icon-save"));
-      button.append("span").attr("class", "count").attr("aria-hidden", "true").text("0");
-      updateCount();
-      context.keybinding().on(key, save, true);
-      context.history().on("change.save", updateCount);
-      context.on("enter.save", function() {
-        if (button) {
-          button.classed("disabled", isDisabled());
-          if (isSaving()) {
-            button.call(tooltipBehavior.hide);
-          }
-        }
-      });
-    };
-    tool.uninstall = function() {
-      context.keybinding().off(key, true);
-      context.history().on("change.save", null);
-      context.on("enter.save", null);
-      button = null;
-      tooltipBehavior = null;
-    };
-    return tool;
-  }
-
-  // modules/ui/tools/sidebar_toggle.js
-  function uiToolSidebarToggle(context) {
-    var tool = {
-      id: "sidebar_toggle",
-      label: _t.append("toolbar.inspect")
-    };
-    tool.render = function(selection2) {
-      selection2.append("button").attr("class", "bar-button").attr("aria-label", _t("sidebar.tooltip")).on("click", function() {
-        context.ui().sidebar.toggle();
-      }).call(
-        uiTooltip().placement("bottom").title(() => _t.append("sidebar.tooltip")).keys([_t("sidebar.key")]).scrollContainer(context.container().select(".top-toolbar"))
-      ).call(svgIcon("#iD-icon-sidebar-" + (_mainLocalizer.textDirection() === "rtl" ? "right" : "left")));
-    };
-    return tool;
   }
 
-  // modules/ui/tools/undo_redo.js
-  function uiToolUndoRedo(context) {
-    var tool = {
-      id: "undo_redo",
-      label: _t.append("toolbar.undo_redo")
-    };
-    var commands = [{
-      id: "undo",
-      cmd: uiCmd("\u2318Z"),
-      action: function() {
-        context.undo();
-      },
-      annotation: function() {
-        return context.history().undoAnnotation();
-      },
-      icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")
-    }, {
-      id: "redo",
-      cmd: uiCmd("\u2318\u21E7Z"),
-      action: function() {
-        context.redo();
-      },
-      annotation: function() {
-        return context.history().redoAnnotation();
-      },
-      icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "undo" : "redo")
-    }];
-    function editable() {
-      return context.mode() && context.mode().id !== "save" && context.map().editableDataEnabled(
-        true
-        /* ignore min zoom */
-      );
-    }
-    tool.render = function(selection2) {
-      var tooltipBehavior = uiTooltip().placement("bottom").title(function(d2) {
-        return d2.annotation() ? _t.append(d2.id + ".tooltip", { action: d2.annotation() }) : _t.append(d2.id + ".nothing");
-      }).keys(function(d2) {
-        return [d2.cmd];
-      }).scrollContainer(context.container().select(".top-toolbar"));
-      var lastPointerUpType;
-      var buttons = selection2.selectAll("button").data(commands).enter().append("button").attr("class", function(d2) {
-        return "disabled " + d2.id + "-button bar-button";
-      }).on("pointerup", function(d3_event) {
-        lastPointerUpType = d3_event.pointerType;
-      }).on("click", function(d3_event, d2) {
-        d3_event.preventDefault();
-        var annotation = d2.annotation();
-        if (editable() && annotation) {
-          d2.action();
+  // modules/ui/success.js
+  var _oci = null;
+  function uiSuccess(context) {
+    const MAXEVENTS = 2;
+    const dispatch14 = dispatch_default("cancel");
+    let _changeset2;
+    let _location;
+    ensureOSMCommunityIndex();
+    function ensureOSMCommunityIndex() {
+      const data = _mainFileFetcher;
+      return Promise.all([
+        data.get("oci_features"),
+        data.get("oci_resources"),
+        data.get("oci_defaults")
+      ]).then((vals) => {
+        if (_oci) return _oci;
+        if (vals[0] && Array.isArray(vals[0].features)) {
+          _sharedLocationManager.mergeCustomGeoJSON(vals[0]);
         }
-        if (editable() && (lastPointerUpType === "touch" || lastPointerUpType === "pen")) {
-          var label = annotation ? _t.append(d2.id + ".tooltip", { action: annotation }) : _t.append(d2.id + ".nothing");
-          context.ui().flash.duration(2e3).iconName("#" + d2.icon).iconClass(annotation ? "" : "disabled").label(label)();
+        let ociResources = Object.values(vals[1].resources);
+        if (ociResources.length) {
+          return _sharedLocationManager.mergeLocationSets(ociResources).then(() => {
+            _oci = {
+              resources: ociResources,
+              defaults: vals[2].defaults
+            };
+            return _oci;
+          });
+        } else {
+          _oci = {
+            resources: [],
+            // no resources?
+            defaults: vals[2].defaults
+          };
+          return _oci;
         }
-        lastPointerUpType = null;
-      }).call(tooltipBehavior);
-      buttons.each(function(d2) {
-        select_default2(this).call(svgIcon("#" + d2.icon));
-      });
-      context.keybinding().on(commands[0].cmd, function(d3_event) {
-        d3_event.preventDefault();
-        if (editable())
-          commands[0].action();
-      }).on(commands[1].cmd, function(d3_event) {
-        d3_event.preventDefault();
-        if (editable())
-          commands[1].action();
       });
-      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
-      context.map().on("move.undo_redo", debouncedUpdate).on("drawn.undo_redo", debouncedUpdate);
-      context.history().on("change.undo_redo", function(difference2) {
-        if (difference2)
-          update();
+    }
+    function parseEventDate(when) {
+      if (!when) return;
+      let raw = when.trim();
+      if (!raw) return;
+      if (!/Z$/.test(raw)) {
+        raw += "Z";
+      }
+      const parsed = new Date(raw);
+      return new Date(parsed.toUTCString().slice(0, 25));
+    }
+    function success(selection2) {
+      let header = selection2.append("div").attr("class", "header fillL");
+      header.append("h2").call(_t.append("success.just_edited"));
+      header.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => dispatch14.call("cancel")).call(svgIcon("#iD-icon-close"));
+      let body = selection2.append("div").attr("class", "body save-success fillL");
+      let summary = body.append("div").attr("class", "save-summary");
+      summary.append("h3").call(_t.append("success.thank_you" + (_location ? "_location" : ""), { where: _location }));
+      summary.append("p").call(_t.append("success.help_html")).append("a").attr("class", "link-out").attr("target", "_blank").attr("href", _t("success.help_link_url")).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("success.help_link_text"));
+      let osm = context.connection();
+      if (!osm) return;
+      let changesetURL = osm.changesetURL(_changeset2.id);
+      let table = summary.append("table").attr("class", "summary-table");
+      let row = table.append("tr").attr("class", "summary-row");
+      row.append("td").attr("class", "cell-icon summary-icon").append("a").attr("target", "_blank").attr("href", changesetURL).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", "#iD-logo-osm");
+      let summaryDetail = row.append("td").attr("class", "cell-detail summary-detail");
+      summaryDetail.append("a").attr("class", "cell-detail summary-view-on-osm").attr("target", "_blank").attr("href", changesetURL).call(_t.append("success.view_on_osm"));
+      summaryDetail.append("div").html(_t.html("success.changeset_id", {
+        changeset_id: { html: '<a href="'.concat(changesetURL, '" target="_blank">').concat(_changeset2.id, "</a>") }
+      }));
+      if (showDonationMessage !== false) {
+        const donationUrl = "https://supporting.openstreetmap.org/";
+        let supporting = body.append("div").attr("class", "save-supporting");
+        supporting.append("h3").call(_t.append("success.supporting.title"));
+        supporting.append("p").call(_t.append("success.supporting.details"));
+        table = supporting.append("table").attr("class", "supporting-table");
+        row = table.append("tr").attr("class", "supporting-row");
+        row.append("td").attr("class", "cell-icon supporting-icon").append("a").attr("target", "_blank").attr("href", donationUrl).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", "#iD-donation");
+        let supportingDetail = row.append("td").attr("class", "cell-detail supporting-detail");
+        supportingDetail.append("a").attr("class", "cell-detail support-the-map").attr("target", "_blank").attr("href", donationUrl).call(_t.append("success.supporting.donation.title"));
+        supportingDetail.append("div").call(_t.append("success.supporting.donation.details"));
+      }
+      ensureOSMCommunityIndex().then((oci) => {
+        const loc = context.map().center();
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
+        let communities = [];
+        oci.resources.forEach((resource) => {
+          let area = validHere[resource.locationSetID];
+          if (!area) return;
+          const localizer = (stringID) => _t.html("community.".concat(stringID));
+          resource.resolved = resolveStrings(resource, oci.defaults, localizer);
+          communities.push({
+            area,
+            order: resource.order || 0,
+            resource
+          });
+        });
+        communities.sort((a2, b2) => a2.area - b2.area || b2.order - a2.order);
+        body.call(showCommunityLinks, communities.map((c2) => c2.resource));
       });
-      context.on("enter.undo_redo", update);
-      function update() {
-        buttons.classed("disabled", function(d2) {
-          return !editable() || !d2.annotation();
-        }).each(function() {
-          var selection3 = select_default2(this);
-          if (!selection3.select(".tooltip.in").empty()) {
-            selection3.call(tooltipBehavior.updateContent);
+    }
+    function showCommunityLinks(selection2, resources) {
+      let communityLinks = selection2.append("div").attr("class", "save-communityLinks");
+      communityLinks.append("h3").call(_t.append("success.like_osm"));
+      let table = communityLinks.append("table").attr("class", "community-table");
+      let row = table.selectAll(".community-row").data(resources);
+      let rowEnter = row.enter().append("tr").attr("class", "community-row");
+      rowEnter.append("td").attr("class", "cell-icon community-icon").append("a").attr("target", "_blank").attr("href", (d2) => d2.resolved.url).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", (d2) => "#community-".concat(d2.type));
+      let communityDetail = rowEnter.append("td").attr("class", "cell-detail community-detail");
+      communityDetail.each(showCommunityDetails);
+      communityLinks.append("div").attr("class", "community-missing").call(_t.append("success.missing")).append("a").attr("class", "link-out").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/osmlab/osm-community-index/issues").append("span").call(_t.append("success.tell_us"));
+    }
+    function showCommunityDetails(d2) {
+      let selection2 = select_default2(this);
+      let communityID = d2.id;
+      selection2.append("div").attr("class", "community-name").html(d2.resolved.nameHTML);
+      selection2.append("div").attr("class", "community-description").html(d2.resolved.descriptionHTML);
+      if (d2.resolved.extendedDescriptionHTML || d2.languageCodes && d2.languageCodes.length) {
+        selection2.append("div").call(
+          uiDisclosure(context, "community-more-".concat(d2.id), false).expanded(false).updatePreference(false).label(() => _t.append("success.more")).content(showMore)
+        );
+      }
+      let nextEvents = (d2.events || []).map((event) => {
+        event.date = parseEventDate(event.when);
+        return event;
+      }).filter((event) => {
+        const t2 = event.date.getTime();
+        const now3 = (/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0);
+        return !isNaN(t2) && t2 >= now3;
+      }).sort((a2, b2) => {
+        return a2.date < b2.date ? -1 : a2.date > b2.date ? 1 : 0;
+      }).slice(0, MAXEVENTS);
+      if (nextEvents.length) {
+        selection2.append("div").call(
+          uiDisclosure(context, "community-events-".concat(d2.id), false).expanded(false).updatePreference(false).label(_t.html("success.events")).content(showNextEvents)
+        ).select(".hide-toggle").append("span").attr("class", "badge-text").text(nextEvents.length);
+      }
+      function showMore(selection3) {
+        let more = selection3.selectAll(".community-more").data([0]);
+        let moreEnter = more.enter().append("div").attr("class", "community-more");
+        if (d2.resolved.extendedDescriptionHTML) {
+          moreEnter.append("div").attr("class", "community-extended-description").html(d2.resolved.extendedDescriptionHTML);
+        }
+        if (d2.languageCodes && d2.languageCodes.length) {
+          const languageList = d2.languageCodes.map((code) => _mainLocalizer.languageName(code)).join(", ");
+          moreEnter.append("div").attr("class", "community-languages").call(_t.append("success.languages", { languages: languageList }));
+        }
+      }
+      function showNextEvents(selection3) {
+        let events = selection3.append("div").attr("class", "community-events");
+        let item = events.selectAll(".community-event").data(nextEvents);
+        let itemEnter = item.enter().append("div").attr("class", "community-event");
+        itemEnter.append("div").attr("class", "community-event-name").append("a").attr("target", "_blank").attr("href", (d4) => d4.url).text((d4) => {
+          let name = d4.name;
+          if (d4.i18n && d4.id) {
+            name = _t("community.".concat(communityID, ".events.").concat(d4.id, ".name"), { default: name });
+          }
+          return name;
+        });
+        itemEnter.append("div").attr("class", "community-event-when").text((d4) => {
+          let options2 = { weekday: "short", day: "numeric", month: "short", year: "numeric" };
+          if (d4.date.getHours() || d4.date.getMinutes()) {
+            options2.hour = "numeric";
+            options2.minute = "numeric";
+          }
+          return d4.date.toLocaleString(_mainLocalizer.localeCode(), options2);
+        });
+        itemEnter.append("div").attr("class", "community-event-where").text((d4) => {
+          let where = d4.where;
+          if (d4.i18n && d4.id) {
+            where = _t("community.".concat(communityID, ".events.").concat(d4.id, ".where"), { default: where });
           }
+          return where;
+        });
+        itemEnter.append("div").attr("class", "community-event-description").text((d4) => {
+          let description = d4.description;
+          if (d4.i18n && d4.id) {
+            description = _t("community.".concat(communityID, ".events.").concat(d4.id, ".description"), { default: description });
+          }
+          return description;
         });
       }
+    }
+    success.changeset = function(val) {
+      if (!arguments.length) return _changeset2;
+      _changeset2 = val;
+      return success;
     };
-    tool.uninstall = function() {
-      context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
-      context.map().on("move.undo_redo", null).on("drawn.undo_redo", null);
-      context.history().on("change.undo_redo", null);
-      context.on("enter.undo_redo", null);
+    success.location = function(val) {
+      if (!arguments.length) return _location;
+      _location = val;
+      return success;
     };
-    return tool;
+    return utilRebind(success, dispatch14, "on");
   }
 
-  // modules/ui/top_toolbar.js
-  function uiTopToolbar(context) {
-    var sidebarToggle = uiToolSidebarToggle(context), modes = uiToolDrawModes(context), notes = uiToolNotes(context), undoRedo = uiToolUndoRedo(context), save = uiToolSave(context);
-    function notesEnabled() {
-      var noteLayer = context.layers().layer("notes");
-      return noteLayer && noteLayer.enabled();
-    }
-    function topToolbar(bar) {
-      bar.on("wheel.topToolbar", function(d3_event) {
-        if (!d3_event.deltaX) {
-          bar.node().scrollLeft += d3_event.deltaY;
-        }
+  // modules/ui/fields/input.js
+  var likelyRawNumberFormat = /^-?(0\.\d*|\d*\.\d{0,2}(\d{4,})?|\d{4,}\.\d{3})$/;
+  function uiFieldText(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var input = select_default2(null);
+    var outlinkButton = select_default2(null);
+    var wrap2 = select_default2(null);
+    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
+    var _entityIDs = [];
+    var _tags;
+    var _phoneFormats = {};
+    const isDirectionField = field.key.split(":").some((keyPart) => keyPart === "direction");
+    const formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
+    const parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
+    const countDecimalPlaces = _mainLocalizer.decimalPlaceCounter(_mainLocalizer.languageCode());
+    if (field.type === "tel") {
+      _mainFileFetcher.get("phone_formats").then(function(d2) {
+        _phoneFormats = d2;
+        updatePhonePlaceholder();
+      }).catch(function() {
       });
-      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
-      context.layers().on("change.topToolbar", debouncedUpdate);
-      update();
-      function update() {
-        var tools = [
-          sidebarToggle,
-          "spacer",
-          modes
-        ];
-        tools.push("spacer");
-        if (notesEnabled()) {
-          tools = tools.concat([notes, "spacer"]);
-        }
-        tools = tools.concat([undoRedo, save]);
-        var toolbarItems = bar.selectAll(".toolbar-item").data(tools, function(d2) {
-          return d2.id || d2;
+    }
+    function calcLocked() {
+      var isLocked = (field.id === "brand" || field.id === "network" || field.id === "operator" || field.id === "flag") && _entityIDs.length && _entityIDs.some(function(entityID) {
+        var entity = context.graph().hasEntity(entityID);
+        if (!entity) return false;
+        if (entity.tags.wikidata) return true;
+        var preset = _mainPresetIndex.match(entity, context.graph());
+        var isSuggestion = preset && preset.suggestion;
+        var which = field.id;
+        return isSuggestion && !!entity.tags[which] && !!entity.tags[which + ":wikidata"];
+      });
+      field.locked(isLocked);
+    }
+    function i3(selection2) {
+      calcLocked();
+      var isLocked = field.locked();
+      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      input = wrap2.selectAll("input").data([0]);
+      input = input.enter().append("input").attr("type", field.type === "identifier" ? "text" : field.type).attr("id", field.domId).classed(field.type, true).call(utilNoAuto).merge(input);
+      input.classed("disabled", !!isLocked).attr("readonly", isLocked || null).on("input", change(true)).on("blur", change()).on("change", change());
+      wrap2.call(_lengthIndicator);
+      if (field.type === "tel") {
+        updatePhonePlaceholder();
+      } else if (field.type === "number") {
+        var rtl = _mainLocalizer.textDirection() === "rtl";
+        input.attr("type", "text");
+        var inc = field.increment;
+        var buttons = wrap2.selectAll(".increment, .decrement").data(rtl ? [inc, -inc] : [-inc, inc]);
+        buttons.enter().append("button").attr("class", function(d2) {
+          var which = d2 > 0 ? "increment" : "decrement";
+          return "form-field-button " + which;
+        }).attr("title", function(d2) {
+          var which = d2 > 0 ? "increment" : "decrement";
+          return _t("inspector.".concat(which));
+        }).merge(buttons).on("click", function(d3_event, d2) {
+          d3_event.preventDefault();
+          var isMixed = Array.isArray(_tags[field.key]);
+          if (isMixed) return;
+          var raw_vals = input.node().value || "0";
+          var vals = raw_vals.split(";");
+          vals = vals.map(function(v2) {
+            v2 = v2.trim();
+            const isRawNumber = likelyRawNumberFormat.test(v2);
+            var num = isRawNumber ? parseFloat(v2) : parseLocaleFloat(v2);
+            if (isDirectionField) {
+              const compassDir = cardinal[v2.toLowerCase()];
+              if (compassDir !== void 0) {
+                num = compassDir;
+              }
+            }
+            if (!isFinite(num)) return v2;
+            num = parseFloat(num);
+            if (!isFinite(num)) return v2;
+            num += d2;
+            if (isDirectionField) {
+              num = (num % 360 + 360) % 360;
+            }
+            return formatFloat(clamped(num), isRawNumber ? v2.includes(".") ? v2.split(".")[1].length : 0 : countDecimalPlaces(v2));
+          });
+          input.node().value = vals.join(";");
+          change()();
         });
-        toolbarItems.exit().each(function(d2) {
-          if (d2.uninstall) {
-            d2.uninstall();
+      } else if (field.type === "identifier" && field.urlFormat && field.pattern) {
+        input.attr("type", "text");
+        outlinkButton = wrap2.selectAll(".foreign-id-permalink").data([0]);
+        outlinkButton = outlinkButton.enter().append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", function() {
+          var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
+          if (domainResults.length >= 2 && domainResults[1]) {
+            var domain = domainResults[1];
+            return _t("icons.view_on", { domain });
           }
-        }).remove();
-        var itemsEnter = toolbarItems.enter().append("div").attr("class", function(d2) {
-          var classes = "toolbar-item " + (d2.id || d2).replace("_", "-");
-          if (d2.klass)
-            classes += " " + d2.klass;
-          return classes;
-        });
-        var actionableItems = itemsEnter.filter(function(d2) {
-          return d2 !== "spacer";
-        });
-        actionableItems.append("div").attr("class", "item-content").each(function(d2) {
-          select_default2(this).call(d2.render, bar);
-        });
-        actionableItems.append("div").attr("class", "item-label").each(function(d2) {
-          d2.label(select_default2(this));
-        });
+          return "";
+        }).merge(outlinkButton);
+        outlinkButton.on("click", function(d3_event) {
+          d3_event.preventDefault();
+          var value = validIdentifierValueForLink();
+          if (value) {
+            var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
+            window.open(url, "_blank");
+          }
+        }).classed("disabled", () => !validIdentifierValueForLink()).merge(outlinkButton);
+      } else if (field.type === "url") {
+        input.attr("type", "text");
+        outlinkButton = wrap2.selectAll(".foreign-id-permalink").data([0]);
+        outlinkButton.enter().append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", () => _t("icons.visit_website")).on("click", function(d3_event) {
+          d3_event.preventDefault();
+          const value = validIdentifierValueForLink();
+          if (value) window.open(value, "_blank");
+        }).merge(outlinkButton);
+      } else if (field.type === "colour") {
+        input.attr("type", "text");
+        updateColourPreview();
+      } else if (field.type === "date") {
+        input.attr("type", "text");
+        updateDateField();
       }
     }
-    return topToolbar;
-  }
-
-  // modules/ui/zoom_to_selection.js
-  function uiZoomToSelection(context) {
-    function isDisabled() {
-      var mode = context.mode();
-      return !mode || !mode.zoomToSelected;
+    function updateColourPreview() {
+      wrap2.selectAll(".colour-preview").remove();
+      const colour = utilGetSetValue(input);
+      if (!isColourValid(colour) && colour !== "") {
+        wrap2.selectAll("input.colour-selector").remove();
+        wrap2.selectAll(".form-field-button").remove();
+        return;
+      }
+      var colourSelector = wrap2.selectAll(".colour-selector").data([0]);
+      colourSelector.enter().append("input").attr("type", "color").attr("class", "colour-selector").on("input", debounce_default(function(d3_event) {
+        d3_event.preventDefault();
+        var colour2 = this.value;
+        if (!isColourValid(colour2)) return;
+        utilGetSetValue(input, this.value);
+        change()();
+        updateColourPreview();
+      }, 100));
+      wrap2.selectAll("input.colour-selector").attr("value", colour);
+      var chooserButton = wrap2.selectAll(".colour-preview").data([colour]);
+      chooserButton = chooserButton.enter().append("div").attr("class", "form-field-button colour-preview").append("div").style("background-color", (d2) => d2).attr("class", "colour-box");
+      if (colour === "") {
+        chooserButton = chooserButton.call(svgIcon("#iD-icon-edit"));
+      }
+      chooserButton.on("click", () => wrap2.select(".colour-selector").node().showPicker());
     }
-    var _lastPointerUpType;
-    function pointerup(d3_event) {
-      _lastPointerUpType = d3_event.pointerType;
+    function updateDateField() {
+      function isDateValid(date2) {
+        return date2.match(/^[0-9]{4}(-[0-9]{2}(-[0-9]{2})?)?$/);
+      }
+      const date = utilGetSetValue(input);
+      const now3 = /* @__PURE__ */ new Date();
+      const today = new Date(now3.getTime() - now3.getTimezoneOffset() * 6e4).toISOString().split("T")[0];
+      if ((field.key === "check_date" || field.key === "survey:date") && date !== today) {
+        wrap2.selectAll(".date-set-today").data([0]).enter().append("button").attr("class", "form-field-button date-set-today").call(svgIcon("#fas-rotate")).call(uiTooltip().title(() => _t.append("inspector.set_today"))).on("click", () => {
+          utilGetSetValue(input, today);
+          change()();
+          updateDateField();
+        });
+      } else {
+        wrap2.selectAll(".date-set-today").remove();
+      }
+      if (!isDateValid(date) && date !== "") {
+        wrap2.selectAll("input.date-selector").remove();
+        wrap2.selectAll(".date-calendar").remove();
+        return;
+      }
+      if (utilDetect().browser !== "Safari") {
+        var dateSelector = wrap2.selectAll(".date-selector").data([0]);
+        dateSelector.enter().append("input").attr("type", "date").attr("class", "date-selector").on("input", debounce_default(function(d3_event) {
+          d3_event.preventDefault();
+          var date2 = this.value;
+          if (!isDateValid(date2)) return;
+          utilGetSetValue(input, this.value);
+          change()();
+          updateDateField();
+        }, 100));
+        wrap2.selectAll("input.date-selector").attr("value", date);
+        var calendarButton = wrap2.selectAll(".date-calendar").data([date]);
+        calendarButton = calendarButton.enter().append("button").attr("class", "form-field-button date-calendar").call(svgIcon("#fas-calendar-days"));
+        calendarButton.on("click", () => wrap2.select(".date-selector").node().showPicker());
+      }
     }
-    function click(d3_event) {
-      d3_event.preventDefault();
-      if (isDisabled()) {
-        if (_lastPointerUpType === "touch" || _lastPointerUpType === "pen") {
-          context.ui().flash.duration(2e3).iconName("#iD-icon-framed-dot").iconClass("disabled").label(_t.append("inspector.zoom_to.no_selection"))();
+    function updatePhonePlaceholder() {
+      if (input.empty() || !Object.keys(_phoneFormats).length) return;
+      var extent = combinedEntityExtent();
+      var countryCode = extent && iso1A2Code(extent.center());
+      var format2 = countryCode && _phoneFormats[countryCode.toLowerCase()];
+      if (format2) input.attr("placeholder", format2);
+    }
+    function validIdentifierValueForLink() {
+      var _a3;
+      const value = utilGetSetValue(input).trim();
+      if (field.type === "url" && value) {
+        try {
+          return new URL(value).href;
+        } catch {
+          return null;
         }
+      }
+      if (field.type === "identifier" && field.pattern) {
+        return value && ((_a3 = value.match(new RegExp(field.pattern))) == null ? void 0 : _a3[0]);
+      }
+      return null;
+    }
+    function clamped(num) {
+      if (field.minValue !== void 0) {
+        num = Math.max(num, field.minValue);
+      }
+      if (field.maxValue !== void 0) {
+        num = Math.min(num, field.maxValue);
+      }
+      return num;
+    }
+    function getVals(tags) {
+      if (field.keys) {
+        const multiSelection = context.selectedIDs();
+        tags = multiSelection.length > 1 ? context.selectedIDs().map((id2) => context.graph().entity(id2)).map((entity) => entity.tags) : [tags];
+        return tags.map((tags2) => new Set(field.keys.reduce((acc, key) => acc.concat(tags2[key]), []).filter(Boolean))).map((vals) => vals.size === 0 ? /* @__PURE__ */ new Set([void 0]) : vals).reduce((a2, b2) => /* @__PURE__ */ new Set([...a2, ...b2]));
       } else {
-        var mode = context.mode();
-        if (mode && mode.zoomToSelected) {
-          mode.zoomToSelected();
-        }
+        return new Set([].concat(tags[field.key]));
       }
-      _lastPointerUpType = null;
     }
-    return function(selection2) {
-      var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(function() {
-        if (isDisabled()) {
-          return _t.append("inspector.zoom_to.no_selection");
+    function change(onInput) {
+      return function() {
+        var t2 = {};
+        var val = utilGetSetValue(input);
+        if (!onInput) val = context.cleanTagValue(val);
+        if (!val && getVals(_tags).size > 1) return;
+        var displayVal = val;
+        if (field.type === "number" && val) {
+          var numbers2 = val.split(";");
+          numbers2 = numbers2.map(function(v2) {
+            if (likelyRawNumberFormat.test(v2)) {
+              return v2;
+            }
+            var num = parseLocaleFloat(v2);
+            const fractionDigits = countDecimalPlaces(v2);
+            return isFinite(num) ? clamped(num).toFixed(fractionDigits) : v2;
+          });
+          val = numbers2.join(";");
         }
-        return _t.append("inspector.zoom_to.title");
-      }).keys([_t("inspector.zoom_to.key")]);
-      var button = selection2.append("button").on("pointerup", pointerup).on("click", click).call(svgIcon("#iD-icon-framed-dot", "light")).call(tooltipBehavior);
-      function setEnabledState() {
-        button.classed("disabled", isDisabled());
-        if (!button.select(".tooltip.in").empty()) {
-          button.call(tooltipBehavior.updateContent);
+        if (!onInput) utilGetSetValue(input, displayVal);
+        t2[field.key] = val || void 0;
+        if (field.keys) {
+          dispatch14.call("change", this, (tags) => {
+            if (field.keys.some((key) => tags[key])) {
+              field.keys.filter((key) => tags[key]).forEach((key) => {
+                tags[key] = val || void 0;
+              });
+            } else {
+              tags[field.key] = val || void 0;
+            }
+            return tags;
+          }, onInput);
+        } else {
+          dispatch14.call("change", this, t2, onInput);
         }
-      }
-      context.on("enter.uiZoomToSelection", setEnabledState);
-      setEnabledState();
-    };
-  }
-
-  // modules/ui/pane.js
-  function uiPane(id2, context) {
-    var _key;
-    var _label = "";
-    var _description = "";
-    var _iconName = "";
-    var _sections;
-    var _paneSelection = select_default2(null);
-    var _paneTooltip;
-    var pane = {
-      id: id2
-    };
-    pane.label = function(val) {
-      if (!arguments.length)
-        return _label;
-      _label = val;
-      return pane;
-    };
-    pane.key = function(val) {
-      if (!arguments.length)
-        return _key;
-      _key = val;
-      return pane;
-    };
-    pane.description = function(val) {
-      if (!arguments.length)
-        return _description;
-      _description = val;
-      return pane;
-    };
-    pane.iconName = function(val) {
-      if (!arguments.length)
-        return _iconName;
-      _iconName = val;
-      return pane;
-    };
-    pane.sections = function(val) {
-      if (!arguments.length)
-        return _sections;
-      _sections = val;
-      return pane;
-    };
-    pane.selection = function() {
-      return _paneSelection;
-    };
-    function hidePane() {
-      context.ui().togglePanes();
+      };
     }
-    pane.togglePane = function(d3_event) {
-      if (d3_event)
-        d3_event.preventDefault();
-      _paneTooltip.hide();
-      context.ui().togglePanes(!_paneSelection.classed("shown") ? _paneSelection : void 0);
-    };
-    pane.renderToggleButton = function(selection2) {
-      if (!_paneTooltip) {
-        _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(() => _description).keys([_key]);
-      }
-      selection2.append("button").on("click", pane.togglePane).call(svgIcon("#" + _iconName, "light")).call(_paneTooltip);
+    i3.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return i3;
     };
-    pane.renderContent = function(selection2) {
-      if (_sections) {
-        _sections.forEach(function(section) {
-          selection2.call(section.render);
+    i3.tags = function(tags) {
+      var _a3;
+      _tags = tags;
+      const vals = getVals(tags);
+      const isMixed = vals.size > 1;
+      var val = vals.size === 1 ? (_a3 = [...vals][0]) != null ? _a3 : "" : "";
+      var shouldUpdate;
+      if (field.type === "number" && val) {
+        var numbers2 = val.split(";");
+        var oriNumbers = utilGetSetValue(input).split(";");
+        if (numbers2.length !== oriNumbers.length) shouldUpdate = true;
+        numbers2 = numbers2.map(function(v2) {
+          v2 = v2.trim();
+          var num = Number(v2);
+          if (!isFinite(num) || v2 === "") return v2;
+          const fractionDigits = v2.includes(".") ? v2.split(".")[1].length : 0;
+          return formatFloat(num, fractionDigits);
         });
+        val = numbers2.join(";");
+        shouldUpdate = (inputValue, setValue) => {
+          const inputNums = inputValue.split(";").map(
+            (setVal) => likelyRawNumberFormat.test(setVal) ? parseFloat(setVal) : parseLocaleFloat(setVal)
+          );
+          const setNums = setValue.split(";").map(parseLocaleFloat);
+          return !isEqual_default(inputNums, setNums);
+        };
       }
-    };
-    pane.renderPane = function(selection2) {
-      _paneSelection = selection2.append("div").attr("class", "fillL map-pane hide " + id2 + "-pane").attr("pane", id2);
-      var heading2 = _paneSelection.append("div").attr("class", "pane-heading");
-      heading2.append("h2").text("").call(_label);
-      heading2.append("button").attr("title", _t("icons.close")).on("click", hidePane).call(svgIcon("#iD-icon-close"));
-      _paneSelection.append("div").attr("class", "pane-content").call(pane.renderContent);
-      if (_key) {
-        context.keybinding().on(_key, pane.togglePane);
+      utilGetSetValue(input, val, shouldUpdate).attr("title", isMixed ? [...vals].join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder() || _t("inspector.unknown")).classed("mixed", isMixed);
+      if (field.type === "number") {
+        const buttons = wrap2.selectAll(".increment, .decrement");
+        if (isMixed) {
+          buttons.attr("disabled", "disabled").classed("disabled", true);
+        } else {
+          var raw_vals = tags[field.key] || "0";
+          const canIncDec = raw_vals.split(";").some((val2) => isFinite(Number(val2)) || isDirectionField && cardinal[val2.trim().toLowerCase()]);
+          buttons.attr("disabled", canIncDec ? null : "disabled").classed("disabled", !canIncDec);
+        }
+      }
+      if (field.type === "tel") updatePhonePlaceholder();
+      if (field.type === "colour") updateColourPreview();
+      if (field.type === "date") updateDateField();
+      if (outlinkButton && !outlinkButton.empty()) {
+        var disabled = !validIdentifierValueForLink();
+        outlinkButton.classed("disabled", disabled);
+      }
+      if (!isMixed) {
+        _lengthIndicator.update(tags[field.key]);
       }
     };
-    return pane;
-  }
-
-  // modules/ui/sections/background_display_options.js
-  function uiSectionBackgroundDisplayOptions(context) {
-    var section = uiSection("background-display-options", context).label(() => _t.append("background.display_options")).disclosureContent(renderDisclosureContent);
-    var _storedOpacity = corePreferences("background-opacity");
-    var _minVal = 0;
-    var _maxVal = 3;
-    var _sliders = ["brightness", "contrast", "saturation", "sharpness"];
-    var _options = {
-      brightness: _storedOpacity !== null ? +_storedOpacity : 1,
-      contrast: 1,
-      saturation: 1,
-      sharpness: 1
+    i3.focus = function() {
+      var node = input.node();
+      if (node) node.focus();
     };
-    function clamp3(x2, min3, max3) {
-      return Math.max(min3, Math.min(x2, max3));
-    }
-    function updateValue(d2, val) {
-      val = clamp3(val, _minVal, _maxVal);
-      _options[d2] = val;
-      context.background()[d2](val);
-      if (d2 === "brightness") {
-        corePreferences("background-opacity", val);
-      }
-      section.reRender();
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
     }
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".display-options-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "display-options-container controls-list");
-      var slidersEnter = containerEnter.selectAll(".display-control").data(_sliders).enter().append("label").attr("class", function(d2) {
-        return "display-control display-control-" + d2;
-      });
-      slidersEnter.html(function(d2) {
-        return _t.html("background." + d2);
-      }).append("span").attr("class", function(d2) {
-        return "display-option-value display-option-value-" + d2;
-      });
-      var sildersControlEnter = slidersEnter.append("div").attr("class", "control-wrap");
-      sildersControlEnter.append("input").attr("class", function(d2) {
-        return "display-option-input display-option-input-" + d2;
-      }).attr("type", "range").attr("min", _minVal).attr("max", _maxVal).attr("step", "0.05").on("input", function(d3_event, d2) {
-        var val = select_default2(this).property("value");
-        if (!val && d3_event && d3_event.target) {
-          val = d3_event.target.value;
-        }
-        updateValue(d2, val);
-      });
-      sildersControlEnter.append("button").attr("title", function(d2) {
-        return "".concat(_t("background.reset"), " ").concat(_t("background." + d2));
-      }).attr("class", function(d2) {
-        return "display-option-reset display-option-reset-" + d2;
-      }).on("click", function(d3_event, d2) {
-        if (d3_event.button !== 0)
-          return;
-        updateValue(d2, 1);
-      }).call(svgIcon("#iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")));
-      containerEnter.append("a").attr("class", "display-option-resetlink").attr("role", "button").attr("href", "#").call(_t.append("background.reset_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        for (var i3 = 0; i3 < _sliders.length; i3++) {
-          updateValue(_sliders[i3], 1);
-        }
-      });
-      container = containerEnter.merge(container);
-      container.selectAll(".display-option-input").property("value", function(d2) {
-        return _options[d2];
+    return utilRebind(i3, dispatch14, "on");
+  }
+
+  // modules/ui/fields/access.js
+  function uiFieldAccess(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var items = select_default2(null);
+    var _tags;
+    function access(selection2) {
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var list2 = wrap2.selectAll("ul").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
+      items = list2.selectAll("li").data(field.keys);
+      var enter = items.enter().append("li").attr("class", function(d2) {
+        return "labeled-input preset-access-" + d2;
       });
-      container.selectAll(".display-option-value").text(function(d2) {
-        return Math.floor(_options[d2] * 100) + "%";
+      enter.append("div").attr("class", "label preset-label-access").attr("for", function(d2) {
+        return "preset-input-access-" + d2;
+      }).html(function(d2) {
+        return field.t.html("types." + d2);
       });
-      container.selectAll(".display-option-reset").classed("disabled", function(d2) {
-        return _options[d2] === 1;
+      enter.append("div").attr("class", "preset-input-access-wrap").append("input").attr("type", "text").attr("class", function(d2) {
+        return "preset-input-access preset-input-access-" + d2;
+      }).call(utilNoAuto).each(function(d2) {
+        select_default2(this).call(
+          uiCombobox(context, "access-" + d2).data(access.options(d2))
+        );
       });
-      if (containerEnter.size() && _options.brightness !== 1) {
-        context.background().brightness(_options.brightness);
-      }
+      items = items.merge(enter);
+      wrap2.selectAll(".preset-input-access").on("change", change).on("blur", change);
     }
-    return section;
-  }
-
-  // modules/ui/settings/custom_background.js
-  function uiSettingsCustomBackground() {
-    var dispatch14 = dispatch_default("change");
-    function render(selection2) {
-      var _origSettings = {
-        template: corePreferences("background-custom-template")
-      };
-      var _currSettings = {
-        template: corePreferences("background-custom-template")
-      };
-      var example = "https://tile.openstreetmap.org/{zoom}/{x}/{y}.png";
-      var modal = uiConfirm(selection2).okButton();
-      modal.classed("settings-modal settings-custom-background", true);
-      modal.select(".modal-section.header").append("h3").call(_t.append("settings.custom_background.header"));
-      var textSection = modal.select(".modal-section.message-text");
-      var instructions = "".concat(_t.html("settings.custom_background.instructions.info"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.wms.tokens_label"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.proj"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.wkid"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.dimensions"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.bbox"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.tms.tokens_label"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.xyz"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.flipped_y"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.switch"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.quadtile"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.scale_factor"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.example"), "\n") + "`".concat(example, "`");
-      textSection.append("div").attr("class", "instructions-template").html(marked(instructions));
-      textSection.append("textarea").attr("class", "field-template").attr("placeholder", _t("settings.custom_background.template.placeholder")).call(utilNoAuto).property("value", _currSettings.template);
-      var buttonSection = modal.select(".modal-section.buttons");
-      buttonSection.insert("button", ".ok-button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
-      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
-      buttonSection.select(".ok-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
-      function isSaveDisabled() {
-        return null;
+    function change(d3_event, d2) {
+      var tag2 = {};
+      var value = context.cleanTagValue(utilGetSetValue(select_default2(this)));
+      if (!value && typeof _tags[d2] !== "string") return;
+      tag2[d2] = value || void 0;
+      dispatch14.call("change", this, tag2);
+    }
+    access.options = function(type2) {
+      var options2 = [
+        "yes",
+        "no",
+        "designated",
+        "permissive",
+        "destination",
+        "customers",
+        "private",
+        "permit",
+        "unknown"
+      ];
+      if (type2 === "access") {
+        options2 = options2.filter((v2) => v2 !== "yes" && v2 !== "designated");
       }
-      function clickCancel() {
-        textSection.select(".field-template").property("value", _origSettings.template);
-        corePreferences("background-custom-template", _origSettings.template);
-        this.blur();
-        modal.close();
+      if (type2 === "bicycle") {
+        options2.splice(options2.length - 4, 0, "dismount");
       }
-      function clickSave() {
-        _currSettings.template = textSection.select(".field-template").property("value");
-        corePreferences("background-custom-template", _currSettings.template);
-        this.blur();
-        modal.close();
-        dispatch14.call("change", this, _currSettings);
+      var stringsField = field.resolveReference("stringsCrossReference");
+      return options2.map(function(option) {
+        return {
+          title: stringsField.t("options." + option + ".description"),
+          value: option
+        };
+      });
+    };
+    const placeholdersByTag = {
+      highway: {
+        footway: {
+          foot: "designated",
+          motor_vehicle: "no"
+        },
+        steps: {
+          foot: "yes",
+          motor_vehicle: "no",
+          bicycle: "no",
+          horse: "no"
+        },
+        ladder: {
+          foot: "yes",
+          motor_vehicle: "no",
+          bicycle: "no",
+          horse: "no"
+        },
+        pedestrian: {
+          foot: "yes",
+          motor_vehicle: "no"
+        },
+        cycleway: {
+          motor_vehicle: "no",
+          bicycle: "designated"
+        },
+        bridleway: {
+          motor_vehicle: "no",
+          horse: "designated"
+        },
+        path: {
+          foot: "yes",
+          motor_vehicle: "no",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        motorway: {
+          foot: "no",
+          motor_vehicle: "yes",
+          bicycle: "no",
+          horse: "no"
+        },
+        trunk: {
+          motor_vehicle: "yes"
+        },
+        primary: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        secondary: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        tertiary: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        residential: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        unclassified: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        service: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        motorway_link: {
+          foot: "no",
+          motor_vehicle: "yes",
+          bicycle: "no",
+          horse: "no"
+        },
+        trunk_link: {
+          motor_vehicle: "yes"
+        },
+        primary_link: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        secondary_link: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        tertiary_link: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        construction: {
+          access: "no"
+        },
+        busway: {
+          access: "no",
+          bus: "designated",
+          emergency: "yes"
+        }
+      },
+      barrier: {
+        bollard: {
+          access: "no",
+          bicycle: "yes",
+          foot: "yes"
+        },
+        bus_trap: {
+          motor_vehicle: "no",
+          psv: "yes",
+          foot: "yes",
+          bicycle: "yes"
+        },
+        city_wall: {
+          access: "no"
+        },
+        coupure: {
+          access: "yes"
+        },
+        cycle_barrier: {
+          motor_vehicle: "no"
+        },
+        ditch: {
+          access: "no"
+        },
+        entrance: {
+          access: "yes"
+        },
+        fence: {
+          access: "no"
+        },
+        hedge: {
+          access: "no"
+        },
+        jersey_barrier: {
+          access: "no"
+        },
+        motorcycle_barrier: {
+          motor_vehicle: "no"
+        },
+        rail_guard: {
+          access: "no"
+        }
       }
-    }
-    return utilRebind(render, dispatch14, "on");
+    };
+    access.tags = function(tags) {
+      _tags = tags;
+      utilGetSetValue(items.selectAll(".preset-input-access"), function(d2) {
+        return typeof tags[d2] === "string" ? tags[d2] : "";
+      }).classed("mixed", function(d2) {
+        return tags[d2] && Array.isArray(tags[d2]);
+      }).attr("title", function(d2) {
+        return tags[d2] && Array.isArray(tags[d2]) && tags[d2].filter(Boolean).join("\n");
+      }).attr("placeholder", function(d2) {
+        if (tags[d2] && Array.isArray(tags[d2])) {
+          return _t("inspector.multiple_values");
+        }
+        if (d2 === "bicycle" || d2 === "motor_vehicle") {
+          if (tags.vehicle && typeof tags.vehicle === "string") {
+            return tags.vehicle;
+          }
+        }
+        if (tags.access && typeof tags.access === "string") {
+          return tags.access;
+        }
+        function getPlaceholdersByTag(key, placeholdersByKey) {
+          if (typeof tags[key] === "string") {
+            if (placeholdersByKey[tags[key]] && placeholdersByKey[tags[key]][d2]) {
+              return placeholdersByKey[tags[key]][d2];
+            }
+          } else {
+            var impliedAccesses = tags[key].filter(Boolean).map(function(val) {
+              return placeholdersByKey[val] && placeholdersByKey[val][d2];
+            }).filter(Boolean);
+            if (impliedAccesses.length === tags[key].length && new Set(impliedAccesses).size === 1) {
+              return impliedAccesses[0];
+            }
+          }
+        }
+        for (const key in placeholdersByTag) {
+          if (tags[key]) {
+            const impliedAccess = getPlaceholdersByTag(key, placeholdersByTag[key]);
+            if (impliedAccess) {
+              return impliedAccess;
+            }
+          }
+        }
+        if (d2 === "access" && !tags.barrier) {
+          return "yes";
+        }
+        return field.placeholder();
+      });
+    };
+    access.focus = function() {
+      items.selectAll(".preset-input-access").node().focus();
+    };
+    return utilRebind(access, dispatch14, "on");
   }
 
-  // modules/ui/sections/background_list.js
-  function uiSectionBackgroundList(context) {
-    var _backgroundList = select_default2(null);
-    var _customSource = context.background().findSource("custom");
-    var _settingsCustomBackground = uiSettingsCustomBackground(context).on("change", customChanged);
-    var section = uiSection("background-list", context).label(() => _t.append("background.backgrounds")).disclosureContent(renderDisclosureContent);
-    function previousBackgroundID() {
-      return corePreferences("background-last-used-toggle");
-    }
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".layer-background-list").data([0]);
-      _backgroundList = container.enter().append("ul").attr("class", "layer-list layer-background-list").attr("dir", "auto").merge(container);
-      var bgExtrasListEnter = selection2.selectAll(".bg-extras-list").data([0]).enter().append("ul").attr("class", "layer-list bg-extras-list");
-      var minimapLabelEnter = bgExtrasListEnter.append("li").attr("class", "minimap-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("background.minimap.tooltip")).keys([_t("background.minimap.key")]).placement("top")
-      );
-      minimapLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        uiMapInMap.toggle();
-      });
-      minimapLabelEnter.append("span").call(_t.append("background.minimap.description"));
-      var panelLabelEnter = bgExtrasListEnter.append("li").attr("class", "background-panel-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("background.panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.background.key"))]).placement("top")
-      );
-      panelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        context.ui().info.toggle("background");
-      });
-      panelLabelEnter.append("span").call(_t.append("background.panel.description"));
-      var locPanelLabelEnter = bgExtrasListEnter.append("li").attr("class", "location-panel-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("background.location_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.location.key"))]).placement("top")
-      );
-      locPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        context.ui().info.toggle("location");
-      });
-      locPanelLabelEnter.append("span").call(_t.append("background.location_panel.description"));
-      selection2.selectAll(".imagery-faq").data([0]).enter().append("div").attr("class", "imagery-faq").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/openstreetmap/iD/blob/develop/FAQ.md#how-can-i-report-an-issue-with-background-imagery").append("span").call(_t.append("background.imagery_problem_faq"));
-      _backgroundList.call(drawListItems, "radio", function(d3_event, d2) {
-        chooseBackground(d2);
-      }, function(d2) {
-        return !d2.isHidden() && !d2.overlay;
-      });
-    }
-    function setTooltips(selection2) {
-      selection2.each(function(d2, i3, nodes) {
-        var item = select_default2(this).select("label");
-        var span = item.select("span");
-        var placement = i3 < nodes.length / 2 ? "bottom" : "top";
-        var hasDescription = d2.hasDescription();
-        var isOverflowing = span.property("clientWidth") !== span.property("scrollWidth");
-        item.call(uiTooltip().destroyAny);
-        if (d2.id === previousBackgroundID()) {
-          item.call(
-            uiTooltip().placement(placement).title(() => _t.append("background.switch")).keys([uiCmd("\u2318" + _t("background.key"))])
-          );
-        } else if (hasDescription || isOverflowing) {
-          item.call(
-            uiTooltip().placement(placement).title(() => hasDescription ? d2.description() : d2.label())
-          );
+  // modules/ui/fields/address.js
+  function uiFieldAddress(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var _selection = select_default2(null);
+    var _wrap = select_default2(null);
+    var addrField = _mainPresetIndex.field("address");
+    var _entityIDs = [];
+    var _tags;
+    var _countryCode;
+    var _addressFormats = [{
+      format: [
+        ["housenumber", "street"],
+        ["city", "postcode"]
+      ]
+    }];
+    _mainFileFetcher.get("address_formats").then(function(d2) {
+      _addressFormats = d2;
+      if (!_selection.empty()) {
+        _selection.call(address);
+      }
+    }).catch(function() {
+    });
+    function getNear(isAddressable, type2, searchRadius, resultProp) {
+      var extent = combinedEntityExtent();
+      var l2 = extent.center();
+      var box = geoExtent(l2).padByMeters(searchRadius);
+      var features = context.history().intersects(box).filter(isAddressable).map((d2) => {
+        let dist = geoSphericalDistance(d2.extent(context.graph()).center(), l2);
+        if (d2.geometry(context.graph()) === "line") {
+          var loc = context.projection([
+            (extent[0][0] + extent[1][0]) / 2,
+            (extent[0][1] + extent[1][1]) / 2
+          ]);
+          var choice = geoChooseEdge(context.graph().childNodes(d2), loc, context.projection);
+          dist = geoSphericalDistance(choice.loc, l2);
         }
+        const value = resultProp && d2.tags[resultProp] ? d2.tags[resultProp] : d2.tags.name;
+        let title = value;
+        if (type2 === "street") {
+          title = "".concat(addrField.t("placeholders.street"), ": ").concat(title);
+        } else if (type2 === "place") {
+          title = "".concat(addrField.t("placeholders.place"), ": ").concat(title);
+        }
+        return {
+          title,
+          value,
+          dist,
+          type: type2,
+          klass: "address-".concat(type2)
+        };
+      }).sort(function(a2, b2) {
+        return a2.dist - b2.dist;
       });
+      return utilArrayUniqBy(features, "value");
     }
-    function drawListItems(layerList, type2, change, filter2) {
-      var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter2).sort(function(a2, b2) {
-        return a2.best() && !b2.best() ? -1 : b2.best() && !a2.best() ? 1 : descending(a2.area(), b2.area()) || ascending(a2.name(), b2.name()) || 0;
-      });
-      var layerLinks = layerList.selectAll("li").data(sources, function(d2, i3) {
-        return d2.id + "---" + i3;
-      });
-      layerLinks.exit().remove();
-      var enter = layerLinks.enter().append("li").classed("layer-custom", function(d2) {
-        return d2.id === "custom";
-      }).classed("best", function(d2) {
-        return d2.best();
-      });
-      var label = enter.append("label");
-      label.append("input").attr("type", type2).attr("name", "background-layer").attr("value", function(d2) {
-        return d2.id;
-      }).on("change", change);
-      label.append("span").each(function(d2) {
-        d2.label()(select_default2(this));
-      });
-      enter.filter(function(d2) {
-        return d2.id === "custom";
-      }).append("button").attr("class", "layer-browse").call(
-        uiTooltip().title(() => _t.append("settings.custom_background.tooltip")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        editCustom();
-      }).call(svgIcon("#iD-icon-more"));
-      enter.filter(function(d2) {
-        return d2.best();
-      }).append("div").attr("class", "best").call(
-        uiTooltip().title(() => _t.append("background.best_imagery")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).append("span").text("\u2605");
-      layerList.call(updateLayerSelections);
-    }
-    function updateLayerSelections(selection2) {
-      function active(d2) {
-        return context.background().showsLayer(d2);
+    function getNearStreets() {
+      function isAddressable(d2) {
+        return d2.tags.highway && d2.tags.name && d2.type === "way";
       }
-      selection2.selectAll("li").classed("active", active).classed("switch", function(d2) {
-        return d2.id === previousBackgroundID();
-      }).call(setTooltips).selectAll("input").property("checked", active);
+      return getNear(isAddressable, "street", 200);
     }
-    function chooseBackground(d2) {
-      if (d2.id === "custom" && !d2.template()) {
-        return editCustom();
+    function getNearPlaces() {
+      function isAddressable(d2) {
+        if (d2.tags.name) {
+          if (d2.tags.place) return true;
+          if (d2.tags.boundary === "administrative" && d2.tags.admin_level > 8) return true;
+        }
+        return false;
       }
-      var previousBackground = context.background().baseLayerSource();
-      corePreferences("background-last-used-toggle", previousBackground.id);
-      corePreferences("background-last-used", d2.id);
-      context.background().baseLayerSource(d2);
+      return getNear(isAddressable, "place", 200);
     }
-    function customChanged(d2) {
-      if (d2 && d2.template) {
-        _customSource.template(d2.template);
-        chooseBackground(_customSource);
-      } else {
-        _customSource.template("");
-        chooseBackground(context.background().findSource("none"));
+    function getNearCities() {
+      function isAddressable(d2) {
+        if (d2.tags.name) {
+          if (d2.tags.boundary === "administrative" && d2.tags.admin_level === "8") return true;
+          if (d2.tags.border_type === "city") return true;
+          if (d2.tags.place === "city" || d2.tags.place === "town" || d2.tags.place === "village") return true;
+        }
+        if (d2.tags["".concat(field.key, ":city")]) return true;
+        return false;
       }
+      return getNear(isAddressable, "city", 200, "".concat(field.key, ":city"));
     }
-    function editCustom() {
-      context.container().call(_settingsCustomBackground);
-    }
-    context.background().on("change.background_list", function() {
-      _backgroundList.call(updateLayerSelections);
-    });
-    context.map().on(
-      "move.background_list",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
-  }
-
-  // modules/ui/sections/background_offset.js
-  function uiSectionBackgroundOffset(context) {
-    var section = uiSection("background-offset", context).label(() => _t.append("background.fix_misalignment")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    var _directions = [
-      ["top", [0, -0.5]],
-      ["left", [-0.5, 0]],
-      ["right", [0.5, 0]],
-      ["bottom", [0, 0.5]]
-    ];
-    function updateValue() {
-      var meters = geoOffsetToMeters(context.background().offset());
-      var x2 = +meters[0].toFixed(2);
-      var y2 = +meters[1].toFixed(2);
-      context.container().selectAll(".nudge-inner-rect").select("input").classed("error", false).property("value", x2 + ", " + y2);
-      context.container().selectAll(".nudge-reset").classed("disabled", function() {
-        return x2 === 0 && y2 === 0;
-      });
-    }
-    function resetOffset() {
-      context.background().offset([0, 0]);
-      updateValue();
+    function getNearPostcodes() {
+      return [...new Set([].concat(getNearValues("postcode")).concat(getNear((d2) => d2.tags.postal_code, "postcode", 200, "postal_code")))];
     }
-    function nudge(d2) {
-      context.background().nudge(d2, context.map().zoom());
-      updateValue();
+    function getNearValues(key) {
+      const tagKey = "".concat(field.key, ":").concat(key);
+      function hasTag(d2) {
+        return _entityIDs.indexOf(d2.id) === -1 && d2.tags[tagKey];
+      }
+      return getNear(hasTag, key, 200, tagKey);
     }
-    function inputOffset() {
-      var input = select_default2(this);
-      var d2 = input.node().value;
-      if (d2 === "")
-        return resetOffset();
-      d2 = d2.replace(/;/g, ",").split(",").map(function(n3) {
-        return !isNaN(n3) && n3;
-      });
-      if (d2.length !== 2 || !d2[0] || !d2[1]) {
-        input.classed("error", true);
-        return;
+    function updateForCountryCode() {
+      if (!_countryCode) return;
+      var addressFormat;
+      for (var i3 = 0; i3 < _addressFormats.length; i3++) {
+        var format2 = _addressFormats[i3];
+        if (!format2.countryCodes) {
+          addressFormat = format2;
+        } else if (format2.countryCodes.indexOf(_countryCode) !== -1) {
+          addressFormat = format2;
+          break;
+        }
       }
-      context.background().offset(geoMetersToOffset(d2));
-      updateValue();
-    }
-    function dragOffset(d3_event) {
-      if (d3_event.button !== 0)
-        return;
-      var origin = [d3_event.clientX, d3_event.clientY];
-      var pointerId = d3_event.pointerId || "mouse";
-      context.container().append("div").attr("class", "nudge-surface");
-      select_default2(window).on(_pointerPrefix + "move.drag-bg-offset", pointermove).on(_pointerPrefix + "up.drag-bg-offset", pointerup);
-      if (_pointerPrefix === "pointer") {
-        select_default2(window).on("pointercancel.drag-bg-offset", pointerup);
+      var dropdowns = addressFormat.dropdowns || [
+        "city",
+        "county",
+        "country",
+        "district",
+        "hamlet",
+        "neighbourhood",
+        "place",
+        "postcode",
+        "province",
+        "quarter",
+        "state",
+        "street",
+        "street+place",
+        "subdistrict",
+        "suburb"
+      ];
+      var widths = addressFormat.widths || {
+        housenumber: 1 / 5,
+        unit: 1 / 5,
+        street: 1 / 2,
+        place: 1 / 2,
+        city: 2 / 3,
+        state: 1 / 4,
+        postcode: 1 / 3
+      };
+      function row(r2) {
+        var total = r2.reduce(function(sum, key) {
+          return sum + (widths[key] || 0.5);
+        }, 0);
+        return r2.map(function(key) {
+          return {
+            id: key,
+            width: (widths[key] || 0.5) / total
+          };
+        });
       }
-      function pointermove(d3_event2) {
-        if (pointerId !== (d3_event2.pointerId || "mouse"))
-          return;
-        var latest = [d3_event2.clientX, d3_event2.clientY];
-        var d2 = [
-          -(origin[0] - latest[0]) / 4,
-          -(origin[1] - latest[1]) / 4
-        ];
-        origin = latest;
-        nudge(d2);
+      var rows = _wrap.selectAll(".addr-row").data(addressFormat.format, function(d2) {
+        return d2.toString();
+      });
+      rows.exit().remove();
+      rows.enter().append("div").attr("class", "addr-row").selectAll("input").data(row).enter().append("input").property("type", "text").call(updatePlaceholder).attr("class", function(d2) {
+        return "addr-" + d2.id;
+      }).call(utilNoAuto).each(addDropdown).style("width", function(d2) {
+        return d2.width * 100 + "%";
+      });
+      function addDropdown(d2) {
+        if (dropdowns.indexOf(d2.id) === -1) return;
+        var nearValues;
+        switch (d2.id) {
+          case "street":
+            nearValues = getNearStreets;
+            break;
+          case "place":
+            nearValues = getNearPlaces;
+            break;
+          case "street+place":
+            nearValues = () => [].concat(getNearStreets()).concat(getNearPlaces());
+            d2.isAutoStreetPlace = true;
+            d2.id = _tags["".concat(field.key, ":place")] ? "place" : "street";
+            break;
+          case "city":
+            nearValues = getNearCities;
+            break;
+          case "postcode":
+            nearValues = getNearPostcodes;
+            break;
+          default:
+            nearValues = getNearValues;
+        }
+        select_default2(this).call(
+          uiCombobox(context, "address-".concat(d2.isAutoStreetPlace ? "street-place" : d2.id)).minItems(1).caseSensitive(true).fetcher(function(typedValue, callback) {
+            typedValue = typedValue.toLowerCase();
+            callback(nearValues(d2.id).filter((v2) => v2.value.toLowerCase().indexOf(typedValue) !== -1));
+          }).on("accept", function(selected) {
+            if (d2.isAutoStreetPlace) {
+              d2.id = selected ? selected.type : "street";
+              utilTriggerEvent(select_default2(this), "change");
+            }
+          })
+        );
       }
-      function pointerup(d3_event2) {
-        if (pointerId !== (d3_event2.pointerId || "mouse"))
-          return;
-        if (d3_event2.button !== 0)
-          return;
-        context.container().selectAll(".nudge-surface").remove();
-        select_default2(window).on(".drag-bg-offset", null);
+      _wrap.selectAll("input").on("blur", change()).on("change", change());
+      _wrap.selectAll("input:not(.combobox-input)").on("input", change(true));
+      if (_tags) updateTags(_tags);
+    }
+    function address(selection2) {
+      _selection = selection2;
+      _wrap = selection2.selectAll(".form-field-input-wrap").data([0]);
+      _wrap = _wrap.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(_wrap);
+      var extent = combinedEntityExtent();
+      if (extent) {
+        var countryCode;
+        if (context.inIntro()) {
+          countryCode = _t("intro.graph.countrycode");
+        } else {
+          var center = extent.center();
+          countryCode = iso1A2Code(center);
+        }
+        if (countryCode) {
+          _countryCode = countryCode.toLowerCase();
+          updateForCountryCode();
+        }
       }
     }
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".nudge-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "nudge-container");
-      containerEnter.append("div").attr("class", "nudge-instructions").call(_t.append("background.offset"));
-      var nudgeWrapEnter = containerEnter.append("div").attr("class", "nudge-controls-wrap");
-      var nudgeEnter = nudgeWrapEnter.append("div").attr("class", "nudge-outer-rect").on(_pointerPrefix + "down", dragOffset);
-      nudgeEnter.append("div").attr("class", "nudge-inner-rect").append("input").attr("type", "text").attr("aria-label", _t("background.offset_label")).on("change", inputOffset);
-      nudgeWrapEnter.append("div").selectAll("button").data(_directions).enter().append("button").attr("title", function(d2) {
-        return _t("background.nudge.".concat(d2[0]));
-      }).attr("class", function(d2) {
-        return d2[0] + " nudge";
-      }).on("click", function(d3_event, d2) {
-        nudge(d2[1]);
-      });
-      nudgeWrapEnter.append("button").attr("title", _t("background.reset")).attr("class", "nudge-reset disabled").on("click", function(d3_event) {
-        d3_event.preventDefault();
-        resetOffset();
-      }).call(svgIcon("#iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")));
-      updateValue();
+    function change(onInput) {
+      return function() {
+        var tags = {};
+        _wrap.selectAll("input").each(function(subfield) {
+          var key = field.key + ":" + subfield.id;
+          var value = this.value;
+          if (!onInput) value = context.cleanTagValue(value);
+          if (Array.isArray(_tags[key]) && !value) return;
+          if (subfield.isAutoStreetPlace) {
+            if (subfield.id === "street") {
+              tags["".concat(field.key, ":place")] = void 0;
+            } else if (subfield.id === "place") {
+              tags["".concat(field.key, ":street")] = void 0;
+            }
+          }
+          tags[key] = value || void 0;
+        });
+        Object.keys(tags).filter((k2) => tags[k2]).forEach((k2) => _tags[k2] = tags[k2]);
+        dispatch14.call("change", this, tags, onInput);
+      };
     }
-    context.background().on("change.backgroundOffset-update", updateValue);
-    return section;
-  }
-
-  // modules/ui/sections/overlay_list.js
-  function uiSectionOverlayList(context) {
-    var section = uiSection("overlay-list", context).label(() => _t.append("background.overlays")).disclosureContent(renderDisclosureContent);
-    var _overlayList = select_default2(null);
-    function setTooltips(selection2) {
-      selection2.each(function(d2, i3, nodes) {
-        var item = select_default2(this).select("label");
-        var span = item.select("span");
-        var placement = i3 < nodes.length / 2 ? "bottom" : "top";
-        var description = d2.description();
-        var isOverflowing = span.property("clientWidth") !== span.property("scrollWidth");
-        item.call(uiTooltip().destroyAny);
-        if (description || isOverflowing) {
-          item.call(
-            uiTooltip().placement(placement).title(() => description || d2.name())
-          );
+    function updatePlaceholder(inputSelection) {
+      return inputSelection.attr("placeholder", function(subfield) {
+        if (_tags && Array.isArray(_tags[field.key + ":" + subfield.id])) {
+          return _t("inspector.multiple_values");
+        }
+        if (subfield.isAutoStreetPlace) {
+          return "".concat(getLocalPlaceholder("street"), " / ").concat(getLocalPlaceholder("place"));
         }
+        return getLocalPlaceholder(subfield.id);
       });
     }
-    function updateLayerSelections(selection2) {
-      function active(d2) {
-        return context.background().showsLayer(d2);
+    function getLocalPlaceholder(key) {
+      if (_countryCode) {
+        var localkey = key + "!" + _countryCode;
+        var tkey = addrField.hasTextForStringId("placeholders." + localkey) ? localkey : key;
+        return addrField.t("placeholders." + tkey);
       }
-      selection2.selectAll("li").classed("active", active).call(setTooltips).selectAll("input").property("checked", active);
     }
-    function chooseOverlay(d3_event, d2) {
-      d3_event.preventDefault();
-      context.background().toggleOverlayLayer(d2);
-      _overlayList.call(updateLayerSelections);
-      document.activeElement.blur();
+    function updateTags(tags) {
+      utilGetSetValue(_wrap.selectAll("input"), (subfield) => {
+        var val;
+        if (subfield.isAutoStreetPlace) {
+          const streetKey = "".concat(field.key, ":street");
+          const placeKey = "".concat(field.key, ":place");
+          if (tags[streetKey] !== void 0 || tags[placeKey] === void 0) {
+            val = tags[streetKey];
+            subfield.id = "street";
+          } else {
+            val = tags[placeKey];
+            subfield.id = "place";
+          }
+        } else {
+          val = tags["".concat(field.key, ":").concat(subfield.id)];
+        }
+        return typeof val === "string" ? val : "";
+      }).attr("title", function(subfield) {
+        var val = tags[field.key + ":" + subfield.id];
+        return val && Array.isArray(val) ? val.filter(Boolean).join("\n") : void 0;
+      }).classed("mixed", function(subfield) {
+        return Array.isArray(tags[field.key + ":" + subfield.id]);
+      }).call(updatePlaceholder);
     }
-    function drawListItems(layerList, type2, change, filter2) {
-      var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter2);
-      var layerLinks = layerList.selectAll("li").data(sources, function(d2) {
-        return d2.name();
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    address.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return address;
+    };
+    address.tags = function(tags) {
+      _tags = tags;
+      updateTags(tags);
+    };
+    address.focus = function() {
+      var node = _wrap.selectAll("input").node();
+      if (node) node.focus();
+    };
+    return utilRebind(address, dispatch14, "on");
+  }
+
+  // modules/ui/fields/directional_combo.js
+  function uiFieldDirectionalCombo(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var items = select_default2(null);
+    var wrap2 = select_default2(null);
+    var _tags;
+    var _combos = {};
+    if (field.type === "cycleway") {
+      field = {
+        ...field,
+        key: field.keys[0],
+        keys: field.keys.slice(1)
+      };
+    }
+    function directionalCombo(selection2) {
+      function stripcolon(s2) {
+        return s2.replace(":", "");
+      }
+      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var div = wrap2.selectAll("ul").data([0]);
+      div = div.enter().append("ul").attr("class", "rows rows-table").merge(div);
+      items = div.selectAll("li").data(field.keys);
+      var enter = items.enter().append("li").attr("class", function(d2) {
+        return "labeled-input preset-directionalcombo-" + stripcolon(d2);
       });
-      layerLinks.exit().remove();
-      var enter = layerLinks.enter().append("li");
-      var label = enter.append("label");
-      label.append("input").attr("type", type2).attr("name", "layers").on("change", change);
-      label.append("span").each(function(d2) {
-        d2.label()(select_default2(this));
+      enter.append("div").attr("class", "label preset-label-directionalcombo").attr("for", function(d2) {
+        return "preset-input-directionalcombo-" + stripcolon(d2);
+      }).html(function(d2) {
+        return field.t.html("types." + d2);
       });
-      layerList.selectAll("li").sort(sortSources);
-      layerList.call(updateLayerSelections);
-      function sortSources(a2, b2) {
-        return a2.best() && !b2.best() ? -1 : b2.best() && !a2.best() ? 1 : descending(a2.area(), b2.area()) || ascending(a2.name(), b2.name()) || 0;
-      }
+      enter.append("div").attr("class", "preset-input-directionalcombo-wrap form-field-input-wrap").each(function(key) {
+        const subField = {
+          ...field,
+          type: "combo",
+          key
+        };
+        const combo = uiFieldCombo(subField, context);
+        combo.on("change", (t2) => change(key, t2[key]));
+        _combos[key] = combo;
+        select_default2(this).call(combo);
+      });
+      items = items.merge(enter);
+      wrap2.selectAll(".preset-input-directionalcombo").on("change", change).on("blur", change);
     }
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".layer-overlay-list").data([0]);
-      _overlayList = container.enter().append("ul").attr("class", "layer-list layer-overlay-list").attr("dir", "auto").merge(container);
-      _overlayList.call(drawListItems, "checkbox", chooseOverlay, function(d2) {
-        return !d2.isHidden() && d2.overlay;
+    function change(key, newValue) {
+      const commonKey = field.key;
+      const otherKey = key === field.keys[0] ? field.keys[1] : field.keys[0];
+      dispatch14.call("change", this, (tags) => {
+        const otherValue = tags[otherKey] || tags[commonKey];
+        if (newValue === otherValue) {
+          tags[commonKey] = newValue;
+          delete tags[key];
+          delete tags[otherKey];
+        } else {
+          tags[key] = newValue;
+          delete tags[commonKey];
+          tags[otherKey] = otherValue;
+        }
+        return tags;
       });
     }
-    context.map().on(
-      "move.overlay_list",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
+    directionalCombo.tags = function(tags) {
+      _tags = tags;
+      const commonKey = field.key;
+      for (let key in _combos) {
+        const uniqueValues = [...new Set([].concat(_tags[commonKey]).concat(_tags[key]).filter(Boolean))];
+        _combos[key].tags({ [key]: uniqueValues.length > 1 ? uniqueValues : uniqueValues[0] });
+      }
+    };
+    directionalCombo.focus = function() {
+      var node = wrap2.selectAll("input").node();
+      if (node) node.focus();
+    };
+    return utilRebind(directionalCombo, dispatch14, "on");
   }
 
-  // modules/ui/panes/background.js
-  function uiPaneBackground(context) {
-    var backgroundPane = uiPane("background", context).key(_t("background.key")).label(_t.append("background.title")).description(_t.append("background.description")).iconName("iD-icon-layers").sections([
-      uiSectionBackgroundList(context),
-      uiSectionOverlayList(context),
-      uiSectionBackgroundDisplayOptions(context),
-      uiSectionBackgroundOffset(context)
-    ]);
-    return backgroundPane;
+  // modules/ui/fields/lanes.js
+  function uiFieldLanes(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var LANE_WIDTH = 40;
+    var LANE_HEIGHT = 200;
+    var _entityIDs = [];
+    function lanes(selection2) {
+      var lanesData = context.entity(_entityIDs[0]).lanes();
+      if (!context.container().select(".inspector-wrap.inspector-hidden").empty() || !selection2.node().parentNode) {
+        selection2.call(lanes.off);
+        return;
+      }
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var surface = wrap2.selectAll(".surface").data([0]);
+      var d2 = utilGetDimensions(wrap2);
+      var freeSpace = d2[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
+      surface = surface.enter().append("svg").attr("width", d2[0]).attr("height", 300).attr("class", "surface").merge(surface);
+      var lanesSelection = surface.selectAll(".lanes").data([0]);
+      lanesSelection = lanesSelection.enter().append("g").attr("class", "lanes").merge(lanesSelection);
+      lanesSelection.attr("transform", function() {
+        return "translate(" + freeSpace / 2 + ", 0)";
+      });
+      var lane = lanesSelection.selectAll(".lane").data(lanesData.lanes);
+      lane.exit().remove();
+      var enter = lane.enter().append("g").attr("class", "lane");
+      enter.append("g").append("rect").attr("y", 50).attr("width", LANE_WIDTH).attr("height", LANE_HEIGHT);
+      enter.append("g").attr("class", "forward").append("text").attr("y", 40).attr("x", 14).text("\u25B2");
+      enter.append("g").attr("class", "bothways").append("text").attr("y", 40).attr("x", 14).text("\u25B2\u25BC");
+      enter.append("g").attr("class", "backward").append("text").attr("y", 40).attr("x", 14).text("\u25BC");
+      lane = lane.merge(enter);
+      lane.attr("transform", function(d4) {
+        return "translate(" + LANE_WIDTH * d4.index * 1.5 + ", 0)";
+      });
+      lane.select(".forward").style("visibility", function(d4) {
+        return d4.direction === "forward" ? "visible" : "hidden";
+      });
+      lane.select(".bothways").style("visibility", function(d4) {
+        return d4.direction === "bothways" ? "visible" : "hidden";
+      });
+      lane.select(".backward").style("visibility", function(d4) {
+        return d4.direction === "backward" ? "visible" : "hidden";
+      });
+    }
+    lanes.entityIDs = function(val) {
+      _entityIDs = val;
+    };
+    lanes.tags = function() {
+    };
+    lanes.focus = function() {
+    };
+    lanes.off = function() {
+    };
+    return utilRebind(lanes, dispatch14, "on");
   }
+  uiFieldLanes.supportsMultiselection = false;
 
-  // modules/ui/panes/help.js
-  function uiPaneHelp(context) {
-    var docKeys = [
-      ["help", [
-        "welcome",
-        "open_data_h",
-        "open_data",
-        "before_start_h",
-        "before_start",
-        "open_source_h",
-        "open_source",
-        "open_source_attribution",
-        "open_source_help"
-      ]],
-      ["overview", [
-        "navigation_h",
-        "navigation_drag",
-        "navigation_zoom",
-        "features_h",
-        "features",
-        "nodes_ways"
-      ]],
-      ["editing", [
-        "select_h",
-        "select_left_click",
-        "select_right_click",
-        "select_space",
-        "multiselect_h",
-        "multiselect",
-        "multiselect_shift_click",
-        "multiselect_lasso",
-        "undo_redo_h",
-        "undo_redo",
-        "save_h",
-        "save",
-        "save_validation",
-        "upload_h",
-        "upload",
-        "backups_h",
-        "backups",
-        "keyboard_h",
-        "keyboard"
-      ]],
-      ["feature_editor", [
-        "intro",
-        "definitions",
-        "type_h",
-        "type",
-        "type_picker",
-        "fields_h",
-        "fields_all_fields",
-        "fields_example",
-        "fields_add_field",
-        "tags_h",
-        "tags_all_tags",
-        "tags_resources"
-      ]],
-      ["points", [
-        "intro",
-        "add_point_h",
-        "add_point",
-        "add_point_finish",
-        "move_point_h",
-        "move_point",
-        "delete_point_h",
-        "delete_point",
-        "delete_point_command"
-      ]],
-      ["lines", [
-        "intro",
-        "add_line_h",
-        "add_line",
-        "add_line_draw",
-        "add_line_continue",
-        "add_line_finish",
-        "modify_line_h",
-        "modify_line_dragnode",
-        "modify_line_addnode",
-        "connect_line_h",
-        "connect_line",
-        "connect_line_display",
-        "connect_line_drag",
-        "connect_line_tag",
-        "disconnect_line_h",
-        "disconnect_line_command",
-        "move_line_h",
-        "move_line_command",
-        "move_line_connected",
-        "delete_line_h",
-        "delete_line",
-        "delete_line_command"
-      ]],
-      ["areas", [
-        "intro",
-        "point_or_area_h",
-        "point_or_area",
-        "add_area_h",
-        "add_area_command",
-        "add_area_draw",
-        "add_area_continue",
-        "add_area_finish",
-        "square_area_h",
-        "square_area_command",
-        "modify_area_h",
-        "modify_area_dragnode",
-        "modify_area_addnode",
-        "delete_area_h",
-        "delete_area",
-        "delete_area_command"
-      ]],
-      ["relations", [
-        "intro",
-        "edit_relation_h",
-        "edit_relation",
-        "edit_relation_add",
-        "edit_relation_delete",
-        "maintain_relation_h",
-        "maintain_relation",
-        "relation_types_h",
-        "multipolygon_h",
-        "multipolygon",
-        "multipolygon_create",
-        "multipolygon_merge",
-        "turn_restriction_h",
-        "turn_restriction",
-        "turn_restriction_field",
-        "turn_restriction_editing",
-        "route_h",
-        "route",
-        "route_add",
-        "boundary_h",
-        "boundary",
-        "boundary_add"
-      ]],
-      ["operations", [
-        "intro",
-        "intro_2",
-        "straighten",
-        "orthogonalize",
-        "circularize",
-        "move",
-        "rotate",
-        "reflect",
-        "continue",
-        "reverse",
-        "disconnect",
-        "split",
-        "extract",
-        "merge",
-        "delete",
-        "downgrade",
-        "copy_paste"
-      ]],
-      ["notes", [
-        "intro",
-        "add_note_h",
-        "add_note",
-        "place_note",
-        "move_note",
-        "update_note_h",
-        "update_note",
-        "save_note_h",
-        "save_note"
-      ]],
-      ["imagery", [
-        "intro",
-        "sources_h",
-        "choosing",
-        "sources",
-        "offsets_h",
-        "offset",
-        "offset_change"
-      ]],
-      ["streetlevel", [
-        "intro",
-        "using_h",
-        "using",
-        "photos",
-        "viewer"
-      ]],
-      ["gps", [
-        "intro",
-        "survey",
-        "using_h",
-        "using",
-        "tracing",
-        "upload"
-      ]],
-      ["qa", [
-        "intro",
-        "tools_h",
-        "tools",
-        "issues_h",
-        "issues"
-      ]]
-    ];
-    var headings = {
-      "help.help.open_data_h": 3,
-      "help.help.before_start_h": 3,
-      "help.help.open_source_h": 3,
-      "help.overview.navigation_h": 3,
-      "help.overview.features_h": 3,
-      "help.editing.select_h": 3,
-      "help.editing.multiselect_h": 3,
-      "help.editing.undo_redo_h": 3,
-      "help.editing.save_h": 3,
-      "help.editing.upload_h": 3,
-      "help.editing.backups_h": 3,
-      "help.editing.keyboard_h": 3,
-      "help.feature_editor.type_h": 3,
-      "help.feature_editor.fields_h": 3,
-      "help.feature_editor.tags_h": 3,
-      "help.points.add_point_h": 3,
-      "help.points.move_point_h": 3,
-      "help.points.delete_point_h": 3,
-      "help.lines.add_line_h": 3,
-      "help.lines.modify_line_h": 3,
-      "help.lines.connect_line_h": 3,
-      "help.lines.disconnect_line_h": 3,
-      "help.lines.move_line_h": 3,
-      "help.lines.delete_line_h": 3,
-      "help.areas.point_or_area_h": 3,
-      "help.areas.add_area_h": 3,
-      "help.areas.square_area_h": 3,
-      "help.areas.modify_area_h": 3,
-      "help.areas.delete_area_h": 3,
-      "help.relations.edit_relation_h": 3,
-      "help.relations.maintain_relation_h": 3,
-      "help.relations.relation_types_h": 2,
-      "help.relations.multipolygon_h": 3,
-      "help.relations.turn_restriction_h": 3,
-      "help.relations.route_h": 3,
-      "help.relations.boundary_h": 3,
-      "help.notes.add_note_h": 3,
-      "help.notes.update_note_h": 3,
-      "help.notes.save_note_h": 3,
-      "help.imagery.sources_h": 3,
-      "help.imagery.offsets_h": 3,
-      "help.streetlevel.using_h": 3,
-      "help.gps.using_h": 3,
-      "help.qa.tools_h": 3,
-      "help.qa.issues_h": 3
-    };
-    var docs = docKeys.map(function(key) {
-      var helpkey = "help." + key[0];
-      var helpPaneReplacements = { version: context.version };
-      var text = key[1].reduce(function(all, part) {
-        var subkey = helpkey + "." + part;
-        var depth = headings[subkey];
-        var hhh = depth ? Array(depth + 1).join("#") + " " : "";
-        return all + hhh + helpHtml(subkey, helpPaneReplacements) + "\n\n";
-      }, "");
-      return {
-        title: _t.html(helpkey + ".title"),
-        content: marked(text.trim()).replace(/<code>/g, "<kbd>").replace(/<\/code>/g, "</kbd>")
-      };
+  // modules/ui/fields/localized.js
+  var _languagesArray = [];
+  var LANGUAGE_SUFFIX_REGEX = /^(.*):([a-z]{2,3}(?:-[A-Z][a-z]{3})?(?:-[A-Z]{2})?)$/;
+  function uiFieldLocalized(field, context) {
+    var dispatch14 = dispatch_default("change", "input");
+    var wikipedia = services.wikipedia;
+    var input = select_default2(null);
+    var localizedInputs = select_default2(null);
+    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
+    var _countryCode;
+    var _tags;
+    _mainFileFetcher.get("languages").then(loadLanguagesArray).catch(function() {
     });
-    var helpPane = uiPane("help", context).key(_t("help.key")).label(_t.append("help.title")).description(_t.append("help.title")).iconName("iD-icon-help");
-    helpPane.renderContent = function(content) {
-      function clickHelp(d2, i3) {
-        var rtl = _mainLocalizer.textDirection() === "rtl";
-        content.property("scrollTop", 0);
-        helpPane.selection().select(".pane-heading h2").html(d2.title);
-        body.html(d2.content);
-        body.selectAll("a").attr("target", "_blank");
-        menuItems.classed("selected", function(m2) {
-          return m2.title === d2.title;
+    var _territoryLanguages = {};
+    _mainFileFetcher.get("territory_languages").then(function(d2) {
+      _territoryLanguages = d2;
+    }).catch(function() {
+    });
+    var langCombo = uiCombobox(context, "localized-lang").fetcher(fetchLanguages).minItems(0);
+    var _selection = select_default2(null);
+    var _multilingual = [];
+    var _buttonTip = uiTooltip().title(() => _t.append("translate.translate")).placement("left");
+    var _wikiTitles;
+    var _entityIDs = [];
+    function loadLanguagesArray(dataLanguages) {
+      if (_languagesArray.length !== 0) return;
+      var replacements = {
+        sr: "sr-Cyrl",
+        // in OSM, `sr` implies Cyrillic
+        "sr-Cyrl": false
+        // `sr-Cyrl` isn't used in OSM
+      };
+      for (var code in dataLanguages) {
+        if (replacements[code] === false) continue;
+        var metaCode = code;
+        if (replacements[code]) metaCode = replacements[code];
+        _languagesArray.push({
+          localName: _mainLocalizer.languageName(metaCode, { localOnly: true }),
+          nativeName: dataLanguages[metaCode].nativeName,
+          code,
+          label: _mainLocalizer.languageName(metaCode)
+        });
+      }
+    }
+    function calcLocked() {
+      var isLocked = field.id === "name" && _entityIDs.length && _entityIDs.some(function(entityID) {
+        var entity = context.graph().hasEntity(entityID);
+        if (!entity) return false;
+        if (entity.tags.wikidata) return true;
+        if (entity.tags["name:etymology:wikidata"]) return true;
+        var preset = _mainPresetIndex.match(entity, context.graph());
+        if (preset) {
+          var isSuggestion = preset.suggestion;
+          var fields = preset.fields(entity.extent(context.graph()).center());
+          var showsBrandField = fields.some(function(d2) {
+            return d2.id === "brand";
+          });
+          var showsOperatorField = fields.some(function(d2) {
+            return d2.id === "operator";
+          });
+          var setsName = preset.addTags.name;
+          var setsBrandWikidata = preset.addTags["brand:wikidata"];
+          var setsOperatorWikidata = preset.addTags["operator:wikidata"];
+          return isSuggestion && setsName && (setsBrandWikidata && !showsBrandField || setsOperatorWikidata && !showsOperatorField);
+        }
+        return false;
+      });
+      field.locked(isLocked);
+    }
+    function calcMultilingual(tags) {
+      var existingLangsOrdered = _multilingual.map(function(item2) {
+        return item2.lang;
+      });
+      var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
+      for (var k2 in tags) {
+        var m2 = k2.match(LANGUAGE_SUFFIX_REGEX);
+        if (m2 && m2[1] === field.key && m2[2]) {
+          var item = { lang: m2[2], value: tags[k2] };
+          if (existingLangs.has(item.lang)) {
+            _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
+            existingLangs.delete(item.lang);
+          } else {
+            _multilingual.push(item);
+          }
+        }
+      }
+      _multilingual.forEach(function(item2) {
+        if (item2.lang && existingLangs.has(item2.lang)) {
+          item2.value = "";
+        }
+      });
+    }
+    function localized(selection2) {
+      _selection = selection2;
+      calcLocked();
+      var isLocked = field.locked();
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      input = wrap2.selectAll(".localized-main").data([0]);
+      input = input.enter().append("input").attr("type", "text").attr("id", field.domId).attr("class", "localized-main").call(utilNoAuto).merge(input);
+      input.classed("disabled", !!isLocked).attr("readonly", isLocked || null).on("input", change(true)).on("blur", change()).on("change", change());
+      wrap2.call(_lengthIndicator);
+      var translateButton = wrap2.selectAll(".localized-add").data([0]);
+      translateButton = translateButton.enter().append("button").attr("class", "localized-add form-field-button").attr("aria-label", _t("icons.plus")).call(svgIcon("#iD-icon-plus")).merge(translateButton);
+      translateButton.classed("disabled", !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on("click", addNew);
+      if (_tags && !_multilingual.length) {
+        calcMultilingual(_tags);
+      }
+      localizedInputs = selection2.selectAll(".localized-multilingual").data([0]);
+      localizedInputs = localizedInputs.enter().append("div").attr("class", "localized-multilingual").merge(localizedInputs);
+      localizedInputs.call(renderMultilingual);
+      localizedInputs.selectAll("button, input").classed("disabled", !!isLocked).attr("readonly", isLocked || null);
+      selection2.selectAll(".combobox-caret").classed("nope", true);
+      function addNew(d3_event) {
+        d3_event.preventDefault();
+        if (field.locked()) return;
+        var defaultLang = _mainLocalizer.languageCode().toLowerCase();
+        var langExists = _multilingual.find(function(datum2) {
+          return datum2.lang === defaultLang;
+        });
+        var isLangEn = defaultLang.indexOf("en") > -1;
+        if (isLangEn || langExists) {
+          defaultLang = "";
+          langExists = _multilingual.find(function(datum2) {
+            return datum2.lang === defaultLang;
+          });
+        }
+        if (!langExists) {
+          _multilingual.unshift({ lang: defaultLang, value: "" });
+          localizedInputs.call(renderMultilingual);
+        }
+      }
+      function change(onInput) {
+        return function(d3_event) {
+          if (field.locked()) {
+            d3_event.preventDefault();
+            return;
+          }
+          var val = utilGetSetValue(select_default2(this));
+          if (!onInput) val = context.cleanTagValue(val);
+          if (!val && Array.isArray(_tags[field.key])) return;
+          var t2 = {};
+          t2[field.key] = val || void 0;
+          dispatch14.call("change", this, t2, onInput);
+        };
+      }
+    }
+    function key(lang) {
+      return field.key + ":" + lang;
+    }
+    function changeLang(d3_event, d2) {
+      var tags = {};
+      var lang = utilGetSetValue(select_default2(this)).toLowerCase();
+      var language = _languagesArray.find(function(d4) {
+        return d4.label.toLowerCase() === lang || d4.localName && d4.localName.toLowerCase() === lang || d4.nativeName && d4.nativeName.toLowerCase() === lang;
+      });
+      if (language) lang = language.code;
+      if (d2.lang && d2.lang !== lang) {
+        tags[key(d2.lang)] = void 0;
+      }
+      var newKey = lang && context.cleanTagKey(key(lang));
+      var value = utilGetSetValue(select_default2(this.parentNode).selectAll(".localized-value"));
+      if (newKey && value) {
+        tags[newKey] = value;
+      } else if (newKey && _wikiTitles && _wikiTitles[d2.lang]) {
+        tags[newKey] = _wikiTitles[d2.lang];
+      }
+      d2.lang = lang;
+      dispatch14.call("change", this, tags);
+    }
+    function changeValue(d3_event, d2) {
+      if (!d2.lang) return;
+      var value = context.cleanTagValue(utilGetSetValue(select_default2(this))) || void 0;
+      if (!value && Array.isArray(d2.value)) return;
+      var t2 = {};
+      t2[key(d2.lang)] = value;
+      d2.value = value;
+      dispatch14.call("change", this, t2);
+    }
+    function fetchLanguages(value, cb) {
+      var v2 = value.toLowerCase();
+      var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
+      if (_countryCode && _territoryLanguages[_countryCode]) {
+        langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
+      }
+      var langItems = [];
+      langCodes.forEach(function(code) {
+        var langItem = _languagesArray.find(function(item) {
+          return item.code === code;
         });
-        nav.html("");
-        if (rtl) {
-          nav.call(drawNext).call(drawPrevious);
-        } else {
-          nav.call(drawPrevious).call(drawNext);
-        }
-        function drawNext(selection2) {
-          if (i3 < docs.length - 1) {
-            var nextLink = selection2.append("a").attr("href", "#").attr("class", "next").on("click", function(d3_event) {
-              d3_event.preventDefault();
-              clickHelp(docs[i3 + 1], i3 + 1);
-            });
-            nextLink.append("span").html(docs[i3 + 1].title).call(svgIcon(rtl ? "#iD-icon-backward" : "#iD-icon-forward", "inline"));
+        if (langItem) langItems.push(langItem);
+      });
+      langItems = utilArrayUniq(langItems.concat(_languagesArray));
+      cb(langItems.filter(function(d2) {
+        return d2.label.toLowerCase().indexOf(v2) >= 0 || d2.localName && d2.localName.toLowerCase().indexOf(v2) >= 0 || d2.nativeName && d2.nativeName.toLowerCase().indexOf(v2) >= 0 || d2.code.toLowerCase().indexOf(v2) >= 0;
+      }).map(function(d2) {
+        return { value: d2.label };
+      }));
+    }
+    function renderMultilingual(selection2) {
+      var entries = selection2.selectAll("div.entry").data(_multilingual, function(d2) {
+        return d2.lang;
+      });
+      entries.exit().style("top", "0").style("max-height", "240px").transition().duration(200).style("opacity", "0").style("max-height", "0px").remove();
+      var entriesEnter = entries.enter().append("div").attr("class", "entry").each(function(_2, index) {
+        var wrap2 = select_default2(this);
+        var domId = utilUniqueDomId(index);
+        var label = wrap2.append("label").attr("class", "field-label").attr("for", domId);
+        var text = label.append("span").attr("class", "label-text");
+        text.append("span").attr("class", "label-textvalue").call(_t.append("translate.localized_translation_label"));
+        text.append("span").attr("class", "label-textannotation");
+        label.append("button").attr("class", "remove-icon-multilingual").attr("title", _t("icons.remove")).on("click", function(d3_event, d2) {
+          if (field.locked()) return;
+          d3_event.preventDefault();
+          _multilingual.splice(_multilingual.indexOf(d2), 1);
+          var langKey = d2.lang && key(d2.lang);
+          if (langKey && langKey in _tags) {
+            delete _tags[langKey];
+            var t2 = {};
+            t2[langKey] = void 0;
+            dispatch14.call("change", this, t2);
+            return;
           }
+          renderMultilingual(selection2);
+        }).call(svgIcon("#iD-operation-delete"));
+        wrap2.append("input").attr("class", "localized-lang").attr("id", domId).attr("type", "text").attr("placeholder", _t("translate.localized_translation_language")).on("blur", changeLang).on("change", changeLang).call(langCombo);
+        wrap2.append("input").attr("type", "text").attr("class", "localized-value").on("blur", changeValue).on("change", changeValue);
+      });
+      entriesEnter.style("margin-top", "0px").style("max-height", "0px").style("opacity", "0").transition().duration(200).style("margin-top", "10px").style("max-height", "240px").style("opacity", "1").on("end", function() {
+        select_default2(this).style("max-height", "").style("overflow", "visible");
+      });
+      entries = entries.merge(entriesEnter);
+      entries.order();
+      entries.classed("present", true);
+      utilGetSetValue(entries.select(".localized-lang"), function(d2) {
+        var langItem = _languagesArray.find(function(item) {
+          return item.code === d2.lang;
+        });
+        if (langItem) return langItem.label;
+        return d2.lang;
+      });
+      utilGetSetValue(entries.select(".localized-value"), function(d2) {
+        return typeof d2.value === "string" ? d2.value : "";
+      }).attr("title", function(d2) {
+        return Array.isArray(d2.value) ? d2.value.filter(Boolean).join("\n") : null;
+      }).attr("placeholder", function(d2) {
+        return Array.isArray(d2.value) ? _t("inspector.multiple_values") : _t("translate.localized_translation_name");
+      }).classed("mixed", function(d2) {
+        return Array.isArray(d2.value);
+      });
+    }
+    localized.tags = function(tags) {
+      _tags = tags;
+      if (typeof tags.wikipedia === "string" && !_wikiTitles) {
+        _wikiTitles = {};
+        var wm = tags.wikipedia.match(/([^:]+):(.+)/);
+        if (wm && wm[0] && wm[1]) {
+          wikipedia.translations(wm[1], wm[2], function(err, d2) {
+            if (err || !d2) return;
+            _wikiTitles = d2;
+          });
         }
-        function drawPrevious(selection2) {
-          if (i3 > 0) {
-            var prevLink = selection2.append("a").attr("href", "#").attr("class", "previous").on("click", function(d3_event) {
-              d3_event.preventDefault();
-              clickHelp(docs[i3 - 1], i3 - 1);
-            });
-            prevLink.call(svgIcon(rtl ? "#iD-icon-forward" : "#iD-icon-backward", "inline")).append("span").html(docs[i3 - 1].title);
-          }
+      }
+      var isMixed = Array.isArray(tags[field.key]);
+      utilGetSetValue(input, typeof tags[field.key] === "string" ? tags[field.key] : "").attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder()).classed("mixed", isMixed);
+      calcMultilingual(tags);
+      _selection.call(localized);
+      if (!isMixed) {
+        _lengthIndicator.update(tags[field.key]);
+      }
+    };
+    localized.focus = function() {
+      input.node().focus();
+    };
+    localized.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      _multilingual = [];
+      loadCountryCode();
+      return localized;
+    };
+    function loadCountryCode() {
+      var extent = combinedEntityExtent();
+      var countryCode = extent && iso1A2Code(extent.center());
+      _countryCode = countryCode && countryCode.toLowerCase();
+    }
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    return utilRebind(localized, dispatch14, "on");
+  }
+
+  // modules/ui/fields/roadheight.js
+  function uiFieldRoadheight(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var primaryUnitInput = select_default2(null);
+    var primaryInput = select_default2(null);
+    var secondaryInput = select_default2(null);
+    var secondaryUnitInput = select_default2(null);
+    var _entityIDs = [];
+    var _tags;
+    var _isImperial;
+    var formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
+    var parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
+    var primaryUnits = [
+      {
+        value: "m",
+        title: _t("inspector.roadheight.meter")
+      },
+      {
+        value: "ft",
+        title: _t("inspector.roadheight.foot")
+      }
+    ];
+    var unitCombo = uiCombobox(context, "roadheight-unit").data(primaryUnits);
+    function roadheight(selection2) {
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      primaryInput = wrap2.selectAll("input.roadheight-number").data([0]);
+      primaryInput = primaryInput.enter().append("input").attr("type", "text").attr("class", "roadheight-number").attr("id", field.domId).call(utilNoAuto).merge(primaryInput);
+      primaryInput.on("change", change).on("blur", change);
+      var loc = combinedEntityExtent().center();
+      _isImperial = roadHeightUnit(loc) === "ft";
+      primaryUnitInput = wrap2.selectAll("input.roadheight-unit").data([0]);
+      primaryUnitInput = primaryUnitInput.enter().append("input").attr("type", "text").attr("class", "roadheight-unit").call(unitCombo).merge(primaryUnitInput);
+      primaryUnitInput.on("blur", changeUnits).on("change", changeUnits);
+      secondaryInput = wrap2.selectAll("input.roadheight-secondary-number").data([0]);
+      secondaryInput = secondaryInput.enter().append("input").attr("type", "text").attr("class", "roadheight-secondary-number").call(utilNoAuto).merge(secondaryInput);
+      secondaryInput.on("change", change).on("blur", change);
+      secondaryUnitInput = wrap2.selectAll("input.roadheight-secondary-unit").data([0]);
+      secondaryUnitInput = secondaryUnitInput.enter().append("input").attr("type", "text").call(utilNoAuto).classed("disabled", true).classed("roadheight-secondary-unit", true).attr("readonly", "readonly").merge(secondaryUnitInput);
+      function changeUnits() {
+        var primaryUnit = utilGetSetValue(primaryUnitInput);
+        if (primaryUnit === "m") {
+          _isImperial = false;
+        } else if (primaryUnit === "ft") {
+          _isImperial = true;
         }
+        utilGetSetValue(primaryUnitInput, _isImperial ? "ft" : "m");
+        setUnitSuggestions();
+        change();
       }
-      function clickWalkthrough(d3_event) {
-        d3_event.preventDefault();
-        if (context.inIntro())
-          return;
-        context.container().call(uiIntro(context));
-        context.ui().togglePanes();
+    }
+    function setUnitSuggestions() {
+      utilGetSetValue(primaryUnitInput, _isImperial ? "ft" : "m");
+    }
+    function change() {
+      var tag2 = {};
+      var primaryValue = utilGetSetValue(primaryInput).trim();
+      var secondaryValue = utilGetSetValue(secondaryInput).trim();
+      if (!primaryValue && !secondaryValue && Array.isArray(_tags[field.key])) return;
+      if (!primaryValue && !secondaryValue) {
+        tag2[field.key] = void 0;
+      } else {
+        var rawPrimaryValue = likelyRawNumberFormat.test(primaryValue) ? parseFloat(primaryValue) : parseLocaleFloat(primaryValue);
+        if (isNaN(rawPrimaryValue)) rawPrimaryValue = primaryValue;
+        var rawSecondaryValue = likelyRawNumberFormat.test(secondaryValue) ? parseFloat(secondaryValue) : parseLocaleFloat(secondaryValue);
+        if (isNaN(rawSecondaryValue)) rawSecondaryValue = secondaryValue;
+        if (isNaN(rawPrimaryValue) || isNaN(rawSecondaryValue) || !_isImperial) {
+          tag2[field.key] = context.cleanTagValue(rawPrimaryValue);
+        } else {
+          if (rawPrimaryValue !== "") {
+            rawPrimaryValue = rawPrimaryValue + "'";
+          }
+          if (rawSecondaryValue !== "") {
+            rawSecondaryValue = rawSecondaryValue + '"';
+          }
+          tag2[field.key] = context.cleanTagValue(rawPrimaryValue + rawSecondaryValue);
+        }
       }
-      function clickShortcuts(d3_event) {
-        d3_event.preventDefault();
-        context.container().call(context.ui().shortcuts, true);
+      dispatch14.call("change", this, tag2);
+    }
+    roadheight.tags = function(tags) {
+      _tags = tags;
+      var primaryValue = tags[field.key];
+      var secondaryValue;
+      var isMixed = Array.isArray(primaryValue);
+      if (!isMixed) {
+        if (primaryValue && (primaryValue.indexOf("'") >= 0 || primaryValue.indexOf('"') >= 0)) {
+          secondaryValue = primaryValue.match(/(-?[\d.]+)"/);
+          if (secondaryValue !== null) {
+            secondaryValue = formatFloat(parseFloat(secondaryValue[1]));
+          }
+          primaryValue = primaryValue.match(/(-?[\d.]+)'/);
+          if (primaryValue !== null) {
+            primaryValue = formatFloat(parseFloat(primaryValue[1]));
+          }
+          _isImperial = true;
+        } else if (primaryValue) {
+          var rawValue = primaryValue;
+          primaryValue = parseFloat(rawValue);
+          if (isNaN(primaryValue)) {
+            primaryValue = rawValue;
+          } else {
+            primaryValue = formatFloat(primaryValue);
+          }
+          _isImperial = false;
+        }
       }
-      var toc = content.append("ul").attr("class", "toc");
-      var menuItems = toc.selectAll("li").data(docs).enter().append("li").append("a").attr("role", "button").attr("href", "#").html(function(d2) {
-        return d2.title;
-      }).on("click", function(d3_event, d2) {
-        d3_event.preventDefault();
-        clickHelp(d2, docs.indexOf(d2));
-      });
-      var shortcuts = toc.append("li").attr("class", "shortcuts").call(
-        uiTooltip().title(() => _t.append("shortcuts.tooltip")).keys(["?"]).placement("top")
-      ).append("a").attr("href", "#").on("click", clickShortcuts);
-      shortcuts.append("div").call(_t.append("shortcuts.title"));
-      var walkthrough = toc.append("li").attr("class", "walkthrough").append("a").attr("href", "#").on("click", clickWalkthrough);
-      walkthrough.append("svg").attr("class", "logo logo-walkthrough").append("use").attr("xlink:href", "#iD-logo-walkthrough");
-      walkthrough.append("div").call(_t.append("splash.walkthrough"));
-      var helpContent = content.append("div").attr("class", "left-content");
-      var body = helpContent.append("div").attr("class", "body");
-      var nav = helpContent.append("div").attr("class", "nav");
-      clickHelp(docs[0], 0);
+      setUnitSuggestions();
+      var inchesPlaceholder = formatFloat(0);
+      utilGetSetValue(primaryInput, typeof primaryValue === "string" ? primaryValue : "").attr("title", isMixed ? primaryValue.filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : _t("inspector.unknown")).classed("mixed", isMixed);
+      utilGetSetValue(secondaryInput, typeof secondaryValue === "string" ? secondaryValue : "").attr("placeholder", isMixed ? _t("inspector.multiple_values") : _isImperial ? inchesPlaceholder : null).classed("mixed", isMixed).classed("disabled", !_isImperial).attr("readonly", _isImperial ? null : "readonly");
+      secondaryUnitInput.attr("value", _isImperial ? _t("inspector.roadheight.inch") : null);
     };
-    return helpPane;
+    roadheight.focus = function() {
+      primaryInput.node().focus();
+    };
+    roadheight.entityIDs = function(val) {
+      _entityIDs = val;
+    };
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    return utilRebind(roadheight, dispatch14, "on");
   }
 
-  // modules/ui/sections/validation_issues.js
-  function uiSectionValidationIssues(id2, severity, context) {
-    var _issues = [];
-    var section = uiSection(id2, context).label(function() {
-      if (!_issues)
-        return "";
-      var issueCountText = _issues.length > 1e3 ? "1000+" : String(_issues.length);
-      return _t.append("inspector.title_count", { title: _t("issues." + severity + "s.list_title"), count: issueCountText });
-    }).disclosureContent(renderDisclosureContent).shouldDisplay(function() {
-      return _issues && _issues.length;
-    });
-    function getOptions() {
+  // modules/ui/fields/roadspeed.js
+  function uiFieldRoadspeed(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var unitInput = select_default2(null);
+    var input = select_default2(null);
+    var _entityIDs = [];
+    var _tags;
+    var _isImperial;
+    var formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
+    var parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
+    var speedCombo = uiCombobox(context, "roadspeed");
+    var unitCombo = uiCombobox(context, "roadspeed-unit").data(["km/h", "mph"].map(comboValues));
+    var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
+    var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
+    function roadspeed(selection2) {
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      input = wrap2.selectAll("input.roadspeed-number").data([0]);
+      input = input.enter().append("input").attr("type", "text").attr("class", "roadspeed-number").attr("id", field.domId).call(utilNoAuto).call(speedCombo).merge(input);
+      input.on("change", change).on("blur", change);
+      var loc = combinedEntityExtent().center();
+      _isImperial = roadSpeedUnit(loc) === "mph";
+      unitInput = wrap2.selectAll("input.roadspeed-unit").data([0]);
+      unitInput = unitInput.enter().append("input").attr("type", "text").attr("class", "roadspeed-unit").attr("aria-label", _t("inspector.speed_unit")).call(unitCombo).merge(unitInput);
+      unitInput.on("blur", changeUnits).on("change", changeUnits);
+      function changeUnits() {
+        var unit2 = utilGetSetValue(unitInput);
+        if (unit2 === "km/h") {
+          _isImperial = false;
+        } else if (unit2 === "mph") {
+          _isImperial = true;
+        }
+        utilGetSetValue(unitInput, _isImperial ? "mph" : "km/h");
+        setUnitSuggestions();
+        change();
+      }
+    }
+    function setUnitSuggestions() {
+      speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
+      utilGetSetValue(unitInput, _isImperial ? "mph" : "km/h");
+    }
+    function comboValues(d2) {
       return {
-        what: corePreferences("validate-what") || "edited",
-        where: corePreferences("validate-where") || "all"
+        value: formatFloat(d2),
+        title: formatFloat(d2)
       };
     }
-    function reloadIssues() {
-      _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
+    function change() {
+      var tag2 = {};
+      var value = utilGetSetValue(input).trim();
+      if (!value && Array.isArray(_tags[field.key])) return;
+      if (!value) {
+        tag2[field.key] = void 0;
+      } else {
+        var rawValue = likelyRawNumberFormat.test(value) ? parseFloat(value) : parseLocaleFloat(value);
+        if (isNaN(rawValue)) rawValue = value;
+        if (isNaN(rawValue) || !_isImperial) {
+          tag2[field.key] = context.cleanTagValue(rawValue);
+        } else {
+          tag2[field.key] = context.cleanTagValue(rawValue + " mph");
+        }
+      }
+      dispatch14.call("change", this, tag2);
     }
-    function renderDisclosureContent(selection2) {
-      var center = context.map().center();
-      var graph = context.graph();
-      var issues = _issues.map(function withDistance(issue) {
-        var extent = issue.extent(graph);
-        var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
-        return Object.assign(issue, { dist });
-      }).sort(function byDistance(a2, b2) {
-        return a2.dist - b2.dist;
-      });
-      issues = issues.slice(0, 1e3);
-      selection2.call(drawIssuesList, issues);
+    roadspeed.tags = function(tags) {
+      _tags = tags;
+      var rawValue = tags[field.key];
+      var value = rawValue;
+      var isMixed = Array.isArray(value);
+      if (!isMixed) {
+        if (rawValue && rawValue.indexOf("mph") >= 0) {
+          _isImperial = true;
+        } else if (rawValue) {
+          _isImperial = false;
+        }
+        value = parseInt(value, 10);
+        if (isNaN(value)) {
+          value = rawValue;
+        } else {
+          value = formatFloat(value);
+        }
+      }
+      setUnitSuggestions();
+      utilGetSetValue(input, typeof value === "string" ? value : "").attr("title", isMixed ? value.filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder()).classed("mixed", isMixed);
+    };
+    roadspeed.focus = function() {
+      input.node().focus();
+    };
+    roadspeed.entityIDs = function(val) {
+      _entityIDs = val;
+    };
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
     }
-    function drawIssuesList(selection2, issues) {
-      var list2 = selection2.selectAll(".issues-list").data([0]);
-      list2 = list2.enter().append("ul").attr("class", "layer-list issues-list " + severity + "s-list").merge(list2);
-      var items = list2.selectAll("li").data(issues, function(d2) {
-        return d2.key;
-      });
-      items.exit().remove();
-      var itemsEnter = items.enter().append("li").attr("class", function(d2) {
-        return "issue severity-" + d2.severity;
-      });
-      var labelsEnter = itemsEnter.append("button").attr("class", "issue-label").on("click", function(d3_event, d2) {
-        context.validator().focusIssue(d2);
-      }).on("mouseover", function(d3_event, d2) {
-        utilHighlightEntities(d2.entityIds, true, context);
-      }).on("mouseout", function(d3_event, d2) {
-        utilHighlightEntities(d2.entityIds, false, context);
-      });
-      var textEnter = labelsEnter.append("span").attr("class", "issue-text");
-      textEnter.append("span").attr("class", "issue-icon").each(function(d2) {
-        var iconName = "#iD-icon-" + (d2.severity === "warning" ? "alert" : "error");
-        select_default2(this).call(svgIcon(iconName));
+    return utilRebind(roadspeed, dispatch14, "on");
+  }
+
+  // modules/ui/fields/radio.js
+  function uiFieldRadio(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var placeholder = select_default2(null);
+    var wrap2 = select_default2(null);
+    var labels = select_default2(null);
+    var radios = select_default2(null);
+    var radioData = (field.options || field.keys).slice();
+    var typeField;
+    var layerField;
+    var _oldType = {};
+    var _entityIDs = [];
+    function selectedKey() {
+      var node = wrap2.selectAll(".form-field-input-radio label.active input");
+      return !node.empty() && node.datum();
+    }
+    function radio(selection2) {
+      selection2.classed("preset-radio", true);
+      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      var enter = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-radio");
+      enter.append("span").attr("class", "placeholder");
+      wrap2 = wrap2.merge(enter);
+      placeholder = wrap2.selectAll(".placeholder");
+      labels = wrap2.selectAll("label").data(radioData);
+      enter = labels.enter().append("label");
+      var stringsField = field.resolveReference("stringsCrossReference");
+      enter.append("input").attr("type", "radio").attr("name", field.id).attr("value", function(d2) {
+        return stringsField.t("options." + d2, { "default": d2 });
+      }).attr("checked", false);
+      enter.append("span").each(function(d2) {
+        stringsField.t.append("options." + d2, { "default": d2 })(select_default2(this));
       });
-      textEnter.append("span").attr("class", "issue-message");
-      items = items.merge(itemsEnter).order();
-      items.selectAll(".issue-message").text("").each(function(d2) {
-        return d2.message(context)(select_default2(this));
+      labels = labels.merge(enter);
+      radios = labels.selectAll("input").on("change", changeRadio);
+    }
+    function structureExtras(selection2, tags) {
+      var selected = selectedKey() || tags.layer !== void 0;
+      var type2 = _mainPresetIndex.field(selected);
+      var layer = _mainPresetIndex.field("layer");
+      var showLayer = selected === "bridge" || selected === "tunnel" || tags.layer !== void 0;
+      var extrasWrap = selection2.selectAll(".structure-extras-wrap").data(selected ? [0] : []);
+      extrasWrap.exit().remove();
+      extrasWrap = extrasWrap.enter().append("div").attr("class", "structure-extras-wrap").merge(extrasWrap);
+      var list2 = extrasWrap.selectAll("ul").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
+      if (type2) {
+        if (!typeField || typeField.id !== selected) {
+          typeField = uiField(context, type2, _entityIDs, { wrap: false }).on("change", changeType);
+        }
+        typeField.tags(tags);
+      } else {
+        typeField = null;
+      }
+      var typeItem = list2.selectAll(".structure-type-item").data(typeField ? [typeField] : [], function(d2) {
+        return d2.id;
       });
+      typeItem.exit().remove();
+      var typeEnter = typeItem.enter().insert("li", ":first-child").attr("class", "labeled-input structure-type-item");
+      typeEnter.append("div").attr("class", "label structure-label-type").attr("for", "preset-input-" + selected).call(_t.append("inspector.radio.structure.type"));
+      typeEnter.append("div").attr("class", "structure-input-type-wrap");
+      typeItem = typeItem.merge(typeEnter);
+      if (typeField) {
+        typeItem.selectAll(".structure-input-type-wrap").call(typeField.render);
+      }
+      if (layer && showLayer) {
+        if (!layerField) {
+          layerField = uiField(context, layer, _entityIDs, { wrap: false }).on("change", changeLayer);
+        }
+        layerField.tags(tags);
+        field.keys = utilArrayUnion(field.keys, ["layer"]);
+      } else {
+        layerField = null;
+        field.keys = field.keys.filter(function(k2) {
+          return k2 !== "layer";
+        });
+      }
+      var layerItem = list2.selectAll(".structure-layer-item").data(layerField ? [layerField] : []);
+      layerItem.exit().remove();
+      var layerEnter = layerItem.enter().append("li").attr("class", "labeled-input structure-layer-item");
+      layerEnter.append("div").attr("class", "label structure-label-layer").attr("for", "preset-input-layer").call(_t.append("inspector.radio.structure.layer"));
+      layerEnter.append("div").attr("class", "structure-input-layer-wrap");
+      layerItem = layerItem.merge(layerEnter);
+      if (layerField) {
+        layerItem.selectAll(".structure-input-layer-wrap").call(layerField.render);
+      }
     }
-    context.validator().on("validated.uiSectionValidationIssues" + id2, function() {
-      window.requestIdleCallback(function() {
-        reloadIssues();
-        section.reRender();
-      });
-    });
-    context.map().on(
-      "move.uiSectionValidationIssues" + id2,
-      debounce_default(function() {
-        window.requestIdleCallback(function() {
-          if (getOptions().where === "visible") {
-            reloadIssues();
+    function changeType(t2, onInput) {
+      var key = selectedKey();
+      if (!key) return;
+      var val = t2[key];
+      if (val !== "no") {
+        _oldType[key] = val;
+      }
+      if (field.type === "structureRadio") {
+        if (val === "no" || key !== "bridge" && key !== "tunnel" || key === "tunnel" && val === "building_passage") {
+          t2.layer = void 0;
+        }
+        if (t2.layer === void 0) {
+          if (key === "bridge" && val !== "no") {
+            t2.layer = "1";
           }
-          section.reRender();
-        });
-      }, 1e3)
-    );
-    return section;
-  }
-
-  // modules/ui/sections/validation_options.js
-  function uiSectionValidationOptions(context) {
-    var section = uiSection("issues-options", context).content(renderContent);
-    function renderContent(selection2) {
-      var container = selection2.selectAll(".issues-options-container").data([0]);
-      container = container.enter().append("div").attr("class", "issues-options-container").merge(container);
-      var data = [
-        { key: "what", values: ["edited", "all"] },
-        { key: "where", values: ["visible", "all"] }
-      ];
-      var options2 = container.selectAll(".issues-option").data(data, function(d2) {
-        return d2.key;
-      });
-      var optionsEnter = options2.enter().append("div").attr("class", function(d2) {
-        return "issues-option issues-option-" + d2.key;
+          if (key === "tunnel" && val !== "no" && val !== "building_passage") {
+            t2.layer = "-1";
+          }
+        }
+      }
+      dispatch14.call("change", this, t2, onInput);
+    }
+    function changeLayer(t2, onInput) {
+      if (t2.layer === "0") {
+        t2.layer = void 0;
+      }
+      dispatch14.call("change", this, t2, onInput);
+    }
+    function changeRadio() {
+      var t2 = {};
+      var activeKey;
+      if (field.key) {
+        t2[field.key] = void 0;
+      }
+      radios.each(function(d2) {
+        var active = select_default2(this).property("checked");
+        if (active) activeKey = d2;
+        if (field.key) {
+          if (active) t2[field.key] = d2;
+        } else {
+          var val = _oldType[activeKey] || "yes";
+          t2[d2] = active ? val : void 0;
+        }
       });
-      optionsEnter.append("div").attr("class", "issues-option-title").html(function(d2) {
-        return _t.html("issues.options." + d2.key + ".title");
+      if (field.type === "structureRadio") {
+        if (activeKey === "bridge") {
+          t2.layer = "1";
+        } else if (activeKey === "tunnel" && t2.tunnel !== "building_passage") {
+          t2.layer = "-1";
+        } else {
+          t2.layer = void 0;
+        }
+      }
+      dispatch14.call("change", this, t2);
+    }
+    radio.tags = function(tags) {
+      function isOptionChecked(d2) {
+        if (field.key) {
+          return tags[field.key] === d2;
+        }
+        return !!(typeof tags[d2] === "string" && tags[d2].toLowerCase() !== "no");
+      }
+      function isMixed(d2) {
+        if (field.key) {
+          return Array.isArray(tags[field.key]) && tags[field.key].includes(d2);
+        }
+        return Array.isArray(tags[d2]);
+      }
+      radios.property("checked", function(d2) {
+        return isOptionChecked(d2) && (field.key || field.options.filter(isOptionChecked).length === 1);
       });
-      var valuesEnter = optionsEnter.selectAll("label").data(function(d2) {
-        return d2.values.map(function(val) {
-          return { value: val, key: d2.key };
-        });
-      }).enter().append("label");
-      valuesEnter.append("input").attr("type", "radio").attr("name", function(d2) {
-        return "issues-option-" + d2.key;
-      }).attr("value", function(d2) {
-        return d2.value;
-      }).property("checked", function(d2) {
-        return getOptions()[d2.key] === d2.value;
-      }).on("change", function(d3_event, d2) {
-        updateOptionValue(d3_event, d2.key, d2.value);
+      labels.classed("active", function(d2) {
+        if (field.key) {
+          return Array.isArray(tags[field.key]) && tags[field.key].includes(d2) || tags[field.key] === d2;
+        }
+        return Array.isArray(tags[d2]) && tags[d2].some((v2) => typeof v2 === "string" && v2.toLowerCase() !== "no") || !!(typeof tags[d2] === "string" && tags[d2].toLowerCase() !== "no");
+      }).classed("mixed", isMixed).attr("title", function(d2) {
+        return isMixed(d2) ? _t("inspector.unshared_value_tooltip") : null;
       });
-      valuesEnter.append("span").html(function(d2) {
-        return _t.html("issues.options." + d2.key + "." + d2.value);
+      var selection2 = radios.filter(function() {
+        return this.checked;
       });
-    }
-    function getOptions() {
-      return {
-        what: corePreferences("validate-what") || "edited",
-        // 'all', 'edited'
-        where: corePreferences("validate-where") || "all"
-        // 'all', 'visible'
-      };
-    }
-    function updateOptionValue(d3_event, d2, val) {
-      if (!val && d3_event && d3_event.target) {
-        val = d3_event.target.value;
+      if (selection2.empty()) {
+        placeholder.text("");
+        placeholder.call(_t.append("inspector.none"));
+      } else {
+        placeholder.text(selection2.attr("value"));
+        _oldType[selection2.datum()] = tags[selection2.datum()];
       }
-      corePreferences("validate-" + d2, val);
-      context.validator().validate();
-    }
-    return section;
+      if (field.type === "structureRadio") {
+        if (!!tags.waterway && !_oldType.tunnel) {
+          _oldType.tunnel = "culvert";
+        }
+        wrap2.call(structureExtras, tags);
+      }
+    };
+    radio.focus = function() {
+      radios.node().focus();
+    };
+    radio.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      _oldType = {};
+      return radio;
+    };
+    radio.isAllowed = function() {
+      return _entityIDs.length === 1;
+    };
+    return utilRebind(radio, dispatch14, "on");
   }
 
-  // modules/ui/sections/validation_rules.js
-  function uiSectionValidationRules(context) {
-    var MINSQUARE = 0;
-    var MAXSQUARE = 20;
-    var DEFAULTSQUARE = 5;
-    var section = uiSection("issues-rules", context).disclosureContent(renderDisclosureContent).label(() => _t.append("issues.rules.title"));
-    var _ruleKeys = context.validator().getRuleKeys().filter(function(key) {
-      return key !== "maprules";
-    }).sort(function(key1, key2) {
-      return _t("issues." + key1 + ".title") < _t("issues." + key2 + ".title") ? -1 : 1;
-    });
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".issues-rulelist-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "issues-rulelist-container");
-      containerEnter.append("ul").attr("class", "layer-list issue-rules-list");
-      var ruleLinks = containerEnter.append("div").attr("class", "issue-rules-links section-footer");
-      ruleLinks.append("a").attr("class", "issue-rules-link").attr("role", "button").attr("href", "#").call(_t.append("issues.disable_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.validator().disableRules(_ruleKeys);
+  // modules/ui/fields/restrictions.js
+  function uiFieldRestrictions(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var breathe = behaviorBreathe(context);
+    corePreferences("turn-restriction-via-way", null);
+    var storedViaWay = corePreferences("turn-restriction-via-way0");
+    var storedDistance = corePreferences("turn-restriction-distance");
+    var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
+    var _maxDistance = storedDistance ? +storedDistance : 30;
+    var _initialized3 = false;
+    var _parent = select_default2(null);
+    var _container = select_default2(null);
+    var _oldTurns;
+    var _graph;
+    var _vertexID;
+    var _intersection;
+    var _fromWayID;
+    var _lastXPos;
+    function restrictions(selection2) {
+      _parent = selection2;
+      if (_vertexID && (context.graph() !== _graph || !_intersection)) {
+        _graph = context.graph();
+        _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
+      }
+      var isOK = _intersection && _intersection.vertices.length && // has vertices
+      _intersection.vertices.filter(function(vertex) {
+        return vertex.id === _vertexID;
+      }).length && _intersection.ways.length > 2;
+      select_default2(selection2.node().parentNode).classed("hide", !isOK);
+      if (!isOK || !context.container().select(".inspector-wrap.inspector-hidden").empty() || !selection2.node().parentNode || !selection2.node().parentNode.parentNode) {
+        selection2.call(restrictions.off);
+        return;
+      }
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var container = wrap2.selectAll(".restriction-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "restriction-container");
+      containerEnter.append("div").attr("class", "restriction-help");
+      _container = containerEnter.merge(container).call(renderViewer);
+      var controls = wrap2.selectAll(".restriction-controls").data([0]);
+      controls.enter().append("div").attr("class", "restriction-controls-container").append("div").attr("class", "restriction-controls").merge(controls).call(renderControls);
+    }
+    function renderControls(selection2) {
+      var distControl = selection2.selectAll(".restriction-distance").data([0]);
+      distControl.exit().remove();
+      var distControlEnter = distControl.enter().append("div").attr("class", "restriction-control restriction-distance");
+      distControlEnter.append("span").attr("class", "restriction-control-label restriction-distance-label").call(_t.append("restriction.controls.distance", { suffix: ":" }));
+      distControlEnter.append("input").attr("class", "restriction-distance-input").attr("type", "range").attr("min", "20").attr("max", "50").attr("step", "5");
+      distControlEnter.append("span").attr("class", "restriction-distance-text");
+      selection2.selectAll(".restriction-distance-input").property("value", _maxDistance).on("input", function() {
+        var val = select_default2(this).property("value");
+        _maxDistance = +val;
+        _intersection = null;
+        _container.selectAll(".layer-osm .layer-turns *").remove();
+        corePreferences("turn-restriction-distance", _maxDistance);
+        _parent.call(restrictions);
       });
-      ruleLinks.append("a").attr("class", "issue-rules-link").attr("role", "button").attr("href", "#").call(_t.append("issues.enable_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.validator().disableRules([]);
+      selection2.selectAll(".restriction-distance-text").call(displayMaxDistance(_maxDistance));
+      var viaControl = selection2.selectAll(".restriction-via-way").data([0]);
+      viaControl.exit().remove();
+      var viaControlEnter = viaControl.enter().append("div").attr("class", "restriction-control restriction-via-way");
+      viaControlEnter.append("span").attr("class", "restriction-control-label restriction-via-way-label").call(_t.append("restriction.controls.via", { suffix: ":" }));
+      viaControlEnter.append("input").attr("class", "restriction-via-way-input").attr("type", "range").attr("min", "0").attr("max", "2").attr("step", "1");
+      viaControlEnter.append("span").attr("class", "restriction-via-way-text");
+      selection2.selectAll(".restriction-via-way-input").property("value", _maxViaWay).on("input", function() {
+        var val = select_default2(this).property("value");
+        _maxViaWay = +val;
+        _container.selectAll(".layer-osm .layer-turns *").remove();
+        corePreferences("turn-restriction-via-way0", _maxViaWay);
+        _parent.call(restrictions);
       });
-      container = container.merge(containerEnter);
-      container.selectAll(".issue-rules-list").call(drawListItems, _ruleKeys, "checkbox", "rule", toggleRule, isRuleEnabled);
+      selection2.selectAll(".restriction-via-way-text").call(displayMaxVia(_maxViaWay));
     }
-    function drawListItems(selection2, data, type2, name, change, active) {
-      var items = selection2.selectAll("li").data(data);
-      items.exit().remove();
-      var enter = items.enter().append("li");
-      if (name === "rule") {
-        enter.call(
-          uiTooltip().title(function(d2) {
-            return _t.append("issues." + d2 + ".tip");
-          }).placement("top")
-        );
+    function renderViewer(selection2) {
+      if (!_intersection) return;
+      var vgraph = _intersection.graph;
+      var filter2 = utilFunctor(true);
+      var projection2 = geoRawMercator();
+      var sdims = utilGetDimensions(context.container().select(".sidebar"));
+      var d2 = [sdims[0] - 50, 370];
+      var c2 = geoVecScale(d2, 0.5);
+      var z2 = 22;
+      projection2.scale(geoZoomToScale(z2));
+      var extent = geoExtent();
+      for (var i3 = 0; i3 < _intersection.vertices.length; i3++) {
+        extent._extend(_intersection.vertices[i3].extent());
       }
-      var label = enter.append("label");
-      label.append("input").attr("type", type2).attr("name", name).on("change", change);
-      label.append("span").html(function(d2) {
-        var params = {};
-        if (d2 === "unsquare_way") {
-          params.val = { html: '<span class="square-degrees"></span>' };
+      var padTop = 35;
+      if (_intersection.vertices.length > 1) {
+        var hPadding = Math.min(160, Math.max(110, d2[0] * 0.4));
+        var vPadding = 160;
+        var tl = projection2([extent[0][0], extent[1][1]]);
+        var br2 = projection2([extent[1][0], extent[0][1]]);
+        var hFactor = (br2[0] - tl[0]) / (d2[0] - hPadding);
+        var vFactor = (br2[1] - tl[1]) / (d2[1] - vPadding - padTop);
+        var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
+        var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
+        z2 = z2 - Math.max(hZoomDiff, vZoomDiff);
+        projection2.scale(geoZoomToScale(z2));
+      }
+      var extentCenter = projection2(extent.center());
+      extentCenter[1] = extentCenter[1] - padTop / 2;
+      projection2.translate(geoVecSubtract(c2, extentCenter)).clipExtent([[0, 0], d2]);
+      var drawLayers = svgLayers(projection2, context).only(["osm", "touch"]).dimensions(d2);
+      var drawVertices = svgVertices(projection2, context);
+      var drawLines = svgLines(projection2, context);
+      var drawTurns = svgTurns(projection2, context);
+      var firstTime = selection2.selectAll(".surface").empty();
+      selection2.call(drawLayers);
+      var surface = selection2.selectAll(".surface").classed("tr", true);
+      if (firstTime) {
+        _initialized3 = true;
+        surface.call(breathe);
+      }
+      if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
+        _fromWayID = null;
+        _oldTurns = null;
+      }
+      surface.call(utilSetDimensions, d2).call(drawVertices, vgraph, _intersection.vertices, filter2, extent, z2).call(drawLines, vgraph, _intersection.ways, filter2).call(drawTurns, vgraph, _intersection.turns(_fromWayID, _maxViaWay));
+      surface.on("click.restrictions", click).on("mouseover.restrictions", mouseover);
+      surface.selectAll(".selected").classed("selected", false);
+      surface.selectAll(".related").classed("related", false);
+      var way;
+      if (_fromWayID) {
+        way = vgraph.entity(_fromWayID);
+        surface.selectAll("." + _fromWayID).classed("selected", true).classed("related", true);
+      }
+      document.addEventListener("resizeWindow", function() {
+        utilSetDimensions(_container, null);
+        redraw(1);
+      }, false);
+      updateHints(null);
+      function click(d3_event) {
+        surface.call(breathe.off).call(breathe);
+        var datum2 = d3_event.target.__data__;
+        var entity = datum2 && datum2.properties && datum2.properties.entity;
+        if (entity) {
+          datum2 = entity;
+        }
+        if (datum2 instanceof osmWay && (datum2.__from || datum2.__via)) {
+          _fromWayID = datum2.id;
+          _oldTurns = null;
+          redraw();
+        } else if (datum2 instanceof osmTurn) {
+          var actions, extraActions, turns, i4;
+          var restrictionType = osmInferRestriction(vgraph, datum2, projection2);
+          if (datum2.restrictionID && !datum2.direct) {
+            return;
+          } else if (datum2.restrictionID && !datum2.only) {
+            var seen = {};
+            var datumOnly = JSON.parse(JSON.stringify(datum2));
+            datumOnly.only = true;
+            restrictionType = restrictionType.replace(/^no/, "only");
+            turns = _intersection.turns(_fromWayID, 2);
+            extraActions = [];
+            _oldTurns = [];
+            for (i4 = 0; i4 < turns.length; i4++) {
+              var turn = turns[i4];
+              if (seen[turn.restrictionID]) continue;
+              if (turn.direct && turn.path[1] === datum2.path[1]) {
+                seen[turns[i4].restrictionID] = true;
+                turn.restrictionType = osmInferRestriction(vgraph, turn, projection2);
+                _oldTurns.push(turn);
+                extraActions.push(actionUnrestrictTurn(turn));
+              }
+            }
+            actions = _intersection.actions.concat(extraActions, [
+              actionRestrictTurn(datumOnly, restrictionType),
+              _t("operations.restriction.annotation.create")
+            ]);
+          } else if (datum2.restrictionID) {
+            turns = _oldTurns || [];
+            extraActions = [];
+            for (i4 = 0; i4 < turns.length; i4++) {
+              if (turns[i4].key !== datum2.key) {
+                extraActions.push(actionRestrictTurn(turns[i4], turns[i4].restrictionType));
+              }
+            }
+            _oldTurns = null;
+            actions = _intersection.actions.concat(extraActions, [
+              actionUnrestrictTurn(datum2),
+              _t("operations.restriction.annotation.delete")
+            ]);
+          } else {
+            actions = _intersection.actions.concat([
+              actionRestrictTurn(datum2, restrictionType),
+              _t("operations.restriction.annotation.create")
+            ]);
+          }
+          context.perform.apply(context, actions);
+          var s2 = surface.selectAll("." + datum2.key);
+          datum2 = s2.empty() ? null : s2.datum();
+          updateHints(datum2);
+        } else {
+          _fromWayID = null;
+          _oldTurns = null;
+          redraw();
         }
-        return _t.html("issues." + d2 + ".title", params);
-      });
-      items = items.merge(enter);
-      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
-      var degStr = corePreferences("validate-square-degrees");
-      if (degStr === null) {
-        degStr = DEFAULTSQUARE.toString();
       }
-      var span = items.selectAll(".square-degrees");
-      var input = span.selectAll(".square-degrees-input").data([0]);
-      input.enter().append("input").attr("type", "number").attr("min", MINSQUARE.toString()).attr("max", MAXSQUARE.toString()).attr("step", "0.5").attr("class", "square-degrees-input").call(utilNoAuto).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        this.select();
-      }).on("keyup", function(d3_event) {
-        if (d3_event.keyCode === 13) {
-          this.blur();
-          this.select();
+      function mouseover(d3_event) {
+        var datum2 = d3_event.target.__data__;
+        updateHints(datum2);
+      }
+      _lastXPos = _lastXPos || sdims[0];
+      function redraw(minChange) {
+        var xPos = -1;
+        if (minChange) {
+          xPos = utilGetDimensions(context.container().select(".sidebar"))[0];
+        }
+        if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
+          if (context.hasEntity(_vertexID)) {
+            _lastXPos = xPos;
+            _container.call(renderViewer);
+          }
+        }
+      }
+      function highlightPathsFrom(wayID) {
+        surface.selectAll(".related").classed("related", false).classed("allow", false).classed("restrict", false).classed("only", false);
+        surface.selectAll("." + wayID).classed("related", true);
+        if (wayID) {
+          var turns = _intersection.turns(wayID, _maxViaWay);
+          for (var i4 = 0; i4 < turns.length; i4++) {
+            var turn = turns[i4];
+            var ids = [turn.to.way];
+            var klass = turn.no ? "restrict" : turn.only ? "only" : "allow";
+            if (turn.only || turns.length === 1) {
+              if (turn.via.ways) {
+                ids = ids.concat(turn.via.ways);
+              }
+            } else if (turn.to.way === wayID) {
+              continue;
+            }
+            surface.selectAll(utilEntitySelector(ids)).classed("related", true).classed("allow", klass === "allow").classed("restrict", klass === "restrict").classed("only", klass === "only");
+          }
+        }
+      }
+      function updateHints(datum2) {
+        var help = _container.selectAll(".restriction-help").html("");
+        var placeholders = {};
+        ["from", "via", "to"].forEach(function(k2) {
+          placeholders[k2] = { html: '<span class="qualifier">' + _t("restriction.help." + k2) + "</span>" };
+        });
+        var entity = datum2 && datum2.properties && datum2.properties.entity;
+        if (entity) {
+          datum2 = entity;
+        }
+        if (_fromWayID) {
+          way = vgraph.entity(_fromWayID);
+          surface.selectAll("." + _fromWayID).classed("selected", true).classed("related", true);
+        }
+        if (datum2 instanceof osmWay && datum2.__from) {
+          way = datum2;
+          highlightPathsFrom(_fromWayID ? null : way.id);
+          surface.selectAll("." + way.id).classed("related", true);
+          var clickSelect = !_fromWayID || _fromWayID !== way.id;
+          help.append("div").html(_t.html("restriction.help." + (clickSelect ? "select_from_name" : "from_name"), {
+            from: placeholders.from,
+            fromName: displayName(way.id, vgraph)
+          }));
+        } else if (datum2 instanceof osmTurn) {
+          var restrictionType = osmInferRestriction(vgraph, datum2, projection2);
+          var turnType = restrictionType.replace(/^(only|no)\_/, "");
+          var indirect = datum2.direct === false ? _t.html("restriction.help.indirect") : "";
+          var klass, turnText, nextText;
+          if (datum2.no) {
+            klass = "restrict";
+            turnText = _t.html("restriction.help.turn.no_" + turnType, { indirect: { html: indirect } });
+            nextText = _t.html("restriction.help.turn.only_" + turnType, { indirect: "" });
+          } else if (datum2.only) {
+            klass = "only";
+            turnText = _t.html("restriction.help.turn.only_" + turnType, { indirect: { html: indirect } });
+            nextText = _t.html("restriction.help.turn.allowed_" + turnType, { indirect: "" });
+          } else {
+            klass = "allow";
+            turnText = _t.html("restriction.help.turn.allowed_" + turnType, { indirect: { html: indirect } });
+            nextText = _t.html("restriction.help.turn.no_" + turnType, { indirect: "" });
+          }
+          help.append("div").attr("class", "qualifier " + klass).html(turnText);
+          help.append("div").html(_t.html("restriction.help.from_name_to_name", {
+            from: placeholders.from,
+            fromName: displayName(datum2.from.way, vgraph),
+            to: placeholders.to,
+            toName: displayName(datum2.to.way, vgraph)
+          }));
+          if (datum2.via.ways && datum2.via.ways.length) {
+            var names = [];
+            for (var i4 = 0; i4 < datum2.via.ways.length; i4++) {
+              var prev = names[names.length - 1];
+              var curr = displayName(datum2.via.ways[i4], vgraph);
+              if (!prev || curr !== prev) {
+                names.push(curr);
+              }
+            }
+            help.append("div").html(_t.html("restriction.help.via_names", {
+              via: placeholders.via,
+              viaNames: names.join(", ")
+            }));
+          }
+          if (!indirect) {
+            help.append("div").html(_t.html("restriction.help.toggle", { turn: { html: nextText.trim() } }));
+          }
+          highlightPathsFrom(null);
+          var alongIDs = datum2.path.slice();
+          surface.selectAll(utilEntitySelector(alongIDs)).classed("related", true).classed("allow", klass === "allow").classed("restrict", klass === "restrict").classed("only", klass === "only");
+        } else {
+          highlightPathsFrom(null);
+          if (_fromWayID) {
+            help.append("div").html(_t.html("restriction.help.from_name", {
+              from: placeholders.from,
+              fromName: displayName(_fromWayID, vgraph)
+            }));
+          } else {
+            help.append("div").html(_t.html("restriction.help.select_from", {
+              from: placeholders.from
+            }));
+          }
         }
-      }).on("blur", changeSquare).merge(input).property("value", degStr);
-    }
-    function changeSquare() {
-      var input = select_default2(this);
-      var degStr = utilGetSetValue(input).trim();
-      var degNum = Number(degStr);
-      if (!isFinite(degNum)) {
-        degNum = DEFAULTSQUARE;
-      } else if (degNum > MAXSQUARE) {
-        degNum = MAXSQUARE;
-      } else if (degNum < MINSQUARE) {
-        degNum = MINSQUARE;
       }
-      degNum = Math.round(degNum * 10) / 10;
-      degStr = degNum.toString();
-      input.property("value", degStr);
-      corePreferences("validate-square-degrees", degStr);
-      context.validator().revalidateUnsquare();
-    }
-    function isRuleEnabled(d2) {
-      return context.validator().isRuleEnabled(d2);
-    }
-    function toggleRule(d3_event, d2) {
-      context.validator().toggleRule(d2);
     }
-    context.validator().on("validated.uiSectionValidationRules", function() {
-      window.requestIdleCallback(section.reRender);
-    });
-    return section;
-  }
-
-  // modules/ui/sections/validation_status.js
-  function uiSectionValidationStatus(context) {
-    var section = uiSection("issues-status", context).content(renderContent).shouldDisplay(function() {
-      var issues = context.validator().getIssues(getOptions());
-      return issues.length === 0;
-    });
-    function getOptions() {
-      return {
-        what: corePreferences("validate-what") || "edited",
-        where: corePreferences("validate-where") || "all"
+    function displayMaxDistance(maxDist) {
+      return (selection2) => {
+        var isImperial = !_mainLocalizer.usesMetric();
+        var opts;
+        if (isImperial) {
+          var distToFeet = {
+            // imprecise conversion for prettier display
+            20: 70,
+            25: 85,
+            30: 100,
+            35: 115,
+            40: 130,
+            45: 145,
+            50: 160
+          }[maxDist];
+          opts = { distance: _t("units.feet", { quantity: distToFeet }) };
+        } else {
+          opts = { distance: _t("units.meters", { quantity: maxDist }) };
+        }
+        return selection2.html("").call(_t.append("restriction.controls.distance_up_to", opts));
       };
     }
-    function renderContent(selection2) {
-      var box = selection2.selectAll(".box").data([0]);
-      var boxEnter = box.enter().append("div").attr("class", "box");
-      boxEnter.append("div").call(svgIcon("#iD-icon-apply", "pre-text"));
-      var noIssuesMessage = boxEnter.append("span");
-      noIssuesMessage.append("strong").attr("class", "message");
-      noIssuesMessage.append("br");
-      noIssuesMessage.append("span").attr("class", "details");
-      renderIgnoredIssuesReset(selection2);
-      setNoIssuesText(selection2);
-    }
-    function renderIgnoredIssuesReset(selection2) {
-      var ignoredIssues = context.validator().getIssues({ what: "all", where: "all", includeDisabledRules: true, includeIgnored: "only" });
-      var resetIgnored = selection2.selectAll(".reset-ignored").data(ignoredIssues.length ? [0] : []);
-      resetIgnored.exit().remove();
-      var resetIgnoredEnter = resetIgnored.enter().append("div").attr("class", "reset-ignored section-footer");
-      resetIgnoredEnter.append("a").attr("href", "#");
-      resetIgnored = resetIgnored.merge(resetIgnoredEnter);
-      resetIgnored.select("a").html(_t.html("inspector.title_count", { title: { html: _t.html("issues.reset_ignored") }, count: ignoredIssues.length }));
-      resetIgnored.on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.validator().resetIgnoredIssues();
-      });
+    function displayMaxVia(maxVia) {
+      return (selection2) => {
+        selection2 = selection2.html("");
+        return maxVia === 0 ? selection2.call(_t.append("restriction.controls.via_node_only")) : maxVia === 1 ? selection2.call(_t.append("restriction.controls.via_up_to_one")) : selection2.call(_t.append("restriction.controls.via_up_to_two"));
+      };
     }
-    function setNoIssuesText(selection2) {
-      var opts = getOptions();
-      function checkForHiddenIssues(cases) {
-        for (var type2 in cases) {
-          var hiddenOpts = cases[type2];
-          var hiddenIssues = context.validator().getIssues(hiddenOpts);
-          if (hiddenIssues.length) {
-            selection2.select(".box .details").html("").call(_t.append(
-              "issues.no_issues.hidden_issues." + type2,
-              { count: hiddenIssues.length.toString() }
-            ));
-            return;
-          }
-        }
-        selection2.select(".box .details").html("").call(_t.append("issues.no_issues.hidden_issues.none"));
-      }
-      var messageType;
-      if (opts.what === "edited" && opts.where === "visible") {
-        messageType = "edits_in_view";
-        checkForHiddenIssues({
-          elsewhere: { what: "edited", where: "all" },
-          everything_else: { what: "all", where: "visible" },
-          disabled_rules: { what: "edited", where: "visible", includeDisabledRules: "only" },
-          everything_else_elsewhere: { what: "all", where: "all" },
-          disabled_rules_elsewhere: { what: "edited", where: "all", includeDisabledRules: "only" },
-          ignored_issues: { what: "edited", where: "visible", includeIgnored: "only" },
-          ignored_issues_elsewhere: { what: "edited", where: "all", includeIgnored: "only" }
-        });
-      } else if (opts.what === "edited" && opts.where === "all") {
-        messageType = "edits";
-        checkForHiddenIssues({
-          everything_else: { what: "all", where: "all" },
-          disabled_rules: { what: "edited", where: "all", includeDisabledRules: "only" },
-          ignored_issues: { what: "edited", where: "all", includeIgnored: "only" }
-        });
-      } else if (opts.what === "all" && opts.where === "visible") {
-        messageType = "everything_in_view";
-        checkForHiddenIssues({
-          elsewhere: { what: "all", where: "all" },
-          disabled_rules: { what: "all", where: "visible", includeDisabledRules: "only" },
-          disabled_rules_elsewhere: { what: "all", where: "all", includeDisabledRules: "only" },
-          ignored_issues: { what: "all", where: "visible", includeIgnored: "only" },
-          ignored_issues_elsewhere: { what: "all", where: "all", includeIgnored: "only" }
-        });
-      } else if (opts.what === "all" && opts.where === "all") {
-        messageType = "everything";
-        checkForHiddenIssues({
-          disabled_rules: { what: "all", where: "all", includeDisabledRules: "only" },
-          ignored_issues: { what: "all", where: "all", includeIgnored: "only" }
-        });
-      }
-      if (opts.what === "edited" && context.history().difference().summary().length === 0) {
-        messageType = "no_edits";
-      }
-      selection2.select(".box .message").html("").call(_t.append("issues.no_issues.message." + messageType));
+    function displayName(entityID, graph) {
+      var entity = graph.entity(entityID);
+      var name = utilDisplayName(entity) || "";
+      var matched = _mainPresetIndex.match(entity, graph);
+      var type2 = matched && matched.name() || utilDisplayType(entity.id);
+      return name || type2;
     }
-    context.validator().on("validated.uiSectionValidationStatus", function() {
-      window.requestIdleCallback(section.reRender);
-    });
-    context.map().on(
-      "move.uiSectionValidationStatus",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
-  }
-
-  // modules/ui/panes/issues.js
-  function uiPaneIssues(context) {
-    var issuesPane = uiPane("issues", context).key(_t("issues.key")).label(_t.append("issues.title")).description(_t.append("issues.title")).iconName("iD-icon-alert").sections([
-      uiSectionValidationOptions(context),
-      uiSectionValidationStatus(context),
-      uiSectionValidationIssues("issues-errors", "error", context),
-      uiSectionValidationIssues("issues-warnings", "warning", context),
-      uiSectionValidationRules(context)
-    ]);
-    return issuesPane;
+    restrictions.entityIDs = function(val) {
+      _intersection = null;
+      _fromWayID = null;
+      _oldTurns = null;
+      _vertexID = val[0];
+    };
+    restrictions.tags = function() {
+    };
+    restrictions.focus = function() {
+    };
+    restrictions.off = function(selection2) {
+      if (!_initialized3) return;
+      selection2.selectAll(".surface").call(breathe.off).on("click.restrictions", null).on("mouseover.restrictions", null);
+      select_default2(window).on("resize.restrictions", null);
+    };
+    return utilRebind(restrictions, dispatch14, "on");
   }
+  uiFieldRestrictions.supportsMultiselection = false;
 
-  // modules/ui/settings/custom_data.js
-  function uiSettingsCustomData(context) {
+  // modules/ui/fields/textarea.js
+  function uiFieldTextarea(field, context) {
     var dispatch14 = dispatch_default("change");
-    function render(selection2) {
-      var dataLayer = context.layers().layer("data");
-      var _origSettings = {
-        fileList: dataLayer && dataLayer.fileList() || null,
-        url: corePreferences("settings-custom-data-url")
-      };
-      var _currSettings = {
-        fileList: dataLayer && dataLayer.fileList() || null
-        // url: prefs('settings-custom-data-url')
-      };
-      var modal = uiConfirm(selection2).okButton();
-      modal.classed("settings-modal settings-custom-data", true);
-      modal.select(".modal-section.header").append("h3").call(_t.append("settings.custom_data.header"));
-      var textSection = modal.select(".modal-section.message-text");
-      textSection.append("pre").attr("class", "instructions-file").call(_t.append("settings.custom_data.file.instructions"));
-      textSection.append("input").attr("class", "field-file").attr("type", "file").attr("accept", ".gpx,.kml,.geojson,.json,application/gpx+xml,application/vnd.google-earth.kml+xml,application/geo+json,application/json").property("files", _currSettings.fileList).on("change", function(d3_event) {
-        var files = d3_event.target.files;
-        if (files && files.length) {
-          _currSettings.url = "";
-          textSection.select(".field-url").property("value", "");
-          _currSettings.fileList = files;
-        } else {
-          _currSettings.fileList = null;
-        }
-      });
-      textSection.append("h4").call(_t.append("settings.custom_data.or"));
-      textSection.append("pre").attr("class", "instructions-url").call(_t.append("settings.custom_data.url.instructions"));
-      textSection.append("textarea").attr("class", "field-url").attr("placeholder", _t("settings.custom_data.url.placeholder")).call(utilNoAuto).property("value", _currSettings.url);
-      var buttonSection = modal.select(".modal-section.buttons");
-      buttonSection.insert("button", ".ok-button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
-      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
-      buttonSection.select(".ok-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
-      function isSaveDisabled() {
-        return null;
-      }
-      function clickCancel() {
-        textSection.select(".field-url").property("value", _origSettings.url);
-        corePreferences("settings-custom-data-url", _origSettings.url);
-        this.blur();
-        modal.close();
-      }
-      function clickSave() {
-        _currSettings.url = textSection.select(".field-url").property("value").trim();
-        if (_currSettings.url) {
-          _currSettings.fileList = null;
-        }
-        if (_currSettings.fileList) {
-          _currSettings.url = "";
-        }
-        corePreferences("settings-custom-data-url", _currSettings.url);
-        this.blur();
-        modal.close();
-        dispatch14.call("change", this, _currSettings);
+    var input = select_default2(null);
+    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue()).silent(field.usage === "changeset" && field.key === "comment");
+    var _tags;
+    function textarea(selection2) {
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).style("position", "relative").merge(wrap2);
+      input = wrap2.selectAll("textarea").data([0]);
+      input = input.enter().append("textarea").attr("id", field.domId).call(utilNoAuto).on("input", change(true)).on("blur", change()).on("change", change()).merge(input);
+      wrap2.call(_lengthIndicator);
+      function change(onInput) {
+        return function() {
+          var val = utilGetSetValue(input);
+          if (!onInput) val = context.cleanTagValue(val);
+          if (!val && Array.isArray(_tags[field.key])) return;
+          var t2 = {};
+          t2[field.key] = val || void 0;
+          dispatch14.call("change", this, t2, onInput);
+        };
       }
     }
-    return utilRebind(render, dispatch14, "on");
+    textarea.tags = function(tags) {
+      _tags = tags;
+      var isMixed = Array.isArray(tags[field.key]);
+      utilGetSetValue(input, !isMixed && tags[field.key] ? tags[field.key] : "").attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder() || _t("inspector.unknown")).classed("mixed", isMixed);
+      if (!isMixed) {
+        _lengthIndicator.update(tags[field.key]);
+      }
+    };
+    textarea.focus = function() {
+      input.node().focus();
+    };
+    return utilRebind(textarea, dispatch14, "on");
   }
 
-  // modules/ui/sections/data_layers.js
-  function uiSectionDataLayers(context) {
-    var settingsCustomData = uiSettingsCustomData(context).on("change", customChanged);
-    var layers = context.layers();
-    var section = uiSection("data-layers", context).label(() => _t.append("map_data.data_layers")).disclosureContent(renderDisclosureContent);
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".data-layer-container").data([0]);
-      container.enter().append("div").attr("class", "data-layer-container").merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems).call(drawPanelItems);
-    }
-    function showsLayer(which) {
-      var layer = layers.layer(which);
-      if (layer) {
-        return layer.enabled();
-      }
-      return false;
-    }
-    function setLayer(which, enabled) {
-      var mode = context.mode();
-      if (mode && /^draw/.test(mode.id))
-        return;
-      var layer = layers.layer(which);
-      if (layer) {
-        layer.enabled(enabled);
-        if (!enabled && (which === "osm" || which === "notes")) {
-          context.enter(modeBrowse(context));
+  // modules/ui/fields/wikidata.js
+  function uiFieldWikidata(field, context) {
+    var wikidata = services.wikidata;
+    var dispatch14 = dispatch_default("change");
+    var _selection = select_default2(null);
+    var _searchInput = select_default2(null);
+    var _qid = null;
+    var _wikidataEntity = null;
+    var _wikiURL = "";
+    var _entityIDs = [];
+    var _wikipediaKey = field.keys && field.keys.find(function(key) {
+      return key.includes("wikipedia");
+    });
+    var _hintKey = field.key === "wikidata" ? "name" : field.key.split(":")[0];
+    var combobox = uiCombobox(context, "combo-" + field.safeid).caseSensitive(true).minItems(1);
+    function wiki(selection2) {
+      _selection = selection2;
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var list2 = wrap2.selectAll("ul").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
+      var searchRow = list2.selectAll("li.wikidata-search").data([0]);
+      var searchRowEnter = searchRow.enter().append("li").attr("class", "wikidata-search");
+      searchRowEnter.append("input").attr("type", "text").attr("id", field.domId).style("flex", "1").call(utilNoAuto).on("focus", function() {
+        var node = select_default2(this).node();
+        node.setSelectionRange(0, node.value.length);
+      }).on("blur", function() {
+        setLabelForEntity();
+      }).call(combobox.fetcher(fetchWikidataItems));
+      combobox.on("accept", function(d2) {
+        if (d2) {
+          _qid = d2.id;
+          change();
         }
-      }
-    }
-    function toggleLayer(which) {
-      setLayer(which, !showsLayer(which));
-    }
-    function drawOsmItems(selection2) {
-      var osmKeys = ["osm", "notes"];
-      var osmLayers = layers.all().filter(function(obj) {
-        return osmKeys.indexOf(obj.id) !== -1;
-      });
-      var ul = selection2.selectAll(".layer-list-osm").data([0]);
-      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-osm").merge(ul);
-      var li = ul.selectAll(".list-item").data(osmLayers);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", function(d2) {
-        return "list-item list-item-" + d2.id;
+      }).on("cancel", function() {
+        setLabelForEntity();
       });
-      var labelEnter = liEnter.append("label").each(function(d2) {
-        if (d2.id === "osm") {
-          select_default2(this).call(
-            uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).keys([uiCmd("\u2325" + _t("area_fill.wireframe.key"))]).placement("bottom")
-          );
-        } else {
-          select_default2(this).call(
-            uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).placement("bottom")
-          );
-        }
+      searchRowEnter.append("button").attr("class", "form-field-button wiki-link").attr("title", _t("icons.view_on", { domain: "wikidata.org" })).call(svgIcon("#iD-icon-out-link")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        if (_wikiURL) window.open(_wikiURL, "_blank");
       });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
-        toggleLayer(d2.id);
+      searchRow = searchRow.merge(searchRowEnter);
+      _searchInput = searchRow.select("input");
+      var wikidataProperties = ["description", "identifier"];
+      var items = list2.selectAll("li.labeled-input").data(wikidataProperties);
+      var enter = items.enter().append("li").attr("class", function(d2) {
+        return "labeled-input preset-wikidata-" + d2;
       });
-      labelEnter.append("span").html(function(d2) {
-        return _t.html("map_data.layers." + d2.id + ".title");
+      enter.append("div").attr("class", "label").html(function(d2) {
+        return _t.html("wikidata." + d2);
       });
-      li.merge(liEnter).classed("active", function(d2) {
-        return d2.layer.enabled();
-      }).selectAll("input").property("checked", function(d2) {
-        return d2.layer.enabled();
+      enter.append("input").attr("type", "text").call(utilNoAuto).classed("disabled", "true").attr("readonly", "true");
+      enter.append("button").attr("class", "form-field-button").attr("title", _t("icons.copy")).call(svgIcon("#iD-operation-copy")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        select_default2(this.parentNode).select("input").node().select();
+        document.execCommand("copy");
       });
     }
-    function drawQAItems(selection2) {
-      var qaKeys = ["keepRight", "improveOSM", "osmose"];
-      var qaLayers = layers.all().filter(function(obj) {
-        return qaKeys.indexOf(obj.id) !== -1;
-      });
-      var ul = selection2.selectAll(".layer-list-qa").data([0]);
-      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-qa").merge(ul);
-      var li = ul.selectAll(".list-item").data(qaLayers);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", function(d2) {
-        return "list-item list-item-" + d2.id;
-      });
-      var labelEnter = liEnter.append("label").each(function(d2) {
-        select_default2(this).call(
-          uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).placement("bottom")
-        );
-      });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
-        toggleLayer(d2.id);
-      });
-      labelEnter.append("span").each(function(d2) {
-        _t.append("map_data.layers." + d2.id + ".title")(select_default2(this));
-      });
-      li.merge(liEnter).classed("active", function(d2) {
-        return d2.layer.enabled();
-      }).selectAll("input").property("checked", function(d2) {
-        return d2.layer.enabled();
+    function fetchWikidataItems(q2, callback) {
+      if (!q2 && _hintKey) {
+        for (var i3 in _entityIDs) {
+          var entity = context.hasEntity(_entityIDs[i3]);
+          if (entity.tags[_hintKey]) {
+            q2 = entity.tags[_hintKey];
+            break;
+          }
+        }
+      }
+      wikidata.itemsForSearchQuery(q2, function(err, data) {
+        if (err) {
+          if (err !== "No query") console.error(err);
+          return;
+        }
+        var result = data.map(function(item) {
+          return {
+            id: item.id,
+            value: item.display.label.value + " (" + item.id + ")",
+            display: (selection2) => selection2.append("span").attr("class", "localized-text").attr("lang", item.display.label.language).text(item.display.label.value),
+            title: item.display.description && item.display.description.value,
+            terms: item.aliases
+          };
+        });
+        if (callback) callback(result);
       });
     }
-    function drawVectorItems(selection2) {
-      var dataLayer = layers.layer("data");
-      var vtData = [
-        {
-          name: "Detroit Neighborhoods/Parks",
-          src: "neighborhoods-parks",
-          tooltip: "Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.",
-          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmur6x34562qp9iv1u3ksf-54hev,jonahadkins.cjksmqxdx33jj2wp90xd9x2md-4e5y2/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
-        },
-        {
-          name: "Detroit Composite POIs",
-          src: "composite-poi",
-          tooltip: "Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.",
-          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmm6a02sli31myxhsr7zf3-2sw8h/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
-        },
-        {
-          name: "Detroit All-The-Places POIs",
-          src: "alltheplaces-poi",
-          tooltip: "Public domain business location data created by web scrapers.",
-          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmswgk340g2vo06p1w9w0j-8fjjc/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
+    function change() {
+      var syncTags = {};
+      syncTags[field.key] = _qid;
+      dispatch14.call("change", this, syncTags);
+      var initGraph = context.graph();
+      var initEntityIDs = _entityIDs;
+      wikidata.entityByQID(_qid, function(err, entity) {
+        if (err) return;
+        if (context.graph() !== initGraph) return;
+        if (!entity.sitelinks) return;
+        var langs = wikidata.languagesToQuery();
+        ["labels", "descriptions"].forEach(function(key) {
+          if (!entity[key]) return;
+          var valueLangs = Object.keys(entity[key]);
+          if (valueLangs.length === 0) return;
+          var valueLang = valueLangs[0];
+          if (langs.indexOf(valueLang) === -1) {
+            langs.push(valueLang);
+          }
+        });
+        var newWikipediaValue;
+        if (_wikipediaKey) {
+          var foundPreferred;
+          for (var i3 in langs) {
+            var lang = langs[i3];
+            var siteID = lang.replace("-", "_") + "wiki";
+            if (entity.sitelinks[siteID]) {
+              foundPreferred = true;
+              newWikipediaValue = lang + ":" + entity.sitelinks[siteID].title;
+              break;
+            }
+          }
+          if (!foundPreferred) {
+            var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function(site) {
+              return site.endsWith("wiki");
+            });
+            if (wikiSiteKeys.length === 0) {
+              newWikipediaValue = null;
+            } else {
+              var wikiLang = wikiSiteKeys[0].slice(0, -4).replace("_", "-");
+              var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
+              newWikipediaValue = wikiLang + ":" + wikiTitle;
+            }
+          }
         }
-      ];
-      var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
-      var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
-      var container = selection2.selectAll(".vectortile-container").data(showVectorItems ? [0] : []);
-      container.exit().remove();
-      var containerEnter = container.enter().append("div").attr("class", "vectortile-container");
-      containerEnter.append("h4").attr("class", "vectortile-header").text("Detroit Vector Tiles (Beta)");
-      containerEnter.append("ul").attr("class", "layer-list layer-list-vectortile");
-      containerEnter.append("div").attr("class", "vectortile-footer").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/osmus/detroit-mapping-challenge").append("span").text("About these layers");
-      container = container.merge(containerEnter);
-      var ul = container.selectAll(".layer-list-vectortile");
-      var li = ul.selectAll(".list-item").data(vtData);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", function(d2) {
-        return "list-item list-item-" + d2.src;
-      });
-      var labelEnter = liEnter.append("label").each(function(d2) {
-        select_default2(this).call(
-          uiTooltip().title(d2.tooltip).placement("top")
+        if (newWikipediaValue) {
+          newWikipediaValue = context.cleanTagValue(newWikipediaValue);
+        }
+        if (typeof newWikipediaValue === "undefined") return;
+        var actions = initEntityIDs.map(function(entityID) {
+          var entity2 = context.hasEntity(entityID);
+          if (!entity2) return null;
+          var currTags = Object.assign({}, entity2.tags);
+          if (newWikipediaValue === null) {
+            if (!currTags[_wikipediaKey]) return null;
+            delete currTags[_wikipediaKey];
+          } else {
+            currTags[_wikipediaKey] = newWikipediaValue;
+          }
+          return actionChangeTags(entityID, currTags);
+        }).filter(Boolean);
+        if (!actions.length) return;
+        context.overwrite(
+          function actionUpdateWikipediaTags(graph) {
+            actions.forEach(function(action) {
+              graph = action(graph);
+            });
+            return graph;
+          },
+          context.history().undoAnnotation()
         );
       });
-      labelEnter.append("input").attr("type", "radio").attr("name", "vectortile").on("change", selectVTLayer);
-      labelEnter.append("span").text(function(d2) {
-        return d2.name;
-      });
-      li.merge(liEnter).classed("active", isVTLayerSelected).selectAll("input").property("checked", isVTLayerSelected);
-      function isVTLayerSelected(d2) {
-        return dataLayer && dataLayer.template() === d2.template;
-      }
-      function selectVTLayer(d3_event, d2) {
-        corePreferences("settings-custom-data-url", d2.template);
-        if (dataLayer) {
-          dataLayer.template(d2.template, d2.src);
-          dataLayer.enabled(true);
+    }
+    function setLabelForEntity() {
+      var label = "";
+      if (_wikidataEntity) {
+        label = entityPropertyForDisplay(_wikidataEntity, "labels");
+        if (label.length === 0) {
+          label = _wikidataEntity.id.toString();
         }
       }
+      utilGetSetValue(_searchInput, label);
     }
-    function drawCustomDataItems(selection2) {
-      var dataLayer = layers.layer("data");
-      var hasData = dataLayer && dataLayer.hasData();
-      var showsData = hasData && dataLayer.enabled();
-      var ul = selection2.selectAll(".layer-list-data").data(dataLayer ? [0] : []);
-      ul.exit().remove();
-      var ulEnter = ul.enter().append("ul").attr("class", "layer-list layer-list-data");
-      var liEnter = ulEnter.append("li").attr("class", "list-item-data");
-      var labelEnter = liEnter.append("label").call(
-        uiTooltip().title(() => _t.append("map_data.layers.custom.tooltip")).placement("top")
-      );
-      labelEnter.append("input").attr("type", "checkbox").on("change", function() {
-        toggleLayer("data");
-      });
-      labelEnter.append("span").call(_t.append("map_data.layers.custom.title"));
-      liEnter.append("button").attr("class", "open-data-options").call(
-        uiTooltip().title(() => _t.append("settings.custom_data.tooltip")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        editCustom();
-      }).call(svgIcon("#iD-icon-more"));
-      liEnter.append("button").attr("class", "zoom-to-data").call(
-        uiTooltip().title(() => _t.append("map_data.layers.custom.zoom")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).on("click", function(d3_event) {
-        if (select_default2(this).classed("disabled"))
-          return;
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        dataLayer.fitZoom();
-      }).call(svgIcon("#iD-icon-framed-dot", "monochrome"));
-      ul = ul.merge(ulEnter);
-      ul.selectAll(".list-item-data").classed("active", showsData).selectAll("label").classed("deemphasize", !hasData).selectAll("input").property("disabled", !hasData).property("checked", showsData);
-      ul.selectAll("button.zoom-to-data").classed("disabled", !hasData);
-    }
-    function editCustom() {
-      context.container().call(settingsCustomData);
-    }
-    function customChanged(d2) {
-      var dataLayer = layers.layer("data");
-      if (d2 && d2.url) {
-        dataLayer.url(d2.url);
-      } else if (d2 && d2.fileList) {
-        dataLayer.fileList(d2.fileList);
+    wiki.tags = function(tags) {
+      var isMixed = Array.isArray(tags[field.key]);
+      _searchInput.attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : "").classed("mixed", isMixed);
+      _qid = typeof tags[field.key] === "string" && tags[field.key] || "";
+      if (!/^Q[0-9]*$/.test(_qid)) {
+        unrecognized();
+        return;
       }
-    }
-    function drawPanelItems(selection2) {
-      var panelsListEnter = selection2.selectAll(".md-extras-list").data([0]).enter().append("ul").attr("class", "layer-list md-extras-list");
-      var historyPanelLabelEnter = panelsListEnter.append("li").attr("class", "history-panel-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("map_data.history_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.history.key"))]).placement("top")
-      );
-      historyPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        context.ui().info.toggle("history");
-      });
-      historyPanelLabelEnter.append("span").call(_t.append("map_data.history_panel.title"));
-      var measurementPanelLabelEnter = panelsListEnter.append("li").attr("class", "measurement-panel-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("map_data.measurement_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.measurement.key"))]).placement("top")
-      );
-      measurementPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        context.ui().info.toggle("measurement");
+      _wikiURL = "https://wikidata.org/wiki/" + _qid;
+      wikidata.entityByQID(_qid, function(err, entity) {
+        if (err) {
+          unrecognized();
+          return;
+        }
+        _wikidataEntity = entity;
+        setLabelForEntity();
+        var description = entityPropertyForDisplay(entity, "descriptions");
+        _selection.select("button.wiki-link").classed("disabled", false);
+        _selection.select(".preset-wikidata-description").style("display", function() {
+          return description.length > 0 ? "flex" : "none";
+        }).select("input").attr("value", description);
+        _selection.select(".preset-wikidata-identifier").style("display", function() {
+          return entity.id ? "flex" : "none";
+        }).select("input").attr("value", entity.id);
       });
-      measurementPanelLabelEnter.append("span").call(_t.append("map_data.measurement_panel.title"));
+      function unrecognized() {
+        _wikidataEntity = null;
+        setLabelForEntity();
+        _selection.select(".preset-wikidata-description").style("display", "none");
+        _selection.select(".preset-wikidata-identifier").style("display", "none");
+        _selection.select("button.wiki-link").classed("disabled", true);
+        if (_qid && _qid !== "") {
+          _wikiURL = "https://wikidata.org/wiki/Special:Search?search=" + _qid;
+        } else {
+          _wikiURL = "";
+        }
+      }
+    };
+    function entityPropertyForDisplay(wikidataEntity, propKey) {
+      if (!wikidataEntity[propKey]) return "";
+      var propObj = wikidataEntity[propKey];
+      var langKeys = Object.keys(propObj);
+      if (langKeys.length === 0) return "";
+      var langs = wikidata.languagesToQuery();
+      for (var i3 in langs) {
+        var lang = langs[i3];
+        var valueObj = propObj[lang];
+        if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
+      }
+      return propObj[langKeys[0]].value;
     }
-    context.layers().on("change.uiSectionDataLayers", section.reRender);
-    context.map().on(
-      "move.uiSectionDataLayers",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
+    wiki.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return wiki;
+    };
+    wiki.focus = function() {
+      _searchInput.node().focus();
+    };
+    return utilRebind(wiki, dispatch14, "on");
   }
 
-  // modules/ui/sections/map_features.js
-  function uiSectionMapFeatures(context) {
-    var _features = context.features().keys();
-    var section = uiSection("map-features", context).label(() => _t.append("map_data.map_features")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".layer-feature-list-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "layer-feature-list-container");
-      containerEnter.append("ul").attr("class", "layer-list layer-feature-list");
-      var footer = containerEnter.append("div").attr("class", "feature-list-links section-footer");
-      footer.append("a").attr("class", "feature-list-link").attr("role", "button").attr("href", "#").call(_t.append("issues.disable_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.features().disableAll();
+  // modules/ui/fields/wikipedia.js
+  function uiFieldWikipedia(field, context) {
+    const scheme = "https://";
+    const domain = "wikipedia.org";
+    const dispatch14 = dispatch_default("change");
+    const wikipedia = services.wikipedia;
+    const wikidata = services.wikidata;
+    let _langInput = select_default2(null);
+    let _titleInput = select_default2(null);
+    let _wikiURL = "";
+    let _entityIDs;
+    let _tags;
+    let _dataWikipedia = [];
+    _mainFileFetcher.get("wmf_sitematrix").then((d2) => {
+      _dataWikipedia = d2;
+      if (_tags) updateForTags(_tags);
+    }).catch(() => {
+    });
+    const langCombo = uiCombobox(context, "wikipedia-lang").fetcher((value, callback) => {
+      const v2 = value.toLowerCase();
+      callback(
+        _dataWikipedia.filter((d2) => {
+          return d2[0].toLowerCase().indexOf(v2) >= 0 || d2[1].toLowerCase().indexOf(v2) >= 0 || d2[2].toLowerCase().indexOf(v2) >= 0;
+        }).map((d2) => ({ value: d2[1] }))
+      );
+    });
+    const titleCombo = uiCombobox(context, "wikipedia-title").fetcher((value, callback) => {
+      if (!value) {
+        value = "";
+        for (let i3 in _entityIDs) {
+          let entity = context.hasEntity(_entityIDs[i3]);
+          if (entity.tags.name) {
+            value = entity.tags.name;
+            break;
+          }
+        }
+      }
+      const searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
+      searchfn(language()[2], value, (query, data) => {
+        callback(data.map((d2) => ({ value: d2 })));
       });
-      footer.append("a").attr("class", "feature-list-link").attr("role", "button").attr("href", "#").call(_t.append("issues.enable_all")).on("click", function(d3_event) {
+    });
+    function wiki(selection2) {
+      let wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap2);
+      let langContainer = wrap2.selectAll(".wiki-lang-container").data([0]);
+      langContainer = langContainer.enter().append("div").attr("class", "wiki-lang-container").merge(langContainer);
+      _langInput = langContainer.selectAll("input.wiki-lang").data([0]);
+      _langInput = _langInput.enter().append("input").attr("type", "text").attr("class", "wiki-lang").attr("placeholder", _t("translate.localized_translation_language")).call(utilNoAuto).call(langCombo).merge(_langInput);
+      _langInput.on("blur", changeLang).on("change", changeLang);
+      let titleContainer = wrap2.selectAll(".wiki-title-container").data([0]);
+      titleContainer = titleContainer.enter().append("div").attr("class", "wiki-title-container").merge(titleContainer);
+      _titleInput = titleContainer.selectAll("input.wiki-title").data([0]);
+      _titleInput = _titleInput.enter().append("input").attr("type", "text").attr("class", "wiki-title").attr("id", field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
+      _titleInput.on("blur", function() {
+        change(true);
+      }).on("change", function() {
+        change(false);
+      });
+      let link3 = titleContainer.selectAll(".wiki-link").data([0]);
+      link3 = link3.enter().append("button").attr("class", "form-field-button wiki-link").attr("title", _t("icons.view_on", { domain })).call(svgIcon("#iD-icon-out-link")).merge(link3);
+      link3.on("click", (d3_event) => {
         d3_event.preventDefault();
-        context.features().enableAll();
+        if (_wikiURL) window.open(_wikiURL, "_blank");
       });
-      container = container.merge(containerEnter);
-      container.selectAll(".layer-feature-list").call(drawListItems, _features, "checkbox", "feature", clickFeature, showsFeature);
     }
-    function drawListItems(selection2, data, type2, name, change, active) {
-      var items = selection2.selectAll("li").data(data);
-      items.exit().remove();
-      var enter = items.enter().append("li").call(
-        uiTooltip().title(function(d2) {
-          var tip = _t.append(name + "." + d2 + ".tooltip");
-          if (autoHiddenFeature(d2)) {
-            var msg = showsLayer("osm") ? _t.append("map_data.autohidden") : _t.append("map_data.osmhidden");
-            return (selection3) => {
-              selection3.call(tip);
-              selection3.append("div").call(msg);
-            };
-          }
-          return tip;
-        }).placement("top")
-      );
-      var label = enter.append("label");
-      label.append("input").attr("type", type2).attr("name", name).on("change", change);
-      label.append("span").html(function(d2) {
-        return _t.html(name + "." + d2 + ".description");
-      });
-      items = items.merge(enter);
-      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", autoHiddenFeature);
+    function defaultLanguageInfo(skipEnglishFallback) {
+      const langCode = _mainLocalizer.languageCode().toLowerCase();
+      for (let i3 in _dataWikipedia) {
+        let d2 = _dataWikipedia[i3];
+        if (d2[2] === langCode) return d2;
+      }
+      return skipEnglishFallback ? ["", "", ""] : ["English", "English", "en"];
     }
-    function autoHiddenFeature(d2) {
-      return context.features().autoHidden(d2);
+    function language(skipEnglishFallback) {
+      const value = utilGetSetValue(_langInput).toLowerCase();
+      for (let i3 in _dataWikipedia) {
+        let d2 = _dataWikipedia[i3];
+        if (d2[0].toLowerCase() === value || d2[1].toLowerCase() === value || d2[2] === value) return d2;
+      }
+      return defaultLanguageInfo(skipEnglishFallback);
     }
-    function showsFeature(d2) {
-      return context.features().enabled(d2);
+    function changeLang() {
+      utilGetSetValue(_langInput, language()[1]);
+      change(true);
     }
-    function clickFeature(d3_event, d2) {
-      context.features().toggle(d2);
+    function change(skipWikidata) {
+      let value = utilGetSetValue(_titleInput);
+      const m2 = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
+      const langInfo = m2 && _dataWikipedia.find((d2) => m2[1] === d2[2]);
+      let syncTags = {};
+      if (langInfo) {
+        const nativeLangName = langInfo[1];
+        value = decodeURIComponent(m2[2]).replace(/_/g, " ");
+        if (m2[3]) {
+          let anchor;
+          anchor = decodeURIComponent(m2[3]);
+          value += "#" + anchor.replace(/_/g, " ");
+        }
+        value = value.slice(0, 1).toUpperCase() + value.slice(1);
+        utilGetSetValue(_langInput, nativeLangName);
+        utilGetSetValue(_titleInput, value);
+      }
+      if (value) {
+        syncTags.wikipedia = context.cleanTagValue(language()[2] + ":" + value);
+      } else {
+        syncTags.wikipedia = void 0;
+      }
+      dispatch14.call("change", this, syncTags);
+      if (skipWikidata || !value || !language()[2]) return;
+      const initGraph = context.graph();
+      const initEntityIDs = _entityIDs;
+      wikidata.itemsByTitle(language()[2], value, (err, data) => {
+        if (err || !data || !Object.keys(data).length) return;
+        if (context.graph() !== initGraph) return;
+        const qids = Object.keys(data);
+        const value2 = qids && qids.find((id2) => id2.match(/^Q\d+$/));
+        let actions = initEntityIDs.map((entityID) => {
+          let entity = context.entity(entityID).tags;
+          let currTags = Object.assign({}, entity);
+          if (currTags.wikidata !== value2) {
+            currTags.wikidata = value2;
+            return actionChangeTags(entityID, currTags);
+          }
+          return null;
+        }).filter(Boolean);
+        if (!actions.length) return;
+        context.overwrite(
+          function actionUpdateWikidataTags(graph) {
+            actions.forEach(function(action) {
+              graph = action(graph);
+            });
+            return graph;
+          },
+          context.history().undoAnnotation()
+        );
+      });
     }
-    function showsLayer(id2) {
-      var layer = context.layers().layer(id2);
-      return layer && layer.enabled();
+    wiki.tags = (tags) => {
+      _tags = tags;
+      updateForTags(tags);
+    };
+    function updateForTags(tags) {
+      const value = typeof tags[field.key] === "string" ? tags[field.key] : "";
+      const m2 = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
+      const tagLang = m2 && m2[1];
+      const tagArticleTitle = m2 && m2[2];
+      let anchor = m2 && m2[3];
+      const tagLangInfo = tagLang && _dataWikipedia.find((d2) => tagLang === d2[2]);
+      if (tagLangInfo) {
+        const nativeLangName = tagLangInfo[1];
+        utilGetSetValue(_langInput, nativeLangName);
+        utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? "#" + anchor : ""));
+        _wikiURL = "".concat(scheme).concat(tagLang, ".").concat(domain, "/wiki/").concat(wiki.encodePath(tagArticleTitle, anchor));
+      } else {
+        utilGetSetValue(_titleInput, value);
+        if (value && value !== "") {
+          utilGetSetValue(_langInput, "");
+          const defaultLangInfo = defaultLanguageInfo();
+          _wikiURL = "".concat(scheme).concat(defaultLangInfo[2], ".").concat(domain, "/w/index.php?fulltext=1&search=").concat(value);
+        } else {
+          const shownOrDefaultLangInfo = language(
+            true
+            /* skipEnglishFallback */
+          );
+          utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
+          _wikiURL = "";
+        }
+      }
     }
-    context.features().on("change.map_features", section.reRender);
-    return section;
+    wiki.encodePath = (tagArticleTitle, anchor) => {
+      const underscoredTitle = tagArticleTitle.replace(/ /g, "_");
+      const uriEncodedUnderscoredTitle = encodeURIComponent(underscoredTitle);
+      const uriEncodedAnchorFragment = wiki.encodeURIAnchorFragment(anchor);
+      return "".concat(uriEncodedUnderscoredTitle).concat(uriEncodedAnchorFragment);
+    };
+    wiki.encodeURIAnchorFragment = (anchor) => {
+      if (!anchor) return "";
+      const underscoredAnchor = anchor.replace(/ /g, "_");
+      return "#" + encodeURIComponent(underscoredAnchor);
+    };
+    wiki.entityIDs = (val) => {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return wiki;
+    };
+    wiki.focus = () => {
+      _titleInput.node().focus();
+    };
+    return utilRebind(wiki, dispatch14, "on");
   }
+  uiFieldWikipedia.supportsMultiselection = false;
 
-  // modules/ui/sections/map_style_options.js
-  function uiSectionMapStyleOptions(context) {
-    var section = uiSection("fill-area", context).label(() => _t.append("map_data.style_options")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".layer-fill-list").data([0]);
-      container.enter().append("ul").attr("class", "layer-list layer-fill-list").merge(container).call(drawListItems, context.map().areaFillOptions, "radio", "area_fill", setFill, isActiveFill);
-      var container2 = selection2.selectAll(".layer-visual-diff-list").data([0]);
-      container2.enter().append("ul").attr("class", "layer-list layer-visual-diff-list").merge(container2).call(drawListItems, ["highlight_edits"], "checkbox", "visual_diff", toggleHighlightEdited, function() {
-        return context.surface().classed("highlight-edited");
+  // modules/ui/fields/index.js
+  var uiFields = {
+    access: uiFieldAccess,
+    address: uiFieldAddress,
+    check: uiFieldCheck,
+    colour: uiFieldText,
+    combo: uiFieldCombo,
+    cycleway: uiFieldDirectionalCombo,
+    date: uiFieldText,
+    defaultCheck: uiFieldCheck,
+    directionalCombo: uiFieldDirectionalCombo,
+    email: uiFieldText,
+    identifier: uiFieldText,
+    lanes: uiFieldLanes,
+    localized: uiFieldLocalized,
+    roadheight: uiFieldRoadheight,
+    roadspeed: uiFieldRoadspeed,
+    manyCombo: uiFieldCombo,
+    multiCombo: uiFieldCombo,
+    networkCombo: uiFieldCombo,
+    number: uiFieldText,
+    onewayCheck: uiFieldCheck,
+    radio: uiFieldRadio,
+    restrictions: uiFieldRestrictions,
+    semiCombo: uiFieldCombo,
+    structureRadio: uiFieldRadio,
+    tel: uiFieldText,
+    text: uiFieldText,
+    textarea: uiFieldTextarea,
+    typeCombo: uiFieldCombo,
+    url: uiFieldText,
+    wikidata: uiFieldWikidata,
+    wikipedia: uiFieldWikipedia
+  };
+
+  // modules/ui/field.js
+  function uiField(context, presetField2, entityIDs, options2) {
+    options2 = Object.assign({
+      show: true,
+      wrap: true,
+      remove: true,
+      revert: true,
+      info: true
+    }, options2);
+    var dispatch14 = dispatch_default("change", "revert");
+    var field = Object.assign({}, presetField2);
+    field.domId = utilUniqueDomId("form-field-" + field.safeid);
+    var _show = options2.show;
+    var _state = "";
+    var _tags = {};
+    var _entityExtent;
+    if (entityIDs && entityIDs.length) {
+      _entityExtent = entityIDs.reduce(function(extent, entityID) {
+        var entity = context.graph().entity(entityID);
+        return extent.extend(entity.extent(context.graph()));
+      }, geoExtent());
+    }
+    var _locked = false;
+    var _lockedTip = uiTooltip().title(() => _t.append("inspector.lock.suggestion", { label: field.title })).placement("bottom");
+    if (_show && !field.impl) {
+      createField();
+    }
+    function createField() {
+      field.impl = uiFields[field.type](field, context).on("change", function(t2, onInput) {
+        dispatch14.call("change", field, t2, onInput);
       });
+      if (entityIDs) {
+        field.entityIDs = entityIDs;
+        if (field.impl.entityIDs) {
+          field.impl.entityIDs(entityIDs);
+        }
+      }
     }
-    function drawListItems(selection2, data, type2, name, change, active) {
-      var items = selection2.selectAll("li").data(data);
-      items.exit().remove();
-      var enter = items.enter().append("li").call(
-        uiTooltip().title(function(d2) {
-          return _t.append(name + "." + d2 + ".tooltip");
-        }).keys(function(d2) {
-          var key = d2 === "wireframe" ? _t("area_fill.wireframe.key") : null;
-          if (d2 === "highlight_edits")
-            key = _t("map_data.highlight_edits.key");
-          return key ? [key] : null;
-        }).placement("top")
-      );
-      var label = enter.append("label");
-      label.append("input").attr("type", type2).attr("name", name).on("change", change);
-      label.append("span").html(function(d2) {
-        return _t.html(name + "." + d2 + ".description");
+    function allKeys() {
+      let keys2 = field.keys || [field.key];
+      if (field.type === "directionalCombo" && field.key) {
+        keys2 = keys2.concat(field.key);
+      }
+      return keys2;
+    }
+    function isModified() {
+      if (!entityIDs || !entityIDs.length) return false;
+      return entityIDs.some(function(entityID) {
+        var original = context.graph().base().entities[entityID];
+        var latest = context.graph().entity(entityID);
+        return allKeys().some(function(key) {
+          return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
+        });
       });
-      items = items.merge(enter);
-      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
     }
-    function isActiveFill(d2) {
-      return context.map().activeAreaFill() === d2;
+    function tagsContainFieldKey() {
+      return allKeys().some(function(key) {
+        if (field.type === "multiCombo") {
+          for (var tagKey in _tags) {
+            if (tagKey.indexOf(key) === 0) {
+              return true;
+            }
+          }
+          return false;
+        }
+        if (field.type === "localized") {
+          for (let tagKey2 in _tags) {
+            let match = tagKey2.match(LANGUAGE_SUFFIX_REGEX);
+            if (match && match[1] === field.key && match[2]) {
+              return true;
+            }
+          }
+        }
+        return _tags[key] !== void 0;
+      });
     }
-    function toggleHighlightEdited(d3_event) {
+    function revert(d3_event, d2) {
+      d3_event.stopPropagation();
       d3_event.preventDefault();
-      context.map().toggleHighlightEdited();
+      if (!entityIDs || _locked) return;
+      dispatch14.call("revert", d2, allKeys());
     }
-    function setFill(d3_event, d2) {
-      context.map().activeAreaFill(d2);
+    function remove2(d3_event, d2) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
+      if (_locked) return;
+      var t2 = {};
+      allKeys().forEach(function(key) {
+        t2[key] = void 0;
+      });
+      dispatch14.call("change", d2, t2);
     }
-    context.map().on("changeHighlighting.ui_style, changeAreaFill.ui_style", section.reRender);
-    return section;
+    field.render = function(selection2) {
+      var container = selection2.selectAll(".form-field").data([field]);
+      var enter = container.enter().append("div").attr("class", function(d2) {
+        return "form-field form-field-" + d2.safeid;
+      }).classed("nowrap", !options2.wrap);
+      if (options2.wrap) {
+        var labelEnter = enter.append("label").attr("class", "field-label").attr("for", function(d2) {
+          return d2.domId;
+        });
+        var textEnter = labelEnter.append("span").attr("class", "label-text");
+        textEnter.append("span").attr("class", "label-textvalue").each(function(d2) {
+          d2.label()(select_default2(this));
+        });
+        textEnter.append("span").attr("class", "label-textannotation");
+        if (options2.remove) {
+          labelEnter.append("button").attr("class", "remove-icon").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
+        }
+        if (options2.revert) {
+          labelEnter.append("button").attr("class", "modified-icon").attr("title", _t("icons.undo")).call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-redo" : "#iD-icon-undo"));
+        }
+      }
+      container = container.merge(enter);
+      container.select(".field-label > .remove-icon").on("click", remove2);
+      container.select(".field-label > .modified-icon").on("click", revert);
+      container.each(function(d2) {
+        var selection3 = select_default2(this);
+        if (!d2.impl) {
+          createField();
+        }
+        var reference, help;
+        if (options2.wrap && field.type === "restrictions") {
+          help = uiFieldHelp(context, "restrictions");
+        }
+        if (options2.wrap && options2.info) {
+          var referenceKey = d2.key || "";
+          if (d2.type === "multiCombo") {
+            referenceKey = referenceKey.replace(/:$/, "");
+          }
+          var referenceOptions = d2.reference || {
+            key: referenceKey,
+            value: _tags[referenceKey]
+          };
+          reference = uiTagReference(referenceOptions, context);
+          if (_state === "hover") {
+            reference.showing(false);
+          }
+        }
+        selection3.call(d2.impl);
+        if (help) {
+          selection3.call(help.body).select(".field-label").call(help.button);
+        }
+        if (reference) {
+          selection3.call(reference.body).select(".field-label").call(reference.button);
+        }
+        d2.impl.tags(_tags);
+      });
+      container.classed("locked", _locked).classed("modified", isModified()).classed("present", tagsContainFieldKey());
+      var annotation = container.selectAll(".field-label .label-textannotation");
+      var icon2 = annotation.selectAll(".icon").data(_locked ? [0] : []);
+      icon2.exit().remove();
+      icon2.enter().append("svg").attr("class", "icon").append("use").attr("xlink:href", "#fas-lock");
+      container.call(_locked ? _lockedTip : _lockedTip.destroy);
+    };
+    field.state = function(val) {
+      if (!arguments.length) return _state;
+      _state = val;
+      return field;
+    };
+    field.tags = function(val) {
+      if (!arguments.length) return _tags;
+      _tags = val;
+      if (tagsContainFieldKey() && !_show) {
+        _show = true;
+        if (!field.impl) {
+          createField();
+        }
+      }
+      return field;
+    };
+    field.locked = function(val) {
+      if (!arguments.length) return _locked;
+      _locked = val;
+      return field;
+    };
+    field.show = function() {
+      _show = true;
+      if (!field.impl) {
+        createField();
+      }
+      if (field.default && field.key && _tags[field.key] !== field.default) {
+        var t2 = {};
+        t2[field.key] = field.default;
+        dispatch14.call("change", this, t2);
+      }
+    };
+    field.isShown = function() {
+      return _show;
+    };
+    field.isAllowed = function() {
+      if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
+      if (field.geometry && !entityIDs.every(function(entityID) {
+        return field.matchGeometry(context.graph().geometry(entityID));
+      })) return false;
+      if (entityIDs && _entityExtent && field.locationSetID) {
+        var validHere = _sharedLocationManager.locationSetsAt(_entityExtent.center());
+        if (!validHere[field.locationSetID]) return false;
+      }
+      var prerequisiteTag = field.prerequisiteTag;
+      if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
+      prerequisiteTag) {
+        if (!entityIDs.every(function(entityID) {
+          var entity = context.graph().entity(entityID);
+          if (prerequisiteTag.key) {
+            var value = entity.tags[prerequisiteTag.key];
+            if (!value) return false;
+            if (prerequisiteTag.valueNot) {
+              return prerequisiteTag.valueNot !== value;
+            }
+            if (prerequisiteTag.value) {
+              return prerequisiteTag.value === value;
+            }
+          } else if (prerequisiteTag.keyNot) {
+            if (entity.tags[prerequisiteTag.keyNot]) return false;
+          }
+          return true;
+        })) return false;
+      }
+      return true;
+    };
+    field.focus = function() {
+      if (field.impl) {
+        field.impl.focus();
+      }
+    };
+    return utilRebind(field, dispatch14, "on");
   }
 
-  // modules/ui/settings/local_photos.js
-  function uiSettingsLocalPhotos(context) {
+  // modules/ui/changeset_editor.js
+  function uiChangesetEditor(context) {
     var dispatch14 = dispatch_default("change");
-    var photoLayer = context.layers().layer("local-photos");
-    var modal;
+    var formFields = uiFormFields(context);
+    var commentCombo = uiCombobox(context, "comment").caseSensitive(true);
+    var _fieldsArr;
+    var _tags;
+    var _changesetID;
+    function changesetEditor(selection2) {
+      render(selection2);
+    }
     function render(selection2) {
-      modal = uiConfirm(selection2).okButton();
-      modal.classed("settings-modal settings-local-photos", true);
-      modal.select(".modal-section.header").append("h3").call(_t.append("local_photos.header"));
-      modal.select(".modal-section.message-text").append("div").classed("local-photos", true);
-      var instructionsSection = modal.select(".modal-section.message-text .local-photos").append("div").classed("instructions", true);
-      instructionsSection.append("p").classed("instructions-local-photos", true).call(_t.append("local_photos.file.instructions"));
-      instructionsSection.append("input").classed("field-file", true).attr("type", "file").attr("multiple", "multiple").attr("accept", ".jpg,.jpeg,.png,image/png,image/jpeg").style("visibility", "hidden").attr("id", "local-photo-files").on("change", function(d3_event) {
-        var files = d3_event.target.files;
-        if (files && files.length) {
-          photoList.select("ul").append("li").classed("placeholder", true).append("div");
-          dispatch14.call("change", this, files);
+      var initial = false;
+      if (!_fieldsArr) {
+        initial = true;
+        var presets = _mainPresetIndex;
+        _fieldsArr = [
+          uiField(context, presets.field("comment"), null, { show: true, revert: false }),
+          uiField(context, presets.field("source"), null, { show: true, revert: false }),
+          uiField(context, presets.field("hashtags"), null, { show: false, revert: false })
+        ];
+        _fieldsArr.forEach(function(field) {
+          field.on("change", function(t2, onInput) {
+            dispatch14.call("change", field, void 0, t2, onInput);
+          });
+        });
+      }
+      _fieldsArr.forEach(function(field) {
+        field.tags(_tags);
+      });
+      selection2.call(formFields.fieldsArr(_fieldsArr));
+      if (initial) {
+        var commentField = selection2.select(".form-field-comment textarea");
+        var commentNode = commentField.node();
+        if (commentNode) {
+          commentNode.focus();
+          commentNode.select();
         }
-        d3_event.target.value = null;
+        utilTriggerEvent(commentField, "blur");
+        var osm = context.connection();
+        if (osm) {
+          osm.userChangesets(function(err, changesets) {
+            if (err) return;
+            var comments = changesets.map(function(changeset) {
+              var comment = changeset.tags.comment;
+              return comment ? { title: comment, value: comment } : null;
+            }).filter(Boolean);
+            commentField.call(
+              commentCombo.data(utilArrayUniqBy(comments, "title"))
+            );
+          });
+        }
+      }
+      const warnings = [];
+      if (_tags.comment.match(/google/i)) {
+        warnings.push({
+          id: 'contains "google"',
+          msg: _t.append("commit.google_warning"),
+          link: _t("commit.google_warning_link")
+        });
+      }
+      const maxChars = context.maxCharsForTagValue();
+      const strLen = utilUnicodeCharsCount(utilCleanOsmString(_tags.comment, Number.POSITIVE_INFINITY));
+      if (strLen > maxChars || false) {
+        warnings.push({
+          id: "message too long",
+          msg: _t.append("commit.changeset_comment_length_warning", { maxChars })
+        });
+      }
+      var commentWarning = selection2.select(".form-field-comment").selectAll(".comment-warning").data(warnings, (d2) => d2.id);
+      commentWarning.exit().transition().duration(200).style("opacity", 0).remove();
+      var commentEnter = commentWarning.enter().insert("div", ".comment-warning").attr("class", "comment-warning field-warning").style("opacity", 0);
+      commentEnter.call(svgIcon("#iD-icon-alert", "inline")).append("span");
+      commentEnter.transition().duration(200).style("opacity", 1);
+      commentWarning.merge(commentEnter).selectAll("div > span").text("").each(function(d2) {
+        let selection3 = select_default2(this);
+        if (d2.link) {
+          selection3 = selection3.append("a").attr("target", "_blank").attr("href", d2.link);
+        }
+        selection3.call(d2.msg);
       });
-      instructionsSection.append("label").attr("for", "local-photo-files").classed("button", true).call(_t.append("local_photos.file.label"));
-      const photoList = modal.select(".modal-section.message-text .local-photos").append("div").append("div").classed("list-local-photos", true);
-      photoList.append("ul");
-      updatePhotoList(photoList.select("ul"));
-      context.layers().on("change", () => updatePhotoList(photoList.select("ul")));
     }
-    function updatePhotoList(container) {
-      var _a2;
-      function locationUnavailable(d2) {
-        return !(isArray_default(d2.loc) && isNumber_default(d2.loc[0]) && isNumber_default(d2.loc[1]));
-      }
-      container.selectAll("li.placeholder").remove();
-      let selection2 = container.selectAll("li").data((_a2 = photoLayer.getPhotos()) != null ? _a2 : [], (d2) => d2.id);
-      selection2.exit().remove();
-      const selectionEnter = selection2.enter().append("li");
-      selectionEnter.append("span").classed("filename", true);
-      selectionEnter.append("button").classed("form-field-button zoom-to-data", true).attr("title", _t("local_photos.zoom_single")).call(svgIcon("#iD-icon-framed-dot"));
-      selectionEnter.append("button").classed("form-field-button no-geolocation", true).call(svgIcon("#iD-icon-alert")).call(
-        uiTooltip().title(() => _t.append("local_photos.no_geolocation.tooltip")).placement("left")
-      );
-      selectionEnter.append("button").classed("form-field-button remove", true).attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
-      selection2 = selection2.merge(selectionEnter);
-      selection2.classed("invalid", locationUnavailable);
-      selection2.select("span.filename").text((d2) => d2.name).attr("title", (d2) => d2.name);
-      selection2.select("span.filename").on("click", (d3_event, d2) => {
-        photoLayer.openPhoto(d3_event, d2, false);
+    changesetEditor.tags = function(_2) {
+      if (!arguments.length) return _tags;
+      _tags = _2;
+      return changesetEditor;
+    };
+    changesetEditor.changesetID = function(_2) {
+      if (!arguments.length) return _changesetID;
+      if (_changesetID === _2) return changesetEditor;
+      _changesetID = _2;
+      _fieldsArr = null;
+      return changesetEditor;
+    };
+    return utilRebind(changesetEditor, dispatch14, "on");
+  }
+
+  // modules/ui/sections/changes.js
+  function uiSectionChanges(context) {
+    var _discardTags = {};
+    _mainFileFetcher.get("discarded").then(function(d2) {
+      _discardTags = d2;
+    }).catch(function() {
+    });
+    var section = uiSection("changes-list", context).label(function() {
+      var history = context.history();
+      var summary = history.difference().summary();
+      return _t.append("inspector.title_count", { title: _t("commit.changes"), count: summary.length });
+    }).disclosureContent(renderDisclosureContent);
+    function renderDisclosureContent(selection2) {
+      var history = context.history();
+      var summary = history.difference().summary();
+      var container = selection2.selectAll(".commit-section").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "commit-section");
+      containerEnter.append("ul").attr("class", "changeset-list");
+      container = containerEnter.merge(container);
+      var items = container.select("ul").selectAll("li").data(summary);
+      var itemsEnter = items.enter().append("li").attr("class", "change-item");
+      var buttons = itemsEnter.append("button").on("mouseover", mouseover).on("mouseout", mouseout).on("click", click);
+      buttons.each(function(d2) {
+        select_default2(this).call(svgIcon("#iD-icon-" + d2.entity.geometry(d2.graph), "pre-text " + d2.changeType));
       });
-      selection2.select("button.zoom-to-data").on("click", (d3_event, d2) => {
-        photoLayer.openPhoto(d3_event, d2, true);
+      buttons.append("span").attr("class", "change-type").html(function(d2) {
+        return _t.html("commit." + d2.changeType) + " ";
       });
-      selection2.select("button.remove").on("click", (d3_event, d2) => {
-        photoLayer.removePhoto(d2.id);
-        updatePhotoList(container);
+      buttons.append("strong").attr("class", "entity-type").text(function(d2) {
+        var matched = _mainPresetIndex.match(d2.entity, d2.graph);
+        return matched && matched.name() || utilDisplayType(d2.entity.id);
+      });
+      buttons.append("span").attr("class", "entity-name").text(function(d2) {
+        var name = utilDisplayName(d2.entity) || "", string = "";
+        if (name !== "") {
+          string += ":";
+        }
+        return string += " " + name;
       });
+      items = itemsEnter.merge(items);
+      var changeset = new osmChangeset().update({ id: void 0 });
+      var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
+      delete changeset.id;
+      var data = JXON.stringify(changeset.osmChangeJXON(changes));
+      var blob = new Blob([data], { type: "text/xml;charset=utf-8;" });
+      var fileName = "changes.osc";
+      var linkEnter = container.selectAll(".download-changes").data([0]).enter().append("a").attr("class", "download-changes");
+      linkEnter.attr("href", window.URL.createObjectURL(blob)).attr("download", fileName);
+      linkEnter.call(svgIcon("#iD-icon-load", "inline")).append("span").call(_t.append("commit.download_changes"));
+      function mouseover(d2) {
+        if (d2.entity) {
+          context.surface().selectAll(
+            utilEntityOrMemberSelector([d2.entity.id], context.graph())
+          ).classed("hover", true);
+        }
+      }
+      function mouseout() {
+        context.surface().selectAll(".hover").classed("hover", false);
+      }
+      function click(d3_event, change) {
+        if (change.changeType !== "deleted") {
+          var entity = change.entity;
+          context.map().zoomToEase(entity);
+          context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed("hover", true);
+        }
+      }
     }
-    return utilRebind(render, dispatch14, "on");
+    return section;
   }
 
-  // modules/ui/sections/photo_overlays.js
-  function uiSectionPhotoOverlays(context) {
-    var settingsLocalPhotos = uiSettingsLocalPhotos(context).on("change", localPhotosChanged);
-    var layers = context.layers();
-    var section = uiSection("photo-overlays", context).label(() => _t.append("photo_overlays.title")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".photo-overlay-container").data([0]);
-      container.enter().append("div").attr("class", "photo-overlay-container").merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter).call(drawLocalPhotos);
+  // modules/ui/commit.js
+  var readOnlyTags = [
+    /^changesets_count$/,
+    /^created_by$/,
+    /^ideditor:/,
+    /^imagery_used$/,
+    /^host$/,
+    /^locale$/,
+    /^warnings:/,
+    /^resolved:/,
+    /^closed:note$/,
+    /^closed:keepright$/,
+    /^closed:osmose:/
+  ];
+  var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
+  function uiCommit(context) {
+    var dispatch14 = dispatch_default("cancel");
+    var _userDetails2;
+    var _selection;
+    var changesetEditor = uiChangesetEditor(context).on("change", changeTags);
+    var rawTagEditor = uiSectionRawTagEditor("changeset-tag-editor", context).on("change", changeTags).readOnlyTags(readOnlyTags);
+    var commitChanges = uiSectionChanges(context);
+    var commitWarnings = uiCommitWarnings(context);
+    function commit(selection2) {
+      _selection = selection2;
+      if (!context.changeset) initChangeset();
+      loadDerivedChangesetTags();
+      selection2.call(render);
     }
-    function drawPhotoItems(selection2) {
-      var photoKeys = context.photos().overlayLayerIDs();
-      var photoLayers = layers.all().filter(function(obj) {
-        return photoKeys.indexOf(obj.id) !== -1;
-      });
-      var data = photoLayers.filter(function(obj) {
-        if (!obj.layer.supported())
-          return false;
-        if (layerEnabled(obj))
-          return true;
-        if (typeof obj.layer.validHere === "function") {
-          return obj.layer.validHere(context.map().extent(), context.map().zoom());
+    function initChangeset() {
+      var commentDate = +corePreferences("commentDate") || 0;
+      var currDate = Date.now();
+      var cutoff = 2 * 86400 * 1e3;
+      if (commentDate > currDate || currDate - commentDate > cutoff) {
+        corePreferences("comment", null);
+        corePreferences("hashtags", null);
+        corePreferences("source", null);
+      }
+      if (context.defaultChangesetComment()) {
+        corePreferences("comment", context.defaultChangesetComment());
+        corePreferences("commentDate", Date.now());
+      }
+      if (context.defaultChangesetSource()) {
+        corePreferences("source", context.defaultChangesetSource());
+        corePreferences("commentDate", Date.now());
+      }
+      if (context.defaultChangesetHashtags()) {
+        corePreferences("hashtags", context.defaultChangesetHashtags());
+        corePreferences("commentDate", Date.now());
+      }
+      var detected = utilDetect();
+      var tags = {
+        comment: corePreferences("comment") || "",
+        created_by: context.cleanTagValue("iD " + context.version),
+        host: context.cleanTagValue(detected.host),
+        locale: context.cleanTagValue(_mainLocalizer.localeCode())
+      };
+      findHashtags(tags, true);
+      var hashtags = corePreferences("hashtags");
+      if (hashtags) {
+        tags.hashtags = hashtags;
+      }
+      var source = corePreferences("source");
+      if (source) {
+        tags.source = source;
+      }
+      var photoOverlaysUsed = context.history().photoOverlaysUsed();
+      if (photoOverlaysUsed.length) {
+        var sources = (tags.source || "").split(";");
+        if (sources.indexOf("streetlevel imagery") === -1) {
+          sources.push("streetlevel imagery");
         }
-        return true;
-      });
-      function layerSupported(d2) {
-        return d2.layer && d2.layer.supported();
+        photoOverlaysUsed.forEach(function(photoOverlay) {
+          if (sources.indexOf(photoOverlay) === -1) {
+            sources.push(photoOverlay);
+          }
+        });
+        tags.source = context.cleanTagValue(sources.join(";"));
       }
-      function layerEnabled(d2) {
-        return layerSupported(d2) && d2.layer.enabled();
+      context.changeset = new osmChangeset({ tags });
+    }
+    function loadDerivedChangesetTags() {
+      var osm = context.connection();
+      if (!osm) return;
+      var tags = Object.assign({}, context.changeset.tags);
+      var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(";"));
+      tags.imagery_used = imageryUsed || "None";
+      var osmClosed = osm.getClosedIDs();
+      var itemType;
+      if (osmClosed.length) {
+        tags["closed:note"] = context.cleanTagValue(osmClosed.join(";"));
       }
-      function layerRendered(d2) {
-        var _a2, _b, _c;
-        return (_c = (_b = (_a2 = d2.layer).rendered) == null ? void 0 : _b.call(_a2, context.map().zoom())) != null ? _c : true;
+      if (services.keepRight) {
+        var krClosed = services.keepRight.getClosedIDs();
+        if (krClosed.length) {
+          tags["closed:keepright"] = context.cleanTagValue(krClosed.join(";"));
+        }
       }
-      var ul = selection2.selectAll(".layer-list-photos").data([0]);
-      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-photos").merge(ul);
-      var li = ul.selectAll(".list-item-photos").data(data);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", function(d2) {
-        var classes = "list-item-photos list-item-" + d2.id;
-        if (d2.id === "mapillary-signs" || d2.id === "mapillary-map-features") {
-          classes += " indented";
+      if (services.osmose) {
+        var osmoseClosed = services.osmose.getClosedCounts();
+        for (itemType in osmoseClosed) {
+          tags["closed:osmose:" + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
         }
-        return classes;
-      });
-      var labelEnter = liEnter.append("label").each(function(d2) {
-        var titleID;
-        if (d2.id === "mapillary-signs")
-          titleID = "mapillary.signs.tooltip";
-        else if (d2.id === "mapillary")
-          titleID = "mapillary_images.tooltip";
-        else if (d2.id === "kartaview")
-          titleID = "kartaview_images.tooltip";
-        else
-          titleID = d2.id.replace(/-/g, "_") + ".tooltip";
-        select_default2(this).call(
-          uiTooltip().title(() => {
-            if (!layerRendered(d2)) {
-              return _t.append("street_side.minzoom_tooltip");
-            } else {
-              return _t.append(titleID);
+      }
+      for (var key in tags) {
+        if (key.match(/(^warnings:)|(^resolved:)/)) {
+          delete tags[key];
+        }
+      }
+      function addIssueCounts(issues, prefix) {
+        var issuesByType = utilArrayGroupBy(issues, "type");
+        for (var issueType in issuesByType) {
+          var issuesOfType = issuesByType[issueType];
+          if (issuesOfType[0].subtype) {
+            var issuesBySubtype = utilArrayGroupBy(issuesOfType, "subtype");
+            for (var issueSubtype in issuesBySubtype) {
+              var issuesOfSubtype = issuesBySubtype[issueSubtype];
+              tags[prefix + ":" + issueType + ":" + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
             }
-          }).placement("top")
-        );
-      });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
-        toggleLayer(d2.id);
-      });
-      labelEnter.append("span").html(function(d2) {
-        var id2 = d2.id;
-        if (id2 === "mapillary-signs")
-          id2 = "photo_overlays.traffic_signs";
-        return _t.html(id2.replace(/-/g, "_") + ".title");
-      });
-      li.merge(liEnter).classed("active", layerEnabled).selectAll("input").property("disabled", (d2) => !layerRendered(d2)).property("checked", layerEnabled);
-    }
-    function drawPhotoTypeItems(selection2) {
-      var data = context.photos().allPhotoTypes();
-      function typeEnabled(d2) {
-        return context.photos().showsPhotoType(d2);
+          } else {
+            tags[prefix + ":" + issueType] = context.cleanTagValue(issuesOfType.length.toString());
+          }
+        }
       }
-      var ul = selection2.selectAll(".layer-list-photo-types").data([0]);
-      ul.exit().remove();
-      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-photo-types").merge(ul);
-      var li = ul.selectAll(".list-item-photo-types").data(context.photos().shouldFilterByPhotoType() ? data : []);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", function(d2) {
-        return "list-item-photo-types list-item-" + d2;
-      });
-      var labelEnter = liEnter.append("label").each(function(d2) {
-        select_default2(this).call(
-          uiTooltip().title(() => _t.append("photo_overlays.photo_type." + d2 + ".tooltip")).placement("top")
-        );
-      });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
-        context.photos().togglePhotoType(d2);
-      });
-      labelEnter.append("span").html(function(d2) {
-        return _t.html("photo_overlays.photo_type." + d2 + ".title");
+      var warnings = context.validator().getIssuesBySeverity({ what: "edited", where: "all", includeIgnored: true, includeDisabledRules: true }).warning.filter(function(issue) {
+        return issue.type !== "help_request";
       });
-      li.merge(liEnter).classed("active", typeEnabled).selectAll("input").property("checked", typeEnabled);
+      addIssueCounts(warnings, "warnings");
+      var resolvedIssues = context.validator().getResolvedIssues();
+      addIssueCounts(resolvedIssues, "resolved");
+      context.changeset = context.changeset.update({ tags });
     }
-    function drawDateFilter(selection2) {
-      var data = context.photos().dateFilters();
-      function filterEnabled(d2) {
-        return context.photos().dateFilterValue(d2);
+    function render(selection2) {
+      var osm = context.connection();
+      if (!osm) return;
+      var header = selection2.selectAll(".header").data([0]);
+      var headerTitle = header.enter().append("div").attr("class", "header fillL");
+      headerTitle.append("div").append("h2").call(_t.append("commit.title"));
+      headerTitle.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
+        dispatch14.call("cancel", this);
+      }).call(svgIcon("#iD-icon-close"));
+      var body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      var changesetSection = body.selectAll(".changeset-editor").data([0]);
+      changesetSection = changesetSection.enter().append("div").attr("class", "modal-section changeset-editor").merge(changesetSection);
+      changesetSection.call(
+        changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)
+      );
+      body.call(commitWarnings);
+      var saveSection = body.selectAll(".save-section").data([0]);
+      saveSection = saveSection.enter().append("div").attr("class", "modal-section save-section fillL").merge(saveSection);
+      var prose = saveSection.selectAll(".commit-info").data([0]);
+      if (prose.enter().size()) {
+        _userDetails2 = null;
       }
-      var ul = selection2.selectAll(".layer-list-date-filter").data([0]);
-      ul.exit().remove();
-      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-date-filter").merge(ul);
-      var li = ul.selectAll(".list-item-date-filter").data(context.photos().shouldFilterByDate() ? data : []);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", "list-item-date-filter");
-      var labelEnter = liEnter.append("label").each(function(d2) {
-        select_default2(this).call(
-          uiTooltip().title(() => _t.append("photo_overlays.date_filter." + d2 + ".tooltip")).placement("top")
-        );
+      prose = prose.enter().append("p").attr("class", "commit-info").call(_t.append("commit.upload_explanation")).merge(prose);
+      osm.userDetails(function(err, user) {
+        if (err) return;
+        if (_userDetails2 === user) return;
+        _userDetails2 = user;
+        var userLink = select_default2(document.createElement("div"));
+        if (user.image_url) {
+          userLink.append("img").attr("src", user.image_url).attr("class", "icon pre-text user-icon");
+        }
+        userLink.append("a").attr("class", "user-info").text(user.display_name).attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
+        prose.html(_t.html("commit.upload_explanation_with_user", { user: { html: userLink.html() } }));
       });
-      labelEnter.append("span").each(function(d2) {
-        _t.append("photo_overlays.date_filter." + d2 + ".title")(select_default2(this));
+      var requestReview = saveSection.selectAll(".request-review").data([0]);
+      var requestReviewEnter = requestReview.enter().append("div").attr("class", "request-review");
+      var requestReviewDomId = utilUniqueDomId("commit-input-request-review");
+      var labelEnter = requestReviewEnter.append("label").attr("for", requestReviewDomId);
+      if (!labelEnter.empty()) {
+        labelEnter.call(uiTooltip().title(() => _t.append("commit.request_review_info")).placement("top"));
+      }
+      labelEnter.append("input").attr("type", "checkbox").attr("id", requestReviewDomId);
+      labelEnter.append("span").call(_t.append("commit.request_review"));
+      requestReview = requestReview.merge(requestReviewEnter);
+      var requestReviewInput = requestReview.selectAll("input").property("checked", isReviewRequested(context.changeset.tags)).on("change", toggleRequestReview);
+      var buttonSection = saveSection.selectAll(".buttons").data([0]);
+      var buttonEnter = buttonSection.enter().append("div").attr("class", "buttons fillL");
+      buttonEnter.append("button").attr("class", "secondary-action button cancel-button").append("span").attr("class", "label").call(_t.append("commit.cancel"));
+      var uploadButton = buttonEnter.append("button").attr("class", "action button save-button");
+      uploadButton.append("span").attr("class", "label").call(_t.append("commit.save"));
+      var uploadBlockerTooltipText = getUploadBlockerMessage();
+      buttonSection = buttonSection.merge(buttonEnter);
+      buttonSection.selectAll(".cancel-button").on("click.cancel", function() {
+        dispatch14.call("cancel", this);
       });
-      labelEnter.append("input").attr("type", "date").attr("class", "list-item-input").attr("placeholder", _t("units.year_month_day")).call(utilNoAuto).each(function(d2) {
-        utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d2) || "");
-      }).on("change", function(d3_event, d2) {
-        var value = utilGetSetValue(select_default2(this)).trim();
-        context.photos().setDateFilter(d2, value, true);
-        li.selectAll("input").each(function(d4) {
-          utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d4) || "");
-        });
+      buttonSection.selectAll(".save-button").classed("disabled", uploadBlockerTooltipText !== null).on("click.save", function() {
+        if (!select_default2(this).classed("disabled")) {
+          this.blur();
+          for (var key in context.changeset.tags) {
+            if (!key) delete context.changeset.tags[key];
+          }
+          context.uploader().save(context.changeset);
+        }
       });
-      li = li.merge(liEnter).classed("active", filterEnabled);
-    }
-    function drawUsernameFilter(selection2) {
-      function filterEnabled() {
-        return context.photos().usernames();
+      uiTooltip().destroyAny(buttonSection.selectAll(".save-button"));
+      if (uploadBlockerTooltipText) {
+        buttonSection.selectAll(".save-button").call(uiTooltip().title(() => uploadBlockerTooltipText).placement("top"));
       }
-      var ul = selection2.selectAll(".layer-list-username-filter").data([0]);
-      ul.exit().remove();
-      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-username-filter").merge(ul);
-      var li = ul.selectAll(".list-item-username-filter").data(context.photos().shouldFilterByUsername() ? ["username-filter"] : []);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", "list-item-username-filter");
-      var labelEnter = liEnter.append("label").each(function() {
-        select_default2(this).call(
-          uiTooltip().title(() => _t.append("photo_overlays.username_filter.tooltip")).placement("top")
+      var tagSection = body.selectAll(".tag-section.raw-tag-editor").data([0]);
+      tagSection = tagSection.enter().append("div").attr("class", "modal-section tag-section raw-tag-editor").merge(tagSection);
+      tagSection.call(
+        rawTagEditor.tags(Object.assign({}, context.changeset.tags)).render
+      );
+      var changesSection = body.selectAll(".commit-changes-section").data([0]);
+      changesSection = changesSection.enter().append("div").attr("class", "modal-section commit-changes-section").merge(changesSection);
+      changesSection.call(commitChanges.render);
+      function toggleRequestReview() {
+        var rr = requestReviewInput.property("checked");
+        updateChangeset({ review_requested: rr ? "yes" : void 0 });
+        tagSection.call(
+          rawTagEditor.tags(Object.assign({}, context.changeset.tags)).render
         );
-      });
-      labelEnter.append("span").call(_t.append("photo_overlays.username_filter.title"));
-      labelEnter.append("input").attr("type", "text").attr("class", "list-item-input").call(utilNoAuto).property("value", usernameValue).on("change", function() {
-        var value = select_default2(this).property("value");
-        context.photos().setUsernameFilter(value, true);
-        select_default2(this).property("value", usernameValue);
-      });
-      li.merge(liEnter).classed("active", filterEnabled);
-      function usernameValue() {
-        var usernames = context.photos().usernames();
-        if (usernames)
-          return usernames.join("; ");
-        return usernames;
       }
     }
-    function toggleLayer(which) {
-      setLayer(which, !showsLayer(which));
-    }
-    function showsLayer(which) {
-      var layer = layers.layer(which);
-      if (layer) {
-        return layer.enabled();
+    function getUploadBlockerMessage() {
+      var errors = context.validator().getIssuesBySeverity({ what: "edited", where: "all" }).error;
+      if (errors.length) {
+        return _t.append("commit.outstanding_errors_message", { count: errors.length });
+      } else {
+        var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
+        if (!hasChangesetComment) {
+          return _t.append("commit.comment_needed_message");
+        }
       }
-      return false;
+      return null;
     }
-    function setLayer(which, enabled) {
-      var layer = layers.layer(which);
-      if (layer) {
-        layer.enabled(enabled);
+    function changeTags(_2, changed, onInput) {
+      if (changed.hasOwnProperty("comment")) {
+        if (changed.comment === void 0) {
+          changed.comment = "";
+        }
+        if (!onInput) {
+          corePreferences("comment", changed.comment);
+          corePreferences("commentDate", Date.now());
+        }
+      }
+      if (changed.hasOwnProperty("source")) {
+        if (changed.source === void 0) {
+          corePreferences("source", null);
+        } else if (!onInput) {
+          corePreferences("source", changed.source);
+          corePreferences("commentDate", Date.now());
+        }
+      }
+      updateChangeset(changed, onInput);
+      if (_selection) {
+        _selection.call(render);
       }
     }
-    function drawLocalPhotos(selection2) {
-      var photoLayer = layers.layer("local-photos");
-      var hasData = photoLayer && photoLayer.hasData();
-      var showsData = hasData && photoLayer.enabled();
-      var ul = selection2.selectAll(".layer-list-local-photos").data(photoLayer ? [0] : []);
-      ul.exit().remove();
-      var ulEnter = ul.enter().append("ul").attr("class", "layer-list layer-list-local-photos");
-      var localPhotosEnter = ulEnter.append("li").attr("class", "list-item-local-photos");
-      var localPhotosLabelEnter = localPhotosEnter.append("label").call(uiTooltip().title(() => _t.append("local_photos.tooltip")));
-      localPhotosLabelEnter.append("input").attr("type", "checkbox").on("change", function() {
-        toggleLayer("local-photos");
-      });
-      localPhotosLabelEnter.call(_t.append("local_photos.header"));
-      localPhotosEnter.append("button").attr("class", "open-data-options").call(
-        uiTooltip().title(() => _t.append("local_photos.tooltip_edit")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        editLocalPhotos();
-      }).call(svgIcon("#iD-icon-more"));
-      localPhotosEnter.append("button").attr("class", "zoom-to-data").call(
-        uiTooltip().title(() => _t.append("local_photos.zoom")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).on("click", function(d3_event) {
-        if (select_default2(this).classed("disabled"))
-          return;
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        photoLayer.fitZoom();
-      }).call(svgIcon("#iD-icon-framed-dot", "monochrome"));
-      ul = ul.merge(ulEnter);
-      ul.selectAll(".list-item-local-photos").classed("active", showsData).selectAll("label").classed("deemphasize", !hasData).selectAll("input").property("disabled", !hasData).property("checked", showsData);
-      ul.selectAll("button.zoom-to-data").classed("disabled", !hasData);
-    }
-    function editLocalPhotos() {
-      context.container().call(settingsLocalPhotos);
-    }
-    function localPhotosChanged(d2) {
-      var localPhotosLayer = layers.layer("local-photos");
-      localPhotosLayer.fileList(d2);
-    }
-    context.layers().on("change.uiSectionPhotoOverlays", section.reRender);
-    context.photos().on("change.uiSectionPhotoOverlays", section.reRender);
-    context.map().on(
-      "move.photo_overlays",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
-  }
-
-  // modules/ui/panes/map_data.js
-  function uiPaneMapData(context) {
-    var mapDataPane = uiPane("map-data", context).key(_t("map_data.key")).label(_t.append("map_data.title")).description(_t.append("map_data.description")).iconName("iD-icon-data").sections([
-      uiSectionDataLayers(context),
-      uiSectionPhotoOverlays(context),
-      uiSectionMapStyleOptions(context),
-      uiSectionMapFeatures(context)
-    ]);
-    return mapDataPane;
-  }
-
-  // modules/ui/panes/preferences.js
-  function uiPanePreferences(context) {
-    let preferencesPane = uiPane("preferences", context).key(_t("preferences.key")).label(_t.append("preferences.title")).description(_t.append("preferences.description")).iconName("fas-user-cog").sections([
-      uiSectionPrivacy(context)
-    ]);
-    return preferencesPane;
-  }
-
-  // modules/ui/init.js
-  function uiInit(context) {
-    var _initCounter = 0;
-    var _needWidth = {};
-    var _lastPointerType;
-    function render(container) {
-      container.on("click.ui", function(d3_event) {
-        if (d3_event.button !== 0)
-          return;
-        if (!d3_event.composedPath)
-          return;
-        var isOkayTarget = d3_event.composedPath().some(function(node) {
-          return node.nodeType === 1 && // clicking <input> focuses it and/or changes a value
-          (node.nodeName === "INPUT" || // clicking <label> affects its <input> by default
-          node.nodeName === "LABEL" || // clicking <a> opens a hyperlink by default
-          node.nodeName === "A");
-        });
-        if (isOkayTarget)
-          return;
-        d3_event.preventDefault();
-      });
-      var detected = utilDetect();
-      if ("GestureEvent" in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
-      // but we only need to do this on desktop Safari anyway. – #7694
-      !detected.isMobileWebKit) {
-        container.on("gesturestart.ui gesturechange.ui gestureend.ui", function(d3_event) {
-          d3_event.preventDefault();
-        });
+    function findHashtags(tags, commentOnly) {
+      var detectedHashtags = commentHashtags();
+      if (detectedHashtags.length) {
+        corePreferences("hashtags", null);
       }
-      if ("PointerEvent" in window) {
-        select_default2(window).on("pointerdown.ui pointerup.ui", function(d3_event) {
-          var pointerType = d3_event.pointerType || "mouse";
-          if (_lastPointerType !== pointerType) {
-            _lastPointerType = pointerType;
-            container.attr("pointer", pointerType);
-          }
-        }, true);
-      } else {
-        _lastPointerType = "mouse";
-        container.attr("pointer", "mouse");
+      if (!detectedHashtags.length || !commentOnly) {
+        detectedHashtags = detectedHashtags.concat(hashtagHashtags());
       }
-      container.attr("lang", _mainLocalizer.localeCode()).attr("dir", _mainLocalizer.textDirection());
-      container.call(uiFullScreen(context));
-      var map2 = context.map();
-      map2.redrawEnable(false);
-      map2.on("hitMinZoom.ui", function() {
-        ui.flash.iconName("#iD-icon-no").label(_t.append("cannot_zoom"))();
-      });
-      container.append("svg").attr("id", "ideditor-defs").call(ui.svgDefs);
-      container.append("div").attr("class", "sidebar").call(ui.sidebar);
-      var content = container.append("div").attr("class", "main-content active");
-      content.append("div").attr("class", "top-toolbar-wrap").append("div").attr("class", "top-toolbar fillD").call(uiTopToolbar(context));
-      content.append("div").attr("class", "main-map").attr("dir", "ltr").call(map2);
-      var overMap = content.append("div").attr("class", "over-map");
-      overMap.append("div").attr("class", "select-trap").text("t");
-      overMap.call(uiMapInMap(context)).call(uiNotice(context));
-      overMap.append("div").attr("class", "spinner").call(uiSpinner(context));
-      var controlsWrap = overMap.append("div").attr("class", "map-controls-wrap");
-      var controls = controlsWrap.append("div").attr("class", "map-controls");
-      controls.append("div").attr("class", "map-control zoombuttons").call(uiZoom(context));
-      controls.append("div").attr("class", "map-control zoom-to-selection-control").call(uiZoomToSelection(context));
-      controls.append("div").attr("class", "map-control geolocate-control").call(uiGeolocate(context));
-      controlsWrap.on("wheel.mapControls", function(d3_event) {
-        if (!d3_event.deltaX) {
-          controlsWrap.node().scrollTop += d3_event.deltaY;
+      var allLowerCase = /* @__PURE__ */ new Set();
+      return detectedHashtags.filter(function(hashtag) {
+        var lowerCase = hashtag.toLowerCase();
+        if (!allLowerCase.has(lowerCase)) {
+          allLowerCase.add(lowerCase);
+          return true;
         }
+        return false;
       });
-      var panes = overMap.append("div").attr("class", "map-panes");
-      var uiPanes = [
-        uiPaneBackground(context),
-        uiPaneMapData(context),
-        uiPaneIssues(context),
-        uiPanePreferences(context),
-        uiPaneHelp(context)
-      ];
-      uiPanes.forEach(function(pane) {
-        controls.append("div").attr("class", "map-control map-pane-control " + pane.id + "-control").call(pane.renderToggleButton);
-        panes.call(pane.renderPane);
-      });
-      ui.info = uiInfo(context);
-      overMap.call(ui.info);
-      overMap.append("div").attr("class", "photoviewer").classed("al", true).classed("hide", true).call(ui.photoviewer);
-      overMap.append("div").attr("class", "attribution-wrap").attr("dir", "ltr").call(uiAttribution(context));
-      var about = content.append("div").attr("class", "map-footer");
-      about.append("div").attr("class", "api-status").call(uiStatus(context));
-      var footer = about.append("div").attr("class", "map-footer-bar fillD");
-      footer.append("div").attr("class", "flash-wrap footer-hide");
-      var footerWrap = footer.append("div").attr("class", "main-footer-wrap footer-show");
-      footerWrap.append("div").attr("class", "scale-block").call(uiScale(context));
-      var aboutList = footerWrap.append("div").attr("class", "info-block").append("ul").attr("class", "map-footer-list");
-      aboutList.append("li").attr("class", "user-list").call(uiContributors(context));
-      var apiConnections = context.connection().apiConnections();
-      if (apiConnections && apiConnections.length > 1) {
-        aboutList.append("li").attr("class", "source-switch").call(
-          uiSourceSwitch(context).keys(apiConnections)
-        );
-      }
-      aboutList.append("li").attr("class", "issues-info").call(uiIssuesInfo(context));
-      aboutList.append("li").attr("class", "feature-warning").call(uiFeatureInfo(context));
-      var issueLinks = aboutList.append("li");
-      issueLinks.append("a").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD/issues").attr("aria-label", _t("report_a_bug")).call(svgIcon("#iD-icon-bug", "light")).call(uiTooltip().title(() => _t.append("report_a_bug")).placement("top"));
-      issueLinks.append("a").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD/blob/develop/CONTRIBUTING.md#translating").attr("aria-label", _t("help_translate")).call(svgIcon("#iD-icon-translate", "light")).call(uiTooltip().title(() => _t.append("help_translate")).placement("top"));
-      aboutList.append("li").attr("class", "version").call(uiVersion(context));
-      if (!context.embed()) {
-        aboutList.call(uiAccount(context));
+      function commentHashtags() {
+        var matches = (tags.comment || "").replace(/http\S*/g, "").match(hashtagRegex);
+        return matches || [];
       }
-      ui.onResize();
-      map2.redrawEnable(true);
-      ui.hash = behaviorHash(context);
-      ui.hash();
-      if (!ui.hash.hadLocation) {
-        map2.centerZoom([0, 0], 2);
+      function hashtagHashtags() {
+        var matches = (tags.hashtags || "").split(/[,;\s]+/).map(function(s2) {
+          if (s2[0] !== "#") {
+            s2 = "#" + s2;
+          }
+          var matched = s2.match(hashtagRegex);
+          return matched && matched[0];
+        }).filter(Boolean);
+        return matches || [];
       }
-      window.onbeforeunload = function() {
-        return context.save();
-      };
-      window.onunload = function() {
-        context.history().unlock();
-      };
-      select_default2(window).on("resize.editor", function() {
-        ui.onResize();
-      });
-      var panPixels = 80;
-      context.keybinding().on("\u232B", function(d3_event) {
-        d3_event.preventDefault();
-      }).on([_t("sidebar.key"), "`", "\xB2", "@"], ui.sidebar.toggle).on("\u2190", pan([panPixels, 0])).on("\u2191", pan([0, panPixels])).on("\u2192", pan([-panPixels, 0])).on("\u2193", pan([0, -panPixels])).on(uiCmd("\u2325\u2190"), pan([map2.dimensions()[0], 0])).on(uiCmd("\u2325\u2191"), pan([0, map2.dimensions()[1]])).on(uiCmd("\u2325\u2192"), pan([-map2.dimensions()[0], 0])).on(uiCmd("\u2325\u2193"), pan([0, -map2.dimensions()[1]])).on(uiCmd("\u2318" + _t("background.key")), function quickSwitch(d3_event) {
-        if (d3_event) {
-          d3_event.stopImmediatePropagation();
-          d3_event.preventDefault();
+    }
+    function isReviewRequested(tags) {
+      var rr = tags.review_requested;
+      if (rr === void 0) return false;
+      rr = rr.trim().toLowerCase();
+      return !(rr === "" || rr === "no");
+    }
+    function updateChangeset(changed, onInput) {
+      var tags = Object.assign({}, context.changeset.tags);
+      Object.keys(changed).forEach(function(k2) {
+        var v2 = changed[k2];
+        k2 = context.cleanTagKey(k2);
+        if (readOnlyTags.indexOf(k2) !== -1) return;
+        if (v2 === void 0) {
+          delete tags[k2];
+        } else if (onInput) {
+          tags[k2] = v2;
+        } else {
+          tags[k2] = context.cleanTagValue(v2);
         }
-        var previousBackground = context.background().findSource(corePreferences("background-last-used-toggle"));
-        if (previousBackground) {
-          var currentBackground = context.background().baseLayerSource();
-          corePreferences("background-last-used-toggle", currentBackground.id);
-          corePreferences("background-last-used", previousBackground.id);
-          context.background().baseLayerSource(previousBackground);
+      });
+      if (!onInput) {
+        var commentOnly = changed.hasOwnProperty("comment") && changed.comment !== "";
+        var arr = findHashtags(tags, commentOnly);
+        if (arr.length) {
+          tags.hashtags = context.cleanTagValue(arr.join(";"));
+          corePreferences("hashtags", tags.hashtags);
+        } else {
+          delete tags.hashtags;
+          corePreferences("hashtags", null);
         }
-      }).on(_t("area_fill.wireframe.key"), function toggleWireframe(d3_event) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        context.map().toggleWireframe();
-      }).on(uiCmd("\u2325" + _t("area_fill.wireframe.key")), function toggleOsmData(d3_event) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        var mode = context.mode();
-        if (mode && /^draw/.test(mode.id))
-          return;
-        var layer = context.layers().layer("osm");
-        if (layer) {
-          layer.enabled(!layer.enabled());
-          if (!layer.enabled()) {
-            context.enter(modeBrowse(context));
+      }
+      if (_userDetails2 && _userDetails2.changesets_count !== void 0) {
+        var changesetsCount = parseInt(_userDetails2.changesets_count, 10) + 1;
+        tags.changesets_count = String(changesetsCount);
+        if (changesetsCount <= 100) {
+          var s2;
+          s2 = corePreferences("walkthrough_completed");
+          if (s2) {
+            tags["ideditor:walkthrough_completed"] = s2;
+          }
+          s2 = corePreferences("walkthrough_progress");
+          if (s2) {
+            tags["ideditor:walkthrough_progress"] = s2;
+          }
+          s2 = corePreferences("walkthrough_started");
+          if (s2) {
+            tags["ideditor:walkthrough_started"] = s2;
           }
         }
-      }).on(_t("map_data.highlight_edits.key"), function toggleHighlightEdited(d3_event) {
+      } else {
+        delete tags.changesets_count;
+      }
+      if (!(0, import_fast_deep_equal10.default)(context.changeset.tags, tags)) {
+        context.changeset = context.changeset.update({ tags });
+      }
+    }
+    commit.reset = function() {
+      context.changeset = null;
+    };
+    return utilRebind(commit, dispatch14, "on");
+  }
+
+  // modules/modes/save.js
+  function modeSave(context) {
+    var mode = { id: "save" };
+    var keybinding = utilKeybinding("modeSave");
+    var commit = uiCommit(context).on("cancel", cancel);
+    var _conflictsUi;
+    var _location;
+    var _success;
+    var uploader = context.uploader().on("saveStarted.modeSave", function() {
+      keybindingOff();
+    }).on("willAttemptUpload.modeSave", prepareForSuccess).on("progressChanged.modeSave", showProgress).on("resultNoChanges.modeSave", function() {
+      cancel();
+    }).on("resultErrors.modeSave", showErrors).on("resultConflicts.modeSave", showConflicts).on("resultSuccess.modeSave", showSuccess);
+    function cancel() {
+      context.enter(modeBrowse(context));
+    }
+    function showProgress(num, total) {
+      var modal = context.container().select(".loading-modal .modal-section");
+      var progress = modal.selectAll(".progress").data([0]);
+      progress.enter().append("div").attr("class", "progress").merge(progress).text(_t("save.conflict_progress", { num, total }));
+    }
+    function showConflicts(changeset, conflicts, origChanges) {
+      var selection2 = context.container().select(".sidebar").append("div").attr("class", "sidebar-component");
+      context.container().selectAll(".main-content").classed("active", true).classed("inactive", false);
+      _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on("cancel", function() {
+        context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
+        selection2.remove();
+        keybindingOn();
+        uploader.cancelConflictResolution();
+      }).on("save", function() {
+        context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
+        selection2.remove();
+        uploader.processResolvedConflicts(changeset);
+      });
+      selection2.call(_conflictsUi);
+    }
+    function showErrors(errors) {
+      keybindingOn();
+      var selection2 = uiConfirm(context.container());
+      selection2.select(".modal-section.header").append("h3").text(_t("save.error"));
+      addErrors(selection2, errors);
+      selection2.okButton();
+    }
+    function addErrors(selection2, data) {
+      var message = selection2.select(".modal-section.message-text");
+      var items = message.selectAll(".error-container").data(data);
+      var enter = items.enter().append("div").attr("class", "error-container");
+      enter.append("a").attr("class", "error-description").attr("href", "#").classed("hide-toggle", true).text(function(d2) {
+        return d2.msg || _t("save.unknown_error_details");
+      }).on("click", function(d3_event) {
         d3_event.preventDefault();
-        context.map().toggleHighlightEdited();
+        var error = select_default2(this);
+        var detail = select_default2(this.nextElementSibling);
+        var exp2 = error.classed("expanded");
+        detail.style("display", exp2 ? "none" : "block");
+        error.classed("expanded", !exp2);
       });
-      context.on("enter.editor", function(entered) {
-        container.classed("mode-" + entered.id, true);
-      }).on("exit.editor", function(exited) {
-        container.classed("mode-" + exited.id, false);
+      var details = enter.append("div").attr("class", "error-detail-container").style("display", "none");
+      details.append("ul").attr("class", "error-detail-list").selectAll("li").data(function(d2) {
+        return d2.details || [];
+      }).enter().append("li").attr("class", "error-detail-item").text(function(d2) {
+        return d2;
       });
-      context.enter(modeBrowse(context));
-      if (!_initCounter++) {
-        if (!ui.hash.startWalkthrough) {
-          context.container().call(uiSplash(context)).call(uiRestore(context));
-        }
-        context.container().call(ui.shortcuts);
+      items.exit().remove();
+    }
+    function showSuccess(changeset) {
+      commit.reset();
+      var ui = _success.changeset(changeset).location(_location).on("cancel", function() {
+        context.ui().sidebar.hide();
+      });
+      context.enter(modeBrowse(context).sidebar(ui));
+    }
+    function keybindingOn() {
+      select_default2(document).call(keybinding.on("\u238B", cancel, true));
+    }
+    function keybindingOff() {
+      select_default2(document).call(keybinding.unbind);
+    }
+    function prepareForSuccess() {
+      _success = uiSuccess(context);
+      _location = null;
+      if (!services.geocoder) return;
+      services.geocoder.reverse(context.map().center(), function(err, result) {
+        if (err || !result || !result.address) return;
+        var addr = result.address;
+        var place = addr && (addr.town || addr.city || addr.county) || "";
+        var region = addr && (addr.state || addr.country) || "";
+        var separator = place && region ? _t("success.thank_you_where.separator") : "";
+        _location = _t(
+          "success.thank_you_where.format",
+          { place, separator, region }
+        );
+      });
+    }
+    mode.selectedIDs = function() {
+      return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
+    };
+    mode.enter = function() {
+      context.ui().sidebar.expand();
+      function done() {
+        context.ui().sidebar.show(commit);
       }
+      keybindingOn();
+      context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
       var osm = context.connection();
-      var auth = uiLoading(context).message(_t.html("loading_auth")).blocking(true);
-      if (osm && auth) {
-        osm.on("authLoading.ui", function() {
-          context.container().call(auth);
-        }).on("authDone.ui", function() {
-          auth.close();
-        });
-      }
-      _initCounter++;
-      if (ui.hash.startWalkthrough) {
-        ui.hash.startWalkthrough = false;
-        context.container().call(uiIntro(context));
+      if (!osm) {
+        cancel();
+        return;
       }
-      function pan(d2) {
-        return function(d3_event) {
-          if (d3_event.shiftKey)
-            return;
-          if (context.container().select(".combobox").size())
-            return;
-          d3_event.preventDefault();
-          context.map().pan(d2, 100);
-        };
+      if (osm.authenticated()) {
+        done();
+      } else {
+        osm.authenticate(function(err) {
+          if (err) {
+            cancel();
+          } else {
+            done();
+          }
+        });
       }
-    }
-    let ui = {};
-    let _loadPromise;
-    ui.ensureLoaded = () => {
-      if (_loadPromise)
-        return _loadPromise;
-      return _loadPromise = Promise.all([
-        // must have strings and presets before loading the UI
-        _mainLocalizer.ensureLoaded(),
-        _mainPresetIndex.ensureLoaded()
-      ]).then(() => {
-        if (!context.container().empty())
-          render(context.container());
-      }).catch((err) => console.error(err));
-    };
-    ui.restart = function() {
-      context.keybinding().clear();
-      _loadPromise = null;
-      context.container().selectAll("*").remove();
-      ui.ensureLoaded();
     };
-    ui.lastPointerType = function() {
-      return _lastPointerType;
+    mode.exit = function() {
+      keybindingOff();
+      context.container().selectAll(".main-content").classed("active", true).classed("inactive", false);
+      context.ui().sidebar.hide();
     };
-    ui.svgDefs = svgDefs(context);
-    ui.flash = uiFlash(context);
-    ui.sidebar = uiSidebar(context);
-    ui.photoviewer = uiPhotoviewer(context);
-    ui.shortcuts = uiShortcuts(context);
-    ui.onResize = function(withPan) {
-      var map2 = context.map();
-      var mapDimensions = utilGetDimensions(context.container().select(".main-content"), true);
-      utilGetDimensions(context.container().select(".sidebar"), true);
-      if (withPan !== void 0) {
-        map2.redrawEnable(false);
-        map2.pan(withPan);
-        map2.redrawEnable(true);
-      }
-      map2.dimensions(mapDimensions);
-      ui.photoviewer.onMapResize();
-      ui.checkOverflow(".top-toolbar");
-      ui.checkOverflow(".map-footer-bar");
-      var resizeWindowEvent = document.createEvent("Event");
-      resizeWindowEvent.initEvent("resizeWindow", true, true);
-      document.dispatchEvent(resizeWindowEvent);
+    return mode;
+  }
+
+  // modules/modes/select_error.js
+  function modeSelectError(context, selectedErrorID, selectedErrorService) {
+    var mode = {
+      id: "select-error",
+      button: "browse"
     };
-    ui.checkOverflow = function(selector, reset) {
-      if (reset) {
-        delete _needWidth[selector];
+    var keybinding = utilKeybinding("select-error");
+    var errorService = services[selectedErrorService];
+    var errorEditor;
+    switch (selectedErrorService) {
+      case "keepRight":
+        errorEditor = uiKeepRightEditor(context).on("change", function() {
+          context.map().pan([0, 0]);
+          var error = checkSelectedID();
+          if (!error) return;
+          context.ui().sidebar.show(errorEditor.error(error));
+        });
+        break;
+      case "osmose":
+        errorEditor = uiOsmoseEditor(context).on("change", function() {
+          context.map().pan([0, 0]);
+          var error = checkSelectedID();
+          if (!error) return;
+          context.ui().sidebar.show(errorEditor.error(error));
+        });
+        break;
+    }
+    var behaviors = [
+      behaviorBreathe(context),
+      behaviorHover(context),
+      behaviorSelect(context),
+      behaviorLasso(context),
+      modeDragNode(context).behavior,
+      modeDragNote(context).behavior
+    ];
+    function checkSelectedID() {
+      if (!errorService) return;
+      var error = errorService.getError(selectedErrorID);
+      if (!error) {
+        context.enter(modeBrowse(context));
       }
-      var selection2 = context.container().select(selector);
-      if (selection2.empty())
-        return;
-      var scrollWidth = selection2.property("scrollWidth");
-      var clientWidth = selection2.property("clientWidth");
-      var needed = _needWidth[selector] || scrollWidth;
-      if (scrollWidth > clientWidth) {
-        selection2.classed("narrow", true);
-        if (!_needWidth[selector]) {
-          _needWidth[selector] = scrollWidth;
-        }
-      } else if (scrollWidth >= needed) {
-        selection2.classed("narrow", false);
+      return error;
+    }
+    mode.zoomToSelected = function() {
+      if (!errorService) return;
+      var error = errorService.getError(selectedErrorID);
+      if (error) {
+        context.map().centerZoomEase(error.loc, 20);
       }
     };
-    ui.togglePanes = function(showPane) {
-      var hidePanes = context.container().selectAll(".map-pane.shown");
-      var side = _mainLocalizer.textDirection() === "ltr" ? "right" : "left";
-      hidePanes.classed("shown", false).classed("hide", true);
-      context.container().selectAll(".map-pane-control button").classed("active", false);
-      if (showPane) {
-        hidePanes.classed("shown", false).classed("hide", true).style(side, "-500px");
-        context.container().selectAll("." + showPane.attr("pane") + "-control button").classed("active", true);
-        showPane.classed("shown", true).classed("hide", false);
-        if (hidePanes.empty()) {
-          showPane.style(side, "-500px").transition().duration(200).style(side, "0px");
+    mode.enter = function() {
+      var error = checkSelectedID();
+      if (!error) return;
+      behaviors.forEach(context.install);
+      keybinding.on(_t("inspector.zoom_to.key"), mode.zoomToSelected).on("\u238B", esc, true);
+      select_default2(document).call(keybinding);
+      selectError();
+      var sidebar = context.ui().sidebar;
+      sidebar.show(errorEditor.error(error));
+      context.map().on("drawn.select-error", selectError);
+      function selectError(d3_event, drawn) {
+        if (!checkSelectedID()) return;
+        var selection2 = context.surface().selectAll(".itemId-" + selectedErrorID + "." + selectedErrorService);
+        if (selection2.empty()) {
+          var source = d3_event && d3_event.type === "zoom" && d3_event.sourceEvent;
+          if (drawn && source && (source.type === "pointermove" || source.type === "mousemove" || source.type === "touchmove")) {
+            context.enter(modeBrowse(context));
+          }
         } else {
-          showPane.style(side, "0px");
+          selection2.classed("selected", true);
+          context.selectedErrorID(selectedErrorID);
         }
-      } else {
-        hidePanes.classed("shown", true).classed("hide", false).style(side, "0px").transition().duration(200).style(side, "-500px").on("end", function() {
-          select_default2(this).classed("shown", false).classed("hide", true);
-        });
       }
-    };
-    var _editMenu = uiEditMenu(context);
-    ui.editMenu = function() {
-      return _editMenu;
-    };
-    ui.showEditMenu = function(anchorPoint, triggerType, operations) {
-      ui.closeEditMenu();
-      if (!operations && context.mode().operations)
-        operations = context.mode().operations();
-      if (!operations || !operations.length)
-        return;
-      if (!context.map().editableDataEnabled())
-        return;
-      var surfaceNode = context.surface().node();
-      if (surfaceNode.focus) {
-        surfaceNode.focus();
+      function esc() {
+        if (context.container().select(".combobox").size()) return;
+        context.enter(modeBrowse(context));
       }
-      operations.forEach(function(operation2) {
-        if (operation2.point)
-          operation2.point(anchorPoint);
-      });
-      _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations);
-      context.map().supersurface.call(_editMenu);
     };
-    ui.closeEditMenu = function() {
-      context.map().supersurface.select(".edit-menu").remove();
+    mode.exit = function() {
+      behaviors.forEach(context.uninstall);
+      select_default2(document).call(keybinding.unbind);
+      context.surface().selectAll(".qaItem.selected").classed("selected hover", false);
+      context.map().on("drawn.select-error", null);
+      context.ui().sidebar.hide();
+      context.selectedErrorID(null);
+      context.features().forceVisible([]);
     };
-    var _saveLoading = select_default2(null);
-    context.uploader().on("saveStarted.ui", function() {
-      _saveLoading = uiLoading(context).message(_t.html("save.uploading")).blocking(true);
-      context.container().call(_saveLoading);
-    }).on("saveEnded.ui", function() {
-      _saveLoading.close();
-      _saveLoading = select_default2(null);
-    });
-    marked.use({
-      mangle: false,
-      headerIds: false
-    });
-    return ui;
+    return mode;
   }
 
   // modules/core/context.js
     let _defaultChangesetSource = context.initialHashParams.source;
     let _defaultChangesetHashtags = context.initialHashParams.hashtags;
     context.defaultChangesetComment = function(val) {
-      if (!arguments.length)
-        return _defaultChangesetComment;
+      if (!arguments.length) return _defaultChangesetComment;
       _defaultChangesetComment = val;
       return context;
     };
     context.defaultChangesetSource = function(val) {
-      if (!arguments.length)
-        return _defaultChangesetSource;
+      if (!arguments.length) return _defaultChangesetSource;
       _defaultChangesetSource = val;
       return context;
     };
     context.defaultChangesetHashtags = function(val) {
-      if (!arguments.length)
-        return _defaultChangesetHashtags;
+      if (!arguments.length) return _defaultChangesetHashtags;
       _defaultChangesetHashtags = val;
       return context;
     };
     let _setsDocumentTitle = true;
     context.setsDocumentTitle = function(val) {
-      if (!arguments.length)
-        return _setsDocumentTitle;
+      if (!arguments.length) return _setsDocumentTitle;
       _setsDocumentTitle = val;
       return context;
     };
     let _documentTitleBase = document.title;
     context.documentTitleBase = function(val) {
-      if (!arguments.length)
-        return _documentTitleBase;
+      if (!arguments.length) return _documentTitleBase;
       _documentTitleBase = val;
       return context;
     };
       return context;
     };
     context.locale = function(locale2) {
-      if (!arguments.length)
-        return _mainLocalizer.localeCode();
+      if (!arguments.length) return _mainLocalizer.localeCode();
       _mainLocalizer.preferredLocaleCodes(locale2);
       return context;
     };
       }
     };
     context.zoomToEntity = (entityID, zoomTo) => {
-      context.loadEntity(entityID, (err, result) => {
-        if (err)
-          return;
+      context.zoomToEntities([entityID], zoomTo);
+    };
+    context.zoomToEntities = (entityIDs, zoomTo) => {
+      let loadedEntities = [];
+      const throttledZoomTo = throttle_default(() => _map.zoomTo(loadedEntities), 500);
+      entityIDs.forEach((entityID) => context.loadEntity(entityID, (err, result) => {
+        if (err) return;
+        const entity = result.data.find((e3) => e3.id === entityID);
+        if (!entity) return;
+        loadedEntities.push(entity);
         if (zoomTo !== false) {
-          const entity = result.data.find((e3) => e3.id === entityID);
-          if (entity) {
-            _map.zoomTo(entity);
-          }
+          throttledZoomTo();
         }
-      });
+      }));
       _map.on("drawn.zoomToEntity", () => {
-        if (!context.hasEntity(entityID))
-          return;
+        if (!entityIDs.every((entityID) => context.hasEntity(entityID))) return;
         _map.on("drawn.zoomToEntity", null);
         context.on("enter.zoomToEntity", null);
-        context.enter(modeSelect(context, [entityID]));
+        context.enter(modeSelect(context, entityIDs));
       });
       context.on("enter.zoomToEntity", () => {
         if (_mode.id !== "browse") {
         }
       });
     };
+    context.zoomToNote = (noteId, zoomTo) => {
+      context.loadNote(noteId, (err, result) => {
+        if (err) return;
+        const entity = result.data.find((e3) => e3.id === noteId);
+        if (entity) {
+          const note = services.osm.getNote(noteId);
+          if (zoomTo !== false) {
+            context.map().centerZoom(note.loc, 15);
+          }
+          const noteLayer = context.layers().layer("notes");
+          noteLayer.enabled(true);
+          context.enter(modeSelectNote(context, noteId));
+        }
+      });
+    };
     let _minEditableZoom = 16;
     context.minEditableZoom = function(val) {
-      if (!arguments.length)
-        return _minEditableZoom;
+      if (!arguments.length) return _minEditableZoom;
       _minEditableZoom = val;
       if (_connection) {
         _connection.tileZoom(val);
     context.cleanRelationRole = (val) => utilCleanOsmString(val, context.maxCharsForRelationRole());
     let _inIntro = false;
     context.inIntro = function(val) {
-      if (!arguments.length)
-        return _inIntro;
+      if (!arguments.length) return _inIntro;
       _inIntro = val;
       return context;
     };
     context.save = () => {
-      if (_inIntro || context.container().select(".modal").size())
-        return;
+      if (_inIntro || context.container().select(".modal").size()) return;
       let canSave;
       if (_mode && _mode.id === "save") {
         canSave = false;
     context.activeID = () => _mode && _mode.activeID && _mode.activeID();
     let _selectedNoteID;
     context.selectedNoteID = function(noteID) {
-      if (!arguments.length)
-        return _selectedNoteID;
+      if (!arguments.length) return _selectedNoteID;
       _selectedNoteID = noteID;
       return context;
     };
     let _selectedErrorID;
     context.selectedErrorID = function(errorID) {
-      if (!arguments.length)
-        return _selectedErrorID;
+      if (!arguments.length) return _selectedErrorID;
       _selectedErrorID = errorID;
       return context;
     };
     context.copyGraph = () => _copyGraph;
     let _copyIDs = [];
     context.copyIDs = function(val) {
-      if (!arguments.length)
-        return _copyIDs;
+      if (!arguments.length) return _copyIDs;
       _copyIDs = val;
       _copyGraph = _history.graph();
       return context;
     };
     let _copyLonLat;
     context.copyLonLat = function(val) {
-      if (!arguments.length)
-        return _copyLonLat;
+      if (!arguments.length) return _copyLonLat;
       _copyLonLat = val;
       return context;
     };
     context.surfaceRect = () => _map.surface.node().getBoundingClientRect();
     context.editable = () => {
       const mode = context.mode();
-      if (!mode || mode.id === "save")
-        return false;
+      if (!mode || mode.id === "save") return false;
       return _map.editableDataEnabled();
     };
     let _debugFlags = {
     context.debugFlags = () => _debugFlags;
     context.getDebug = (flag) => flag && _debugFlags[flag];
     context.setDebug = function(flag, val) {
-      if (arguments.length === 1)
-        val = true;
+      if (arguments.length === 1) val = true;
       _debugFlags[flag] = val;
       dispatch14.call("change");
       return context;
     };
     let _container = select_default2(null);
     context.container = function(val) {
-      if (!arguments.length)
-        return _container;
+      if (!arguments.length) return _container;
       _container = val;
       _container.classed("ideditor", true);
       return context;
     };
     context.containerNode = function(val) {
-      if (!arguments.length)
-        return context.container().node();
+      if (!arguments.length) return context.container().node();
       context.container(select_default2(val));
       return context;
     };
     let _embed;
     context.embed = function(val) {
-      if (!arguments.length)
-        return _embed;
+      if (!arguments.length) return _embed;
       _embed = val;
       return context;
     };
     let _assetPath = "";
     context.assetPath = function(val) {
-      if (!arguments.length)
-        return _assetPath;
+      if (!arguments.length) return _assetPath;
       _assetPath = val;
       _mainFileFetcher.assetPath(val);
       return context;
     };
     let _assetMap = {};
     context.assetMap = function(val) {
-      if (!arguments.length)
-        return _assetMap;
+      if (!arguments.length) return _assetMap;
       _assetMap = val;
       _mainFileFetcher.assetMap(val);
       return context;
     };
     context.asset = (val) => {
-      if (/^http(s)?:\/\//i.test(val))
-        return val;
+      if (/^http(s)?:\/\//i.test(val)) return val;
       const filename = _assetPath + val;
       return _assetMap[filename] || filename;
     };
   var nominatim_default = {
     init: function() {
       _inflight = {};
-      _nominatimCache = new import_rbush7.default();
+      _nominatimCache = new RBush();
     },
     reset: function() {
       Object.values(_inflight).forEach(function(controller) {
         controller.abort();
       });
       _inflight = {};
-      _nominatimCache = new import_rbush7.default();
+      _nominatimCache = new RBush();
     },
     countryCode: function(location, callback) {
       this.reverse(location, function(err, result) {
         { minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1] }
       );
       if (cached.length > 0) {
-        if (callback)
-          callback(null, cached[0].data);
+        if (callback) callback(null, cached[0].data);
         return;
       }
       var params = { zoom: 13, format: "json", addressdetails: 1, lat: loc[1], lon: loc[0] };
       var url = apibase + "reverse?" + utilQsString(params);
-      if (_inflight[url])
-        return;
+      if (_inflight[url]) return;
       var controller = new AbortController();
       _inflight[url] = controller;
       json_default(url, {
         }
         var extent = geoExtent(loc).padByMeters(200);
         _nominatimCache.insert(Object.assign(extent.bbox(), { data: result }));
-        if (callback)
-          callback(null, result);
+        if (callback) callback(null, result);
       }).catch(function(err) {
         delete _inflight[url];
-        if (err.name === "AbortError")
-          return;
-        if (callback)
-          callback(err.message);
+        if (err.name === "AbortError") return;
+        if (callback) callback(err.message);
       });
     },
     search: function(val, callback) {
         format: "json"
       };
       var url = apibase + "search?" + utilQsString(params);
-      if (_inflight[url])
-        return;
+      if (_inflight[url]) return;
       var controller = new AbortController();
       _inflight[url] = controller;
       json_default(url, {
         if (result && result.error) {
           throw new Error(result.error);
         }
-        if (callback)
-          callback(null, result);
+        if (callback) callback(null, result);
       }).catch(function(err) {
         delete _inflight[url];
-        if (err.name === "AbortError")
-          return;
-        if (callback)
-          callback(err.message);
+        if (err.name === "AbortError") return;
+        if (callback) callback(err.message);
       });
     }
   };
   // node_modules/name-suggestion-index/lib/simplify.js
   var import_diacritics3 = __toESM(require_diacritics(), 1);
   function simplify2(str) {
-    if (typeof str !== "string")
-      return "";
+    if (typeof str !== "string") return "";
     return import_diacritics3.default.remove(
       str.replace(/&/g, "and").replace(/İ/ig, "i").replace(/[\s\-=_!"#%'*{},.\/:;?\(\)\[\]@\\$\^*+<>«»~`’\u00a1\u00a7\u00b6\u00b7\u00bf\u037e\u0387\u055a-\u055f\u0589\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0af0\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f14\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1360-\u1368\u166d\u166e\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u1805\u1807-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cc0-\u1cc7\u1cd3\u2000-\u206f\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00-\u2e7f\u3001-\u3003\u303d\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uaaf0\uaaf1\uabeb\ufe10-\ufe16\ufe19\ufe30\ufe45\ufe46\ufe49-\ufe4c\ufe50-\ufe52\ufe54-\ufe57\ufe5f-\ufe61\ufe68\ufe6a\ufe6b\ufeff\uff01-\uff03\uff05-\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65]+/g, "").toLowerCase()
     );
     //
     buildMatchIndex(data) {
       const that = this;
-      if (that.matchIndex)
-        return;
+      if (that.matchIndex) return;
       that.matchIndex = /* @__PURE__ */ new Map();
       const seenTree = /* @__PURE__ */ new Map();
       Object.keys(data).forEach((tkv) => {
         (exclude.named || []).forEach((s2) => branch.excludeNamed.set(s2, new RegExp(s2, "i")));
         const excludeRegexes = [...branch.excludeGeneric.values(), ...branch.excludeNamed.values()];
         let items = category.items;
-        if (!Array.isArray(items) || !items.length)
-          return;
+        if (!Array.isArray(items) || !items.length) return;
         const primaryName = new RegExp(tree.nameTags.primary, "i");
         const alternateName = new RegExp(tree.nameTags.alternate, "i");
         const notName = /:(colou?r|type|forward|backward|left|right|etymology|pronunciation|wikipedia)$/i;
         const matchGroupKV = /* @__PURE__ */ new Set();
         Object.values(matchGroups).forEach((matchGroup) => {
           const inGroup = matchGroup.some((otherkv) => otherkv === thiskv);
-          if (!inGroup)
-            return;
+          if (!inGroup) return;
           matchGroup.forEach((otherkv) => {
-            if (otherkv === thiskv)
-              return;
+            if (otherkv === thiskv) return;
             matchGroupKV.add(otherkv);
             const otherk = otherkv.split("/", 2)[0];
             genericKV.add("".concat(otherk, "/yes"));
           });
         });
         items.forEach((item) => {
-          if (!item.id)
-            return;
+          if (!item.id) return;
           if (Array.isArray(item.matchTags) && item.matchTags.length) {
             item.matchTags = item.matchTags.filter((matchTag) => !matchGroupKV.has(matchTag) && !genericKV.has(matchTag));
-            if (!item.matchTags.length)
-              delete item.matchTags;
+            if (!item.matchTags.length) delete item.matchTags;
           }
           let kvTags = ["".concat(thiskv)].concat(item.matchTags || []);
           if (!skipGenericKV) {
             kvTags = kvTags.concat(Array.from(genericKV));
           }
           Object.keys(item.tags).forEach((osmkey) => {
-            if (notName.test(osmkey))
-              return;
+            if (notName.test(osmkey)) return;
             const osmvalue = item.tags[osmkey];
-            if (!osmvalue || excludeRegexes.some((regex) => regex.test(osmvalue)))
-              return;
+            if (!osmvalue || excludeRegexes.some((regex) => regex.test(osmvalue))) return;
             if (primaryName.test(osmkey)) {
               kvTags.forEach((kv) => insertName("primary", t2, kv, simplify2(osmvalue), item.id));
             } else if (alternateName.test(osmkey)) {
     //
     buildLocationIndex(data, loco) {
       const that = this;
-      if (that.locationIndex)
-        return;
+      if (that.locationIndex) return;
       that.itemLocation = /* @__PURE__ */ new Map();
       that.locationSets = /* @__PURE__ */ new Map();
       Object.keys(data).forEach((tkv) => {
         const items = data[tkv].items;
-        if (!Array.isArray(items) || !items.length)
-          return;
+        if (!Array.isArray(items) || !items.length) return;
         items.forEach((item) => {
-          if (that.itemLocation.has(item.id))
-            return;
+          if (that.itemLocation.has(item.id)) return;
           let resolved;
           try {
             resolved = loco.resolveLocationSet(item.locationSet);
           } catch (err) {
             console.warn("buildLocationIndex: ".concat(err.message));
           }
-          if (!resolved || !resolved.id)
-            return;
+          if (!resolved || !resolved.id) return;
           that.itemLocation.set(item.id, resolved.id);
-          if (that.locationSets.has(resolved.id))
-            return;
+          if (that.locationSets.has(resolved.id)) return;
           let feature3 = _cloneDeep2(resolved.feature);
           feature3.id = resolved.id;
           feature3.properties.id = resolved.id;
       let results = [];
       gatherResults("primary");
       gatherResults("alternate");
-      if (results.length)
-        return results;
+      if (results.length) return results;
       gatherResults("exclude");
       return results.length ? results : null;
       function gatherResults(which) {
         const kv = "".concat(k2, "/").concat(v2);
         let didMatch = tryMatch(which, kv);
-        if (didMatch)
-          return;
+        if (didMatch) return;
         for (let mg in matchGroups) {
           const matchGroup = matchGroups[mg];
           const inGroup = matchGroup.some((otherkv) => otherkv === kv);
-          if (!inGroup)
-            continue;
+          if (!inGroup) continue;
           for (let i3 = 0; i3 < matchGroup.length; i3++) {
             const otherkv = matchGroup[i3];
-            if (otherkv === kv)
-              continue;
+            if (otherkv === kv) continue;
             didMatch = tryMatch(which, otherkv);
-            if (didMatch)
-              return;
+            if (didMatch) return;
           }
         }
         if (which === "exclude") {
       }
       function tryMatch(which, kv) {
         const branch = that.matchIndex.get(kv);
-        if (!branch)
-          return;
+        if (!branch) return;
         if (which === "exclude") {
           let regex = [...branch.excludeNamed.values()].find((regex2) => regex2.test(n3));
           if (regex) {
           return;
         }
         const leaf = branch[which].get(nsimple);
-        if (!leaf || !leaf.size)
-          return;
+        if (!leaf || !leaf.size) return;
         let hits = Array.from(leaf).map((itemID) => {
           let area = Infinity;
           if (that.itemLocation && that.locationSets) {
           hits = hits.filter(isValidLocation);
           sortFn = byAreaAscending;
         }
-        if (!hits.length)
-          return;
+        if (!hits.length) return;
         hits.sort(sortFn).forEach((hit) => {
-          if (seen.has(hit.itemID))
-            return;
+          if (seen.has(hit.itemID)) return;
           seen.add(hit.itemID);
           results.push(hit);
         });
         return true;
         function isValidLocation(hit) {
-          if (!that.itemLocation)
-            return true;
+          if (!that.itemLocation) return true;
           return matchLocations.find((props) => props.id === that.itemLocation.get(hit.itemID));
         }
         function byAreaAscending(hitA, hitB) {
     };
     let fileMap = _mainFileFetcher.fileMap();
     for (const k2 in sources) {
-      if (!fileMap[k2])
-        fileMap[k2] = sources[k2];
+      if (!fileMap[k2]) fileMap[k2] = sources[k2];
     }
   }
   function loadNsiPresets() {
       matcher.locationSets = /* @__PURE__ */ new Map();
       Object.keys(_nsi.data).forEach((tkv) => {
         const items = _nsi.data[tkv].items;
-        if (!Array.isArray(items) || !items.length)
-          return;
+        if (!Array.isArray(items) || !items.length) return;
         items.forEach((item) => {
-          if (matcher.itemLocation.has(item.id))
-            return;
+          if (matcher.itemLocation.has(item.id)) return;
           const locationSetID = _sharedLocationManager.locationSetID(item.locationSet);
           matcher.itemLocation.set(item.id, locationSetID);
-          if (matcher.locationSets.has(locationSetID))
-            return;
+          if (matcher.locationSets.has(locationSetID)) return;
           const fakeFeature = { id: locationSetID, properties: { id: locationSetID, area: 1 } };
           matcher.locationSets.set(locationSetID, fakeFeature);
         });
           _nsi.ids.set(item.id, item);
           const wd = item.tags[mainTag];
           const wp = item.tags[mainTag.replace("wikidata", "wikipedia")];
-          if (wd)
-            _nsi.qids.set(wd, wd);
-          if (wp && wd)
-            _nsi.qids.set(wp, wd);
+          if (wd) _nsi.qids.set(wd, wd);
+          if (wp && wd) _nsi.qids.set(wp, wd);
         });
       });
     });
     let alternate = /* @__PURE__ */ new Set();
     Object.keys(tags).forEach((osmkey) => {
       const osmvalue = tags[osmkey];
-      if (!osmvalue)
-        return;
-      if (osmkey === "route_master")
-        osmkey = "route";
+      if (!osmvalue) return;
+      if (osmkey === "route_master") osmkey = "route";
       const vmap = _nsi.kvt.get(osmkey);
-      if (!vmap)
-        return;
+      if (!vmap) return;
       if (vmap.get(osmvalue)) {
         primary.add("".concat(osmkey, "/").concat(osmvalue));
       } else if (osmvalue === "yes") {
     let unknown;
     let t2;
     Object.keys(tags).forEach((osmkey) => {
-      if (t2)
-        return;
+      if (t2) return;
       const osmvalue = tags[osmkey];
-      if (!osmvalue)
-        return;
-      if (osmkey === "route_master")
-        osmkey = "route";
+      if (!osmvalue) return;
+      if (osmkey === "route_master") osmkey = "route";
       const vmap = _nsi.kvt.get(osmkey);
-      if (!vmap)
-        return;
+      if (!vmap) return;
       if (osmvalue === "yes") {
         unknown = "unknown";
       } else {
     let testNameFragments = false;
     let patterns2;
     let t2 = identifyTree(tags);
-    if (!t2)
-      return empty2;
+    if (!t2) return empty2;
     if (t2 === "transit") {
       patterns2 = {
         primary: /^network$/i,
     }
     Object.keys(tags).forEach((osmkey) => {
       const osmvalue = tags[osmkey];
-      if (!osmvalue)
-        return;
+      if (!osmvalue) return;
       if (isNamelike(osmkey, "primary")) {
         if (/;/.test(osmvalue)) {
           foundSemi = true;
       return { primary, alternate };
     }
     function isNamelike(osmkey, which) {
-      if (osmkey === "old_name")
-        return false;
+      if (osmkey === "old_name") return false;
       return patterns2[which].test(osmkey) && !notNames.test(osmkey);
     }
   }
     }
     const tryNames = gatherNames(tags);
     const foundQID = _nsi.qids.get(tags.wikidata) || _nsi.qids.get(tags.wikipedia);
-    if (foundQID)
-      tryNames.primary.add(foundQID);
+    if (foundQID) tryNames.primary.add(foundQID);
     if (!tryNames.primary.size && !tryNames.alternate.size) {
       return changed ? { newTags, matched: null } : null;
     }
     for (let i3 = 0; i3 < tuples.length; i3++) {
       const tuple = tuples[i3];
       const hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n, loc);
-      if (!hits || !hits.length)
-        continue;
-      if (hits[0].match !== "primary" && hits[0].match !== "alternate")
-        break;
+      if (!hits || !hits.length) continue;
+      if (hits[0].match !== "primary" && hits[0].match !== "alternate") break;
       let itemID, item;
       for (let j2 = 0; j2 < hits.length; j2++) {
         const hit = hits[j2];
         itemID = hit.itemID;
-        if (_nsi.dissolved[itemID])
-          continue;
+        if (_nsi.dissolved[itemID]) continue;
         item = _nsi.ids.get(itemID);
-        if (!item)
-          continue;
+        if (!item) continue;
         const mainTag = item.mainTag;
         const itemQID = item.tags[mainTag];
         const notQID = newTags["not:".concat(mainTag)];
           break;
         }
       }
-      if (!item)
-        continue;
+      if (!item) continue;
       item = JSON.parse(JSON.stringify(item));
       const tkv = item.tkv;
       const parts = tkv.split("/", 3);
       const properties = category.properties || {};
       let preserveTags = item.preserveTags || properties.preserveTags || [];
       ["building", "emergency", "internet_access", "takeaway"].forEach((osmkey) => {
-        if (k2 !== osmkey)
-          preserveTags.push("^".concat(osmkey, "$"));
+        if (k2 !== osmkey) preserveTags.push("^".concat(osmkey, "$"));
       });
       const regexes = preserveTags.map((s2) => new RegExp(s2, "i"));
       let keepTags = {};
         }
       });
       _nsi.kvt.forEach((vmap, k3) => {
-        if (newTags[k3] === "yes")
-          delete newTags[k3];
+        if (newTags[k3] === "yes") delete newTags[k3];
       });
       if (foundQID) {
         delete newTags.wikipedia;
             const name = nameParts.slice(0, split).join(" ");
             const branch = nameParts.slice(split).join(" ");
             const nameHits = _nsi.matcher.match(k2, v2, name, loc);
-            if (!nameHits || !nameHits.length)
-              continue;
+            if (!nameHits || !nameHits.length) continue;
             if (nameHits.some((hit) => hit.itemID === itemID)) {
               if (branch) {
                 if (notBranches.test(branch)) {
   }
   function _isGenericName(tags) {
     const n3 = tags.name;
-    if (!n3)
-      return false;
+    if (!n3) return false;
     const tryNames = { primary: /* @__PURE__ */ new Set([n3]), alternate: /* @__PURE__ */ new Set() };
     const tryKVs = gatherKVs(tags);
-    if (!tryKVs.primary.size && !tryKVs.alternate.size)
-      return false;
+    if (!tryKVs.primary.size && !tryKVs.alternate.size) return false;
     const tuples = gatherTuples(tryKVs, tryNames);
     for (let i3 = 0; i3 < tuples.length; i3++) {
       const tuple = tuples[i3];
       const hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n);
-      if (hits && hits.length && hits[0].match === "excludeGeneric")
-        return true;
+      if (hits && hits.length && hits[0].match === "excludeGeneric") return true;
     }
     return false;
   }
   };
 
   // modules/services/kartaview.js
-  var import_rbush8 = __toESM(require_rbush_min());
   var apibase2 = "https://kartaview.org";
   var maxResults = 1e3;
   var tileZoom = 14;
-  var tiler4 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
-  var dispatch7 = dispatch_default("loadedImages");
+  var tiler3 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
+  var dispatch6 = dispatch_default("loadedImages");
   var imgZoom2 = zoom_default2().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
   var _oscCache;
   var _oscSelectedImage;
   var _loadViewerPromise2;
-  function abortRequest4(controller) {
+  function abortRequest3(controller) {
     controller.abort();
   }
   function maxPageAtZoom(z2) {
-    if (z2 < 15)
-      return 2;
-    if (z2 === 15)
-      return 5;
-    if (z2 === 16)
-      return 10;
-    if (z2 === 17)
-      return 20;
-    if (z2 === 18)
-      return 40;
-    if (z2 > 18)
-      return 80;
+    if (z2 < 15) return 2;
+    if (z2 === 15) return 5;
+    if (z2 === 16) return 10;
+    if (z2 === 17) return 20;
+    if (z2 === 18) return 40;
+    if (z2 > 18) return 80;
   }
   function loadTiles2(which, url, projection2) {
     var currZoom = Math.floor(geoScaleToZoom(projection2.scale()));
-    var tiles = tiler4.getTiles(projection2);
+    var tiles = tiler3.getTiles(projection2);
     var cache = _oscCache[which];
     Object.keys(cache.inflight).forEach(function(k2) {
       var wanted = tiles.find(function(tile) {
         return k2.indexOf(tile.id + ",") === 0;
       });
       if (!wanted) {
-        abortRequest4(cache.inflight[k2]);
+        abortRequest3(cache.inflight[k2]);
         delete cache.inflight[k2];
       }
     });
       bbTopLeft: [bbox2.maxY, bbox2.minX].join(","),
       bbBottomRight: [bbox2.minY, bbox2.maxX].join(",")
     }, true);
-    if (nextPage > maxPages)
-      return;
+    if (nextPage > maxPages) return;
     var id2 = tile.id + "," + String(nextPage);
-    if (cache.loaded[id2] || cache.inflight[id2])
-      return;
+    if (cache.loaded[id2] || cache.inflight[id2]) return;
     var controller = new AbortController();
     cache.inflight[id2] = controller;
     var options2 = {
         cache.nextPage[tile.id] = Infinity;
       }
       if (which === "images") {
-        dispatch7.call("loadedImages");
+        dispatch6.call("loadedImages");
       }
     }).catch(function() {
       cache.loaded[id2] = true;
   function partitionViewport2(projection2) {
     var z2 = geoScaleToZoom(projection2.scale());
     var z22 = Math.ceil(z2 * 2) / 2 + 2.5;
-    var tiler9 = utilTiler().zoomExtent([z22, z22]);
-    return tiler9.getTiles(projection2).map(function(tile) {
+    var tiler8 = utilTiler().zoomExtent([z22, z22]);
+    return tiler8.getTiles(projection2).map(function(tile) {
       return tile.extent;
     });
   }
       if (!_oscCache) {
         this.reset();
       }
-      this.event = utilRebind(this, dispatch7, "on");
+      this.event = utilRebind(this, dispatch6, "on");
     },
     reset: function() {
       if (_oscCache) {
-        Object.values(_oscCache.images.inflight).forEach(abortRequest4);
+        Object.values(_oscCache.images.inflight).forEach(abortRequest3);
       }
       _oscCache = {
-        images: { inflight: {}, loaded: {}, nextPage: {}, rtree: new import_rbush8.default(), forImageKey: {} },
+        images: { inflight: {}, loaded: {}, nextPage: {}, rtree: new RBush(), forImageKey: {} },
         sequences: {}
       };
       _oscSelectedImage = null;
       loadTiles2("images", url, projection2);
     },
     ensureViewerLoaded: function(context) {
-      if (_loadViewerPromise2)
-        return _loadViewerPromise2;
+      if (_loadViewerPromise2) return _loadViewerPromise2;
       var wrap2 = context.container().select(".photoviewer").selectAll(".kartaview-wrapper").data([0]);
       var that = this;
       var wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper kartaview-wrapper").classed("hide", true).call(imgZoom2.on("zoom", zoomPan2)).on("dblclick.zoom", null);
       }
       function rotate(deg) {
         return function() {
-          if (!_oscSelectedImage)
-            return;
+          if (!_oscSelectedImage) return;
           var sequenceKey = _oscSelectedImage.sequence_id;
           var sequence = _oscCache.sequences[sequenceKey];
-          if (!sequence)
-            return;
+          if (!sequence) return;
           var r2 = sequence.rotation || 0;
           r2 += deg;
-          if (r2 > 180)
-            r2 -= 360;
-          if (r2 < -180)
-            r2 += 360;
+          if (r2 > 180) r2 -= 360;
+          if (r2 < -180) r2 += 360;
           sequence.rotation = r2;
           var wrap3 = context.container().select(".photoviewer .kartaview-wrapper");
           wrap3.transition().duration(100).call(imgZoom2.transform, identity2);
       }
       function step(stepBy) {
         return function() {
-          if (!_oscSelectedImage)
-            return;
+          if (!_oscSelectedImage) return;
           var sequenceKey = _oscSelectedImage.sequence_id;
           var sequence = _oscCache.sequences[sequenceKey];
-          if (!sequence)
-            return;
+          if (!sequence) return;
           var nextIndex = _oscSelectedImage.sequence_index + stepBy;
           var nextImage = sequence.images[nextIndex];
-          if (!nextImage)
-            return;
+          if (!nextImage) return;
           context.map().centerEase(nextImage.loc);
           that.selectImage(context, nextImage.key);
         };
       _oscSelectedImage = null;
       this.updateUrlImage(null);
       var viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(null);
+      if (!viewer.empty()) viewer.datum(null);
       viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
       context.container().selectAll(".viewfield-group, .sequence, .icon-sign").classed("currentView", false);
       return this.setStyles(context, null, true);
       _oscSelectedImage = d2;
       this.updateUrlImage(imageKey);
       var viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(d2);
+      if (!viewer.empty()) viewer.datum(d2);
       this.setStyles(context, null, true);
       context.container().selectAll(".icon-sign").classed("currentView", false);
-      if (!d2)
-        return this;
+      if (!d2) return this;
       var wrap2 = context.container().select(".photoviewer .kartaview-wrapper");
       var imageWrap = wrap2.selectAll(".kartaview-image-wrap");
       var attribution = wrap2.selectAll(".photo-attribution").text("");
       }
       return this;
       function localeDateString2(s2) {
-        if (!s2)
-          return null;
+        if (!s2) return null;
         var options2 = { day: "numeric", month: "short", year: "numeric" };
         var d4 = new Date(s2);
-        if (isNaN(d4.getTime()))
-          return null;
+        if (isNaN(d4.getTime())) return null;
         return d4.toLocaleDateString(_mainLocalizer.localeCode(), options2);
       }
     },
     }
   };
 
-  // modules/services/vegbilder.js
-  var import_rbush9 = __toESM(require_rbush_min());
-
   // modules/services/pannellum_photo.js
   var pannellumViewerCSS = "pannellum/pannellum.css";
   var pannellumViewerJS = "pannellum/pannellum.js";
-  var dispatch8 = dispatch_default("viewerChanged");
+  var dispatch7 = dispatch_default("viewerChanged");
   var _currScenes = [];
   var _pannellumViewer;
   var pannellum_photo_default = {
     init: async function(context, selection2) {
-      selection2.append("div").attr("class", "photo-frame pannellum-frame").attr("id", "ideditor-pannellum-viewer").classed("hide", true);
+      selection2.append("div").attr("class", "photo-frame pannellum-frame").attr("id", "ideditor-pannellum-viewer").classed("hide", true).on("keydown", function(e3) {
+        e3.stopPropagation();
+      });
       if (!window.pannellum) {
         await this.loadPannellum(context);
       }
       const options2 = {
         "default": { firstScene: "" },
-        scenes: {}
+        scenes: {},
+        minHfov: 20
       };
       _pannellumViewer = window.pannellum.viewer("ideditor-pannellum-viewer", options2);
       _pannellumViewer.on("mousedown", () => {
         select_default2(window).on("pointermove.pannellum mousemove.pannellum", () => {
-          dispatch8.call("viewerChanged");
+          dispatch7.call("viewerChanged");
         });
       }).on("mouseup", () => {
         select_default2(window).on("pointermove.pannellum mousemove.pannellum", null);
       }).on("animatefinished", () => {
-        dispatch8.call("viewerChanged");
+        dispatch7.call("viewerChanged");
       });
       context.ui().photoviewer.on("resize.pannellum", () => {
         _pannellumViewer.resize();
       });
-      this.event = utilRebind(this, dispatch8, "on");
+      this.event = utilRebind(this, dispatch7, "on");
       return this;
     },
     loadPannellum: function(context) {
         let newSceneOptions = {
           showFullscreenCtrl: false,
           autoLoad: false,
-          compass: true,
+          compass: false,
           yaw: 0,
           type: "equirectangular",
           preview: data.preview_path,
         pitch = _pannellumViewer.getPitch();
       }
       _pannellumViewer.loadScene(key, pitch, yaw);
-      dispatch8.call("viewerChanged");
+      dispatch7.call("viewerChanged");
       if (_currScenes.length > 3) {
         const old_key = _currScenes.shift();
         _pannellumViewer.removeScene(old_key);
       }
+      _pannellumViewer.resize();
       return this;
     },
     getYaw: function() {
   // modules/services/vegbilder.js
   var owsEndpoint = "https://www.vegvesen.no/kart/ogc/vegbilder_1_0/ows?";
   var tileZoom2 = 14;
-  var tiler5 = utilTiler().zoomExtent([tileZoom2, tileZoom2]).skipNullIsland(true);
-  var dispatch9 = dispatch_default("loadedImages", "viewerChanged");
+  var tiler4 = utilTiler().zoomExtent([tileZoom2, tileZoom2]).skipNullIsland(true);
+  var dispatch8 = dispatch_default("loadedImages", "viewerChanged");
   var directionEnum = Object.freeze({
     forward: Symbol(0),
     backward: Symbol(1)
   var _loadViewerPromise3;
   var _vegbilderCache;
   async function fetchAvailableLayers() {
-    var _a2, _b, _c;
+    var _a3, _b3, _c;
     const params = {
       service: "WFS",
       request: "GetCapabilities",
     let node;
     const availableLayers = [];
     while ((node = l2.iterateNext()) !== null) {
-      const match = (_a2 = node.textContent) == null ? void 0 : _a2.match(regexMatcher);
+      const match = (_a3 = node.textContent) == null ? void 0 : _a3.match(regexMatcher);
       if (match) {
         availableLayers.push({
           name: match[0],
-          is_sphere: !!((_b = match.groups) == null ? void 0 : _b.image_type),
+          is_sphere: !!((_b3 = match.groups) == null ? void 0 : _b3.image_type),
           year: parseInt((_c = match.groups) == null ? void 0 : _c.year, 10)
         });
       }
     return Array.from(_vegbilderCache.wfslayers.values()).filter(({ layerInfo }) => layerInfo.year >= fromYear && (!toYear || layerInfo.year <= toYear) && (!layerInfo.is_sphere && showsFlat || layerInfo.is_sphere && showsPano));
   }
   function loadWFSLayers(projection2, margin, wfslayers) {
-    const tiles = tiler5.margin(margin).getTiles(projection2);
+    const tiles = tiler4.margin(margin).getTiles(projection2);
     for (const cache of wfslayers) {
       loadWFSLayer(projection2, cache, tiles);
     }
   async function loadTile2(cache, typename, tile) {
     const bbox2 = tile.extent.bbox();
     const tileid = tile.id;
-    if (cache.loaded.get(tileid) === true || cache.inflight.has(tileid))
-      return;
+    if (cache.loaded.get(tileid) === true || cache.inflight.has(tileid)) return;
     const params = {
       service: "WFS",
       request: "GetFeature",
       };
     });
     _vegbilderCache.rtree.load(features);
-    dispatch9.call("loadedImages");
+    dispatch8.call("loadedImages");
   }
   function orderSequences(projection2, cache) {
     const { points } = cache;
   function partitionViewport3(projection2) {
     const zoom = geoScaleToZoom(projection2.scale());
     const roundZoom = Math.ceil(zoom * 2) / 2 + 2.5;
-    const tiler9 = utilTiler().zoomExtent([roundZoom, roundZoom]);
-    return tiler9.getTiles(projection2).map((tile) => tile.extent);
+    const tiler8 = utilTiler().zoomExtent([roundZoom, roundZoom]);
+    return tiler8.getTiles(projection2).map((tile) => tile.extent);
   }
   function searchLimited3(limit, projection2, rtree) {
     limit != null ? limit : limit = 5;
   }
   var vegbilder_default = {
     init: function() {
-      this.event = utilRebind(this, dispatch9, "on");
+      this.event = utilRebind(this, dispatch8, "on");
     },
     reset: async function() {
       if (_vegbilderCache) {
       }
       _vegbilderCache = {
         wfslayers: /* @__PURE__ */ new Map(),
-        rtree: new import_rbush9.default(),
+        rtree: new RBush(),
         image2sequence_map: /* @__PURE__ */ new Map()
       };
       const availableLayers = await fetchAvailableLayers();
       const line_strings = [];
       for (const { data } of _vegbilderCache.rtree.search(bbox2)) {
         const sequence = _vegbilderCache.image2sequence_map.get(data.key);
-        if (!sequence)
-          continue;
+        if (!sequence) continue;
         const { key, geometry, images } = sequence;
-        if (seen.has(key))
-          continue;
+        if (seen.has(key)) continue;
         seen.add(key);
         const line = {
           type: "LineString",
     },
     cachedImage: function(key) {
       for (const { points } of _vegbilderCache.wfslayers.values()) {
-        if (points.has(key))
-          return points.get(key);
+        if (points.has(key)) return points.get(key);
       }
     },
     getSequenceForImage: function(image) {
       return _currentFrame;
     },
     ensureViewerLoaded: function(context) {
-      if (_loadViewerPromise3)
-        return _loadViewerPromise3;
+      if (_loadViewerPromise3) return _loadViewerPromise3;
       const step = (stepBy) => () => {
         const viewer = context.container().select(".photoviewer");
         const selected = viewer.empty() ? void 0 : viewer.datum();
-        if (!selected)
-          return;
+        if (!selected) return;
         const sequence = this.getSequenceForImage(selected);
         const nextIndex = sequence.images.indexOf(selected) + stepBy;
         const nextImage = sequence.images[nextIndex];
-        if (!nextImage)
-          return;
+        if (!nextImage) return;
         context.map().centerEase(nextImage.loc);
         this.selectImage(context, nextImage.key, true);
       };
         plane_photo_default.init(context, wrapEnter)
       ]).then(([pannellumPhotoFrame, planePhotoFrame]) => {
         _pannellumFrame = pannellumPhotoFrame;
-        _pannellumFrame.event.on("viewerChanged", () => dispatch9.call("viewerChanged"));
+        _pannellumFrame.event.on("viewerChanged", () => dispatch8.call("viewerChanged"));
         _planeFrame = planePhotoFrame;
-        _planeFrame.event.on("viewerChanged", () => dispatch9.call("viewerChanged"));
+        _planeFrame.event.on("viewerChanged", () => dispatch8.call("viewerChanged"));
       });
       return _loadViewerPromise3;
     },
         viewer.datum(d2);
       }
       this.setStyles(context, null, true);
-      if (!d2)
-        return this;
+      if (!d2) return this;
       const wrap2 = context.container().select(".photoviewer .vegbilder-wrapper");
       const attribution = wrap2.selectAll(".photo-attribution").text("");
       if (d2.captured_at) {
     hideViewer: function(context) {
       this.updateUrlImage(null);
       const viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(null);
+      if (!viewer.empty()) viewer.datum(null);
       viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
       context.container().selectAll(".viewfield-group, .sequence").classed("currentView", false);
       return this.setStyles(context, null, true);
     // Reset is only necessary when interacting with the viewport because
     // this implicitly changes the currently selected bubble/sequence
     setStyles: function(context, hovered, reset) {
-      var _a2, _b;
+      var _a3, _b3;
       if (reset) {
         context.container().selectAll(".viewfield-group").classed("highlighted", false).classed("hovered", false).classed("currentView", false);
         context.container().selectAll(".sequence").classed("highlighted", false).classed("currentView", false);
       const hoveredImageKey = hovered == null ? void 0 : hovered.key;
       const hoveredSequence = this.getSequenceForImage(hovered);
       const hoveredSequenceKey = hoveredSequence == null ? void 0 : hoveredSequence.key;
-      const hoveredImageKeys = (_a2 = hoveredSequence == null ? void 0 : hoveredSequence.images.map((d2) => d2.key)) != null ? _a2 : [];
+      const hoveredImageKeys = (_a3 = hoveredSequence == null ? void 0 : hoveredSequence.images.map((d2) => d2.key)) != null ? _a3 : [];
       const viewer = context.container().select(".photoviewer");
       const selected = viewer.empty() ? void 0 : viewer.datum();
       const selectedImageKey = selected == null ? void 0 : selected.key;
       const selectedSequence = this.getSequenceForImage(selected);
       const selectedSequenceKey = selectedSequence == null ? void 0 : selectedSequence.key;
-      const selectedImageKeys = (_b = selectedSequence == null ? void 0 : selectedSequence.images.map((d2) => d2.key)) != null ? _b : [];
+      const selectedImageKeys = (_b3 = selectedSequence == null ? void 0 : selectedSequence.images.map((d2) => d2.key)) != null ? _b3 : [];
       const highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
       context.container().selectAll(".layer-vegbilder .viewfield-group").classed("highlighted", (d2) => highlightedImageKeys.indexOf(d2.key) !== -1).classed("hovered", (d2) => d2.key === hoveredImageKey).classed("currentView", (d2) => d2.key === selectedImageKey);
       context.container().selectAll(".layer-vegbilder .sequence").classed("highlighted", (d2) => d2.key === hoveredSequenceKey).classed("currentView", (d2) => d2.key === selectedSequenceKey);
       };
     }
     function token(k2, v2) {
-      if (arguments.length === 1)
-        return _store.getItem(o2.url + k2);
-      else if (arguments.length === 2)
-        return _store.setItem(o2.url + k2, v2);
+      var key = o2.url + k2;
+      if (arguments.length === 1) {
+        var val = _store.getItem(key) || "";
+        return val.replace(/"/g, "");
+      } else if (arguments.length === 2) {
+        if (v2) {
+          return _store.setItem(key, v2);
+        } else {
+          return _store.removeItem(key);
+        }
+      }
     }
     oauth2.authenticated = function() {
       return !!token("oauth2_access_token");
         scope: o2.scope,
         state,
         code_challenge: pkce.code_challenge,
-        code_challenge_method: pkce.code_challenge_method
+        code_challenge_method: pkce.code_challenge_method,
+        locale: o2.locale || ""
       });
       if (o2.singlepage) {
         if (_store.isMocked) {
       window.authComplete = function(url2) {
         var params2 = utilStringQs2(url2.split("?")[1]);
         if (params2.state !== state) {
-          error = new Error("Invalid state");
-          error.status = "invalid-state";
-          callback(error);
+          var error2 = new Error("Invalid state");
+          error2.status = "invalid-state";
+          callback(error2);
           return;
         }
         _getAccessToken(params2.code, pkce.code_verifier, accessTokenDone);
         callback(e3, null);
       };
       xhr.open(method, url, true);
-      for (var h2 in headers)
-        xhr.setRequestHeader(h2, headers[h2]);
+      for (var h2 in headers) xhr.setRequestHeader(h2, headers[h2]);
       xhr.send(data);
       return xhr;
     };
       return oauth2;
     };
     oauth2.options = function(val) {
-      if (!arguments.length)
-        return o2;
+      if (!arguments.length) return o2;
       o2 = val;
       o2.apiUrl = o2.apiUrl || "https://api.openstreetmap.org";
       o2.url = o2.url || "https://www.openstreetmap.org";
   }
   function utilStringQs2(str) {
     var i3 = 0;
-    while (i3 < str.length && (str[i3] === "?" || str[i3] === "#"))
-      i3++;
+    while (i3 < str.length && (str[i3] === "?" || str[i3] === "#")) i3++;
     str = str.slice(i3);
     return str.split("&").reduce(function(obj, pair3) {
       var parts = pair3.split("=");
   }
 
   // modules/services/osm.js
-  var import_rbush10 = __toESM(require_rbush_min());
-  var tiler6 = utilTiler();
-  var dispatch10 = dispatch_default("apiStatusChange", "authLoading", "authDone", "change", "loading", "loaded", "loadedNotes");
+  var tiler5 = utilTiler();
+  var dispatch9 = dispatch_default("apiStatusChange", "authLoading", "authDone", "change", "loading", "loaded", "loadedNotes");
   var urlroot = osmApiConnections[0].url;
   var apiUrlroot = osmApiConnections[0].apiUrl || urlroot;
   var redirectPath = window.location.origin + window.location.pathname;
     url: urlroot,
     apiUrl: apiUrlroot,
     client_id: osmApiConnections[0].client_id,
-    client_secret: osmApiConnections[0].client_secret,
     scope: "read_prefs write_prefs write_api read_gpx write_notes",
     redirect_uri: redirectPath + "land.html",
     loading: authLoading,
   });
   var _apiConnections = osmApiConnections;
   var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
-  var _tileCache = { toLoad: {}, loaded: {}, inflight: {}, seen: {}, rtree: new import_rbush10.default() };
-  var _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: new import_rbush10.default() };
+  var _tileCache = { toLoad: {}, loaded: {}, inflight: {}, seen: {}, rtree: new RBush() };
+  var _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: new RBush() };
   var _userCache = { toLoad: {}, user: {} };
   var _cachedApiStatus;
   var _changeset = {};
   var _deferred = /* @__PURE__ */ new Set();
   var _connectionID = 1;
-  var _tileZoom4 = 16;
+  var _tileZoom3 = 16;
   var _noteZoom = 12;
   var _rateLimitError;
   var _userChangesets;
   var _off;
   var _maxWayNodes = 2e3;
   function authLoading() {
-    dispatch10.call("authLoading");
+    dispatch9.call("authLoading");
   }
   function authDone() {
-    dispatch10.call("authDone");
+    dispatch9.call("authDone");
   }
-  function abortRequest5(controllerOrXHR) {
+  function abortRequest4(controllerOrXHR) {
     if (controllerOrXHR) {
       controllerOrXHR.abort();
     }
   function hasInflightRequests(cache) {
     return Object.keys(cache.inflight).length;
   }
-  function abortUnwantedRequests4(cache, visibleTiles) {
+  function abortUnwantedRequests3(cache, visibleTiles) {
     Object.keys(cache.inflight).forEach(function(k2) {
-      if (cache.toLoad[k2])
-        return;
+      if (cache.toLoad[k2]) return;
       if (visibleTiles.find(function(tile) {
         return k2 === tile.id;
-      }))
-        return;
-      abortRequest5(cache.inflight[k2]);
+      })) return;
+      abortRequest4(cache.inflight[k2]);
       delete cache.inflight[k2];
     });
   }
         for (var j2 = 0; j2 < childNodes.length; j2++) {
           var node = childNodes[j2];
           var nodeName = node.nodeName;
-          if (nodeName === "#text")
-            continue;
+          if (nodeName === "#text") continue;
           parsedComment[nodeName] = node.textContent;
           if (nodeName === "uid") {
             var uid = node.textContent;
       return callback({ message: "No JSON", status: -1 });
     }
     var json = payload;
-    if (typeof json !== "object")
-      json = JSON.parse(payload);
-    if (!json.elements)
-      return callback({ message: "No JSON", status: -1 });
+    if (typeof json !== "object") json = JSON.parse(payload);
+    if (!json.elements) return callback({ message: "No JSON", status: -1 });
     var children2 = json.elements;
     var handle = window.requestIdleCallback(function() {
       _deferred.delete(handle);
       var result;
       for (var i3 = 0; i3 < children2.length; i3++) {
         result = parseChild(children2[i3]);
-        if (result)
-          results.push(result);
+        if (result) results.push(result);
       }
       callback(null, results);
     });
     _deferred.add(handle);
     function parseChild(child) {
       var parser3 = jsonparsers[child.type];
-      if (!parser3)
-        return null;
+      if (!parser3) return null;
       var uid;
       uid = osmEntity.id.fromOSM(child.type, child.id);
       if (options2.skipSeen) {
-        if (_tileCache.seen[uid])
-          return null;
+        if (_tileCache.seen[uid]) return null;
         _tileCache.seen[uid] = true;
       }
       return parser3(child, uid);
       return callback({ message: "No JSON", status: -1 });
     }
     var json = payload;
-    if (typeof json !== "object")
-      json = JSON.parse(payload);
-    if (!json.users && !json.user)
-      return callback({ message: "No JSON", status: -1 });
+    if (typeof json !== "object") json = JSON.parse(payload);
+    if (!json.users && !json.user) return callback({ message: "No JSON", status: -1 });
     var objs = json.users || [json];
     var handle = window.requestIdleCallback(function() {
       _deferred.delete(handle);
       var result;
       for (var i3 = 0; i3 < objs.length; i3++) {
         result = parseObj(objs[i3]);
-        if (result)
-          results.push(result);
+        if (result) results.push(result);
       }
       callback(null, results);
     });
       for (var i3 = 0; i3 < childNodes.length; i3++) {
         var node = childNodes[i3];
         var nodeName = node.nodeName;
-        if (nodeName === "#text")
-          continue;
+        if (nodeName === "#text") continue;
         if (nodeName === "comments") {
           props[nodeName] = parseComments(node.childNodes);
         } else {
       var note = new osmNote(props);
       var item = encodeNoteRtree(note);
       _noteCache.note[note.id] = note;
-      updateRtree4(item, true);
+      updateRtree3(item, true);
       return note;
     },
     user: function parseUser2(obj, uid) {
       var result;
       for (var i3 = 0; i3 < children2.length; i3++) {
         result = parseChild(children2[i3]);
-        if (result)
-          results.push(result);
+        if (result) results.push(result);
       }
       callback(null, results);
     });
     _deferred.add(handle);
     function parseChild(child) {
       var parser3 = parsers[child.nodeName];
-      if (!parser3)
-        return null;
+      if (!parser3) return null;
       var uid;
       if (child.nodeName === "user") {
         uid = child.attributes.id.value;
       } else {
         uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
         if (options2.skipSeen) {
-          if (_tileCache.seen[uid])
-            return null;
+          if (_tileCache.seen[uid]) return null;
           _tileCache.seen[uid] = true;
         }
       }
       return parser3(child, uid);
     }
   }
-  function updateRtree4(item, replace) {
+  function updateRtree3(item, replace) {
     _noteCache.rtree.remove(item, function isEql(a2, b2) {
       return a2.data.id === b2.data.id;
     });
   }
   var osm_default = {
     init: function() {
-      utilRebind(this, dispatch10, "on");
+      utilRebind(this, dispatch9, "on");
     },
     reset: function() {
       Array.from(_deferred).forEach(function(handle) {
       _userChangesets = void 0;
       _userDetails = void 0;
       _rateLimitError = void 0;
-      Object.values(_tileCache.inflight).forEach(abortRequest5);
-      Object.values(_noteCache.inflight).forEach(abortRequest5);
-      Object.values(_noteCache.inflightPost).forEach(abortRequest5);
-      if (_changeset.inflight)
-        abortRequest5(_changeset.inflight);
-      _tileCache = { toLoad: {}, loaded: {}, inflight: {}, seen: {}, rtree: new import_rbush10.default() };
-      _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: new import_rbush10.default() };
+      Object.values(_tileCache.inflight).forEach(abortRequest4);
+      Object.values(_noteCache.inflight).forEach(abortRequest4);
+      Object.values(_noteCache.inflightPost).forEach(abortRequest4);
+      if (_changeset.inflight) abortRequest4(_changeset.inflight);
+      _tileCache = { toLoad: {}, loaded: {}, inflight: {}, seen: {}, rtree: new RBush() };
+      _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: new RBush() };
       _userCache = { toLoad: {}, user: {} };
       _cachedApiStatus = void 0;
       _changeset = {};
       var cid = _connectionID;
       function done(err, payload) {
         if (that.getConnectionId() !== cid) {
-          if (callback)
-            callback({ message: "Connection Switched", status: -1 });
+          if (callback) callback({ message: "Connection Switched", status: -1 });
           return;
         }
         var isAuthenticated = that.authenticated();
         } else {
           if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
             _rateLimitError = err;
-            dispatch10.call("change");
+            dispatch9.call("change");
             that.reloadApiStatus();
           } else if (err && _cachedApiStatus === "online" || !err && _cachedApiStatus !== "online") {
             that.reloadApiStatus();
         fn(url, { signal: controller.signal }).then(function(data) {
           done(null, data);
         }).catch(function(err) {
-          if (err.name === "AbortError")
-            return;
+          if (err.name === "AbortError") return;
           var match = err.message.match(/^\d{3}/);
           if (match) {
             done({ status: +match[0], statusText: err.message });
       this.loadFromAPI(
         "/api/0.6/" + type2 + "/" + osmID + (type2 !== "node" ? "/full" : "") + ".json",
         function(err, entities) {
-          if (callback)
-            callback(err, { data: entities });
+          if (callback) callback(err, { data: entities });
         },
         options2
       );
       this.loadFromAPI(
         "/api/0.6/notes/" + id2,
         function(err, entities) {
-          if (callback)
-            callback(err, { data: entities });
+          if (callback) callback(err, { data: entities });
         },
         options2
       );
       this.loadFromAPI(
         "/api/0.6/" + type2 + "/" + osmID + "/" + version + ".json",
         function(err, entities) {
-          if (callback)
-            callback(err, { data: entities });
+          if (callback) callback(err, { data: entities });
         },
         options2
       );
       this.loadFromAPI(
         "/api/0.6/" + type2 + "/" + osmID + "/relations.json",
         function(err, entities) {
-          if (callback)
-            callback(err, { data: entities });
+          if (callback) callback(err, { data: entities });
         },
         options2
       );
           that.loadFromAPI(
             "/api/0.6/" + type2 + ".json?" + type2 + "=" + arr.join(),
             function(err, entities) {
-              if (callback)
-                callback(err, { data: entities });
+              if (callback) callback(err, { data: entities });
             },
             options2
           );
       }
       function uploadedChangeset(err) {
         _changeset.inflight = null;
-        if (err)
-          return callback(err, changeset);
+        if (err) return callback(err, changeset);
         window.setTimeout(function() {
           callback(null, changeset);
         }, 2500);
       });
       if (cached.length || !this.authenticated()) {
         callback(void 0, cached);
-        if (!this.authenticated())
-          return;
+        if (!this.authenticated()) return;
       }
       utilArrayChunk(toLoad, 150).forEach((function(arr) {
         oauth.xhr({
         }, wrapcb(this, done, _connectionID));
       }).bind(this));
       function done(err, payload) {
-        if (err)
-          return callback(err);
+        if (err) return callback(err);
         var options2 = { skipSeen: true };
         return parseUserJSON(payload, function(err2, results) {
-          if (err2)
-            return callback(err2);
+          if (err2) return callback(err2);
           return callback(void 0, results);
         }, options2);
       }
         path: "/api/0.6/user/" + uid + ".json"
       }, wrapcb(this, done, _connectionID));
       function done(err, payload) {
-        if (err)
-          return callback(err);
+        if (err) return callback(err);
         var options2 = { skipSeen: true };
         return parseUserJSON(payload, function(err2, results) {
-          if (err2)
-            return callback(err2);
+          if (err2) return callback(err2);
           return callback(void 0, results[0]);
         }, options2);
       }
         path: "/api/0.6/user/details.json"
       }, wrapcb(this, done, _connectionID));
       function done(err, payload) {
-        if (err)
-          return callback(err);
+        if (err) return callback(err);
         var options2 = { skipSeen: false };
         return parseUserJSON(payload, function(err2, results) {
-          if (err2)
-            return callback(err2);
+          if (err2) return callback(err2);
           _userDetails = results[0];
           return callback(void 0, _userDetails);
         }, options2);
         } else {
           var waynodes = xml.getElementsByTagName("waynodes");
           var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute("maximum"), 10);
-          if (maxWayNodes && isFinite(maxWayNodes))
-            _maxWayNodes = maxWayNodes;
+          if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
           var apiStatus = xml.getElementsByTagName("status");
           var val = apiStatus[0].getAttribute("api");
           return callback(void 0, val);
           that.status(function(err, status) {
             if (status !== _cachedApiStatus) {
               _cachedApiStatus = status;
-              dispatch10.call("apiStatusChange", that, err, status);
+              dispatch9.call("apiStatusChange", that, err, status);
             }
           });
         }, 500);
     // Load data (entities) from the API in tiles
     // GET /api/0.6/map?bbox=
     loadTiles: function(projection2, callback) {
-      if (_off)
-        return;
-      var tiles = tiler6.zoomExtent([_tileZoom4, _tileZoom4]).getTiles(projection2);
+      if (_off) return;
+      var tiles = tiler5.zoomExtent([_tileZoom3, _tileZoom3]).getTiles(projection2);
       var hadRequests = hasInflightRequests(_tileCache);
-      abortUnwantedRequests4(_tileCache, tiles);
+      abortUnwantedRequests3(_tileCache, tiles);
       if (hadRequests && !hasInflightRequests(_tileCache)) {
-        dispatch10.call("loaded");
+        dispatch9.call("loaded");
       }
       tiles.forEach(function(tile) {
         this.loadTile(tile, callback);
     // Load a single data tile
     // GET /api/0.6/map?bbox=
     loadTile: function(tile, callback) {
-      if (_off)
-        return;
-      if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id])
-        return;
+      if (_off) return;
+      if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
       if (!hasInflightRequests(_tileCache)) {
-        dispatch10.call("loading");
+        dispatch9.call("loading");
       }
       var path = "/api/0.6/map.json?bbox=";
       var options2 = { skipSeen: true };
           callback(err, Object.assign({ data: parsed }, tile));
         }
         if (!hasInflightRequests(_tileCache)) {
-          dispatch10.call("loaded");
+          dispatch9.call("loaded");
         }
       }
     },
     },
     // load the tile that covers the given `loc`
     loadTileAtLoc: function(loc, callback) {
-      if (Object.keys(_tileCache.toLoad).length > 50)
-        return;
-      var k2 = geoZoomToScale(_tileZoom4 + 1);
+      if (Object.keys(_tileCache.toLoad).length > 50) return;
+      var k2 = geoZoomToScale(_tileZoom3 + 1);
       var offset = geoRawMercator().scale(k2)(loc);
       var projection2 = geoRawMercator().transform({ k: k2, x: -offset[0], y: -offset[1] });
-      var tiles = tiler6.zoomExtent([_tileZoom4, _tileZoom4]).getTiles(projection2);
+      var tiles = tiler5.zoomExtent([_tileZoom3, _tileZoom3]).getTiles(projection2);
       tiles.forEach(function(tile) {
-        if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id])
-          return;
+        if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
         _tileCache.toLoad[tile.id] = true;
         this.loadTile(tile, callback);
       }, this);
     // GET /api/0.6/notes?bbox=
     loadNotes: function(projection2, noteOptions) {
       noteOptions = Object.assign({ limit: 1e4, closed: 7 }, noteOptions);
-      if (_off)
-        return;
+      if (_off) return;
       var that = this;
       var path = "/api/0.6/notes?limit=" + noteOptions.limit + "&closed=" + noteOptions.closed + "&bbox=";
       var throttleLoadUsers = throttle_default(function() {
         var uids = Object.keys(_userCache.toLoad);
-        if (!uids.length)
-          return;
+        if (!uids.length) return;
         that.loadUsers(uids, function() {
         });
       }, 750);
-      var tiles = tiler6.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection2);
-      abortUnwantedRequests4(_noteCache, tiles);
+      var tiles = tiler5.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection2);
+      abortUnwantedRequests3(_noteCache, tiles);
       tiles.forEach(function(tile) {
-        if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id])
-          return;
+        if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
         var options2 = { skipSeen: false };
         _noteCache.inflight[tile.id] = that.loadFromAPI(
           path + tile.extent.toParam(),
               _noteCache.loaded[tile.id] = true;
             }
             throttleLoadUsers();
-            dispatch10.call("loadedNotes");
+            dispatch9.call("loadedNotes");
           },
           options2
         );
       if (_noteCache.inflightPost[note.id]) {
         return callback({ message: "Note update already inflight", status: -2 }, note);
       }
-      if (!note.loc[0] || !note.loc[1] || !note.newComment)
-        return;
+      if (!note.loc[0] || !note.loc[1] || !note.newComment) return;
       var comment = note.newComment;
       if (note.newCategory && note.newCategory !== "None") {
         comment += " #" + note.newCategory;
         action = "reopen";
       } else {
         action = "comment";
-        if (!note.newComment)
-          return;
+        if (!note.newComment) return;
       }
       var path = "/api/0.6/notes/" + note.id + "/" + action;
       if (note.newComment) {
     },
     /* connection options for source switcher (optional) */
     apiConnections: function(val) {
-      if (!arguments.length)
-        return _apiConnections;
+      if (!arguments.length) return _apiConnections;
       _apiConnections = val;
       return this;
     },
       this.reset();
       this.userChangesets(function() {
       });
-      dispatch10.call("change");
+      dispatch9.call("change");
       return this;
     },
     toggle: function(val) {
         var target = {};
         Object.keys(source).forEach(function(k2) {
           if (k2 === "rtree") {
-            target.rtree = new import_rbush10.default().fromJSON(source.rtree.toJSON());
+            target.rtree = new RBush().fromJSON(source.rtree.toJSON());
           } else if (k2 === "note") {
             target.note = {};
             Object.keys(source.note).forEach(function(id2) {
       _userChangesets = void 0;
       _userDetails = void 0;
       oauth.logout();
-      dispatch10.call("change");
+      dispatch9.call("change");
       return this;
     },
     authenticated: function() {
       _userDetails = void 0;
       function done(err, res) {
         if (err) {
-          if (callback)
-            callback(err);
+          if (callback) callback(err);
           return;
         }
         if (that.getConnectionId() !== cid) {
-          if (callback)
-            callback({ message: "Connection Switched", status: -1 });
+          if (callback) callback({ message: "Connection Switched", status: -1 });
           return;
         }
         _rateLimitError = void 0;
-        dispatch10.call("change");
-        if (callback)
-          callback(err, res);
+        dispatch9.call("change");
+        if (callback) callback(err, res);
         that.userChangesets(function() {
         });
       }
+      oauth.options({
+        ...oauth.options(),
+        locale: _mainLocalizer.localeCode()
+      });
       oauth.authenticate(done);
     },
     imageryBlocklists: function() {
       return _imageryBlocklists;
     },
     tileZoom: function(val) {
-      if (!arguments.length)
-        return _tileZoom4;
-      _tileZoom4 = val;
+      if (!arguments.length) return _tileZoom3;
+      _tileZoom3 = val;
       return this;
     },
     // get all cached notes covering the viewport
     },
     // remove a single note from the cache
     removeNote: function(note) {
-      if (!(note instanceof osmNote) || !note.id)
-        return;
+      if (!(note instanceof osmNote) || !note.id) return;
       delete _noteCache.note[note.id];
-      updateRtree4(encodeNoteRtree(note), false);
+      updateRtree3(encodeNoteRtree(note), false);
     },
     // replace a single note in the cache
     replaceNote: function(note) {
-      if (!(note instanceof osmNote) || !note.id)
-        return;
+      if (!(note instanceof osmNote) || !note.id) return;
       _noteCache.note[note.id] = note;
-      updateRtree4(encodeNoteRtree(note), true);
+      updateRtree3(encodeNoteRtree(note), true);
       return note;
     },
     // Get an array of note IDs closed during this session.
   var _localeIDs = { en: false };
   var debouncedRequest = debounce_default(request, 500, { leading: false });
   function request(url, callback) {
-    if (_inflight2[url])
-      return;
+    if (_inflight2[url]) return;
     var controller = new AbortController();
     _inflight2[url] = controller;
     json_default(url, { signal: controller.signal }).then(function(result) {
       delete _inflight2[url];
-      if (callback)
-        callback(null, result);
+      if (callback) callback(null, result);
     }).catch(function(err) {
       delete _inflight2[url];
-      if (err.name === "AbortError")
-        return;
-      if (callback)
-        callback(err.message);
+      if (err.name === "AbortError") return;
+      if (callback) callback(err.message);
     });
   }
   var osm_wikibase_default = {
      * @param langCode string e.g. 'fr' for French
      */
     claimToValue: function(entity, property, langCode) {
-      if (!entity.claims[property])
-        return void 0;
+      if (!entity.claims[property]) return void 0;
       var locale2 = _localeIDs[langCode];
       var preferredPick, localePick;
       entity.claims[property].forEach(function(stmt) {
      * @param property string e.g. 'P31' for monolingual wiki page title
      */
     monolingualClaimToValueObj: function(entity, property) {
-      if (!entity || !entity.claims[property])
-        return void 0;
+      if (!entity || !entity.claims[property]) return void 0;
       return entity.claims[property].reduce(function(acc, obj) {
         var value = obj.mainsnak.datavalue.value;
         acc[value.language] = value.text;
             break;
           }
         }
-        if (!description && Object.values(entity.descriptions).length)
-          description = Object.values(entity.descriptions)[0];
+        if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0];
         var result = {
           title: entity.title,
           description: description ? description.value : "",
               break;
             }
           }
-          if (result.wiki)
-            break;
+          if (result.wiki) break;
         }
         callback(null, result);
         function getWikiInfo(wiki2, langCode, tKey) {
       _localeIDs[langCode] = qid;
     },
     apibase: function(val) {
-      if (!arguments.length)
-        return apibase3;
+      if (!arguments.length) return apibase3;
       apibase3 = val;
       return this;
     }
   };
 
   // modules/services/streetside.js
-  var import_rbush11 = __toESM(require_rbush_min());
   var streetsideApi = "https://dev.virtualearth.net/REST/v1/Imagery/MetaData/Streetside?mapArea={bbox}&key={key}&count={count}";
   var maxResults2 = 500;
   var bubbleAppKey = utilAesDecrypt("5c875730b09c6b422433e807e1ff060b6536c791dbfffcffc4c6b18a1bdba1f14593d151adb50e19e1be1ab19aef813bf135d0f103475e5c724dec94389e45d0");
   var pannellumViewerCSS2 = "pannellum/pannellum.css";
   var pannellumViewerJS2 = "pannellum/pannellum.js";
   var tileZoom3 = 16.5;
-  var tiler7 = utilTiler().zoomExtent([tileZoom3, tileZoom3]).skipNullIsland(true);
-  var dispatch11 = dispatch_default("loadedImages", "viewerChanged");
+  var tiler6 = utilTiler().zoomExtent([tileZoom3, tileZoom3]).skipNullIsland(true);
+  var dispatch10 = dispatch_default("loadedImages", "viewerChanged");
   var minHfov = 10;
   var maxHfov = 90;
   var defaultHfov = 45;
     cubeMap: []
   };
   var _loadViewerPromise4;
-  function abortRequest6(i3) {
+  function abortRequest5(i3) {
     i3.abort();
   }
   function localeTimestamp2(s2) {
-    if (!s2)
-      return null;
+    if (!s2) return null;
     const options2 = { day: "numeric", month: "short", year: "numeric" };
     const d2 = new Date(s2);
-    if (isNaN(d2.getTime()))
-      return null;
+    if (isNaN(d2.getTime())) return null;
     return d2.toLocaleString(_mainLocalizer.localeCode(), options2);
   }
   function loadTiles3(which, url, projection2, margin) {
-    const tiles = tiler7.margin(margin).getTiles(projection2);
+    const tiles = tiler6.margin(margin).getTiles(projection2);
     const cache = _ssCache[which];
     Object.keys(cache.inflight).forEach((k2) => {
       const wanted = tiles.find((tile) => k2.indexOf(tile.id + ",") === 0);
       if (!wanted) {
-        abortRequest6(cache.inflight[k2]);
+        abortRequest5(cache.inflight[k2]);
         delete cache.inflight[k2];
       }
     });
     const cache = _ssCache[which];
     const nextPage = cache.nextPage[tile.id] || 0;
     const id2 = tile.id + "," + String(nextPage);
-    if (cache.loaded[id2] || cache.inflight[id2])
-      return;
+    if (cache.loaded[id2] || cache.inflight[id2]) return;
     cache.inflight[id2] = getBubbles(url, tile, (response) => {
       cache.loaded[id2] = true;
       delete cache.inflight[id2];
-      if (!response)
-        return;
+      if (!response) return;
       if (response.resourceSets[0].resources.length === maxResults2) {
         const split = tile.extent.split();
         loadNextTilePage2(which, url, { id: tile.id + ",a", extent: split[0] });
       }
       const features = response.resourceSets[0].resources.map((bubble) => {
         const bubbleId = bubble.imageUrl;
-        if (cache.points[bubbleId])
-          return null;
-        const loc = [bubble.lon, bubble.lat];
+        if (cache.points[bubbleId]) return null;
+        const loc = [
+          bubble.lon || bubble.longitude,
+          bubble.lat || bubble.latitude
+        ];
         const d2 = {
           loc,
           key: bubbleId,
             "{subdomain}",
             bubble.imageUrlSubdomains[0]
           ),
-          ca: bubble.he,
+          ca: bubble.he || bubble.heading,
           captured_at: bubble.vintageEnd,
           captured_by: "microsoft",
           pano: true,
       }).filter(Boolean);
       cache.rtree.load(features);
       if (which === "bubbles") {
-        dispatch11.call("loadedImages");
+        dispatch10.call("loadedImages");
       }
     });
   }
   function partitionViewport4(projection2) {
     let z2 = geoScaleToZoom(projection2.scale());
     let z22 = Math.ceil(z2 * 2) / 2 + 2.5;
-    let tiler9 = utilTiler().zoomExtent([z22, z22]);
-    return tiler9.getTiles(projection2).map((tile) => tile.extent);
+    let tiler8 = utilTiler().zoomExtent([z22, z22]);
+    return tiler8.getTiles(projection2).map((tile) => tile.extent);
   }
   function searchLimited4(limit, projection2, rtree) {
     limit = limit || 5;
       if (!_ssCache) {
         this.reset();
       }
-      this.event = utilRebind(this, dispatch11, "on");
+      this.event = utilRebind(this, dispatch10, "on");
     },
     /**
      * reset() reset the cache.
      */
     reset: function() {
       if (_ssCache) {
-        Object.values(_ssCache.bubbles.inflight).forEach(abortRequest6);
+        Object.values(_ssCache.bubbles.inflight).forEach(abortRequest5);
       }
       _ssCache = {
-        bubbles: { inflight: {}, loaded: {}, nextPage: {}, rtree: new import_rbush11.default(), points: {} },
+        bubbles: { inflight: {}, loaded: {}, nextPage: {}, rtree: new RBush(), points: {} },
         sequences: {}
       };
     },
      * loadBubbles()
      */
     loadBubbles: function(projection2, margin) {
-      if (margin === void 0)
-        margin = 2;
+      if (margin === void 0) margin = 2;
       loadTiles3("bubbles", streetsideApi, projection2, margin);
     },
     viewer: function() {
       return _pannellumViewer2;
     },
     initViewer: function() {
-      if (!window.pannellum)
-        return;
-      if (_pannellumViewer2)
-        return;
+      if (!window.pannellum) return;
+      if (_pannellumViewer2) return;
       _currScene += 1;
       const sceneID = _currScene.toString();
       const options2 = {
       _pannellumViewer2 = window.pannellum.viewer("ideditor-viewer-streetside", options2);
     },
     ensureViewerLoaded: function(context) {
-      if (_loadViewerPromise4)
-        return _loadViewerPromise4;
+      if (_loadViewerPromise4) return _loadViewerPromise4;
       let wrap2 = context.container().select(".photoviewer").selectAll(".ms-wrapper").data([0]);
       let wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper ms-wrapper").classed("hide", true);
       let that = this;
       let pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
       wrapEnter.append("div").attr("id", "ideditor-viewer-streetside").on(pointerPrefix + "down.streetside", () => {
         select_default2(window).on(pointerPrefix + "move.streetside", () => {
-          dispatch11.call("viewerChanged");
+          dispatch10.call("viewerChanged");
         }, true);
       }).on(pointerPrefix + "up.streetside pointercancel.streetside", () => {
         select_default2(window).on(pointerPrefix + "move.streetside", null);
         let t2 = timer((elapsed) => {
-          dispatch11.call("viewerChanged");
+          dispatch10.call("viewerChanged");
           if (elapsed > 2e3) {
             t2.stop();
           }
         let loadedCount = 0;
         function loaded() {
           loadedCount += 1;
-          if (loadedCount === 2)
-            resolve();
+          if (loadedCount === 2) resolve();
         }
         const head = select_default2("head");
         head.selectAll("#ideditor-streetside-viewercss").data([0]).enter().append("link").attr("id", "ideditor-streetside-viewercss").attr("rel", "stylesheet").attr("crossorigin", "anonymous").attr("href", context.asset(pannellumViewerCSS2)).on("load.serviceStreetside", loaded).on("error.serviceStreetside", function() {
         return () => {
           let viewer = context.container().select(".photoviewer");
           let selected = viewer.empty() ? void 0 : viewer.datum();
-          if (!selected)
-            return;
+          if (!selected) return;
           let nextID = stepBy === 1 ? selected.ne : selected.pr;
           let yaw = _pannellumViewer2.getYaw();
           let ca = selected.ca + yaw;
           let poly = [p1, p2, p3, p4, p1];
           let angle2 = (stepBy === 1 ? ca : ca + 180) * (Math.PI / 180);
           poly = geoRotate(poly, -angle2, origin);
-          let extent = poly.reduce((extent2, point2) => {
-            return extent2.extend(geoExtent(point2));
+          let extent = poly.reduce((extent2, point) => {
+            return extent2.extend(geoExtent(point));
           }, geoExtent());
           let minDist = Infinity;
           _ssCache.bubbles.rtree.search(extent.bbox()).forEach((d2) => {
-            if (d2.data.key === selected.key)
-              return;
-            if (!geoPointInPolygon(d2.data.loc, poly))
-              return;
+            if (d2.data.key === selected.key) return;
+            if (!geoPointInPolygon(d2.data.loc, poly)) return;
             let dist = geoVecLength(d2.data.loc, selected.loc);
             let theta = selected.ca - d2.data.ca;
             let minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
             }
           });
           let nextBubble = nextID && that.cachedImage(nextID);
-          if (!nextBubble)
-            return;
+          if (!nextBubble) return;
           context.map().centerEase(nextBubble.loc);
           that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
         };
       }
     },
     yaw: function(yaw) {
-      if (typeof yaw !== "number")
-        return yaw;
+      if (typeof yaw !== "number") return yaw;
       _sceneOptions.yaw = yaw;
       return this;
     },
      */
     hideViewer: function(context) {
       let viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(null);
+      if (!viewer.empty()) viewer.datum(null);
       viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
       context.container().selectAll(".viewfield-group, .sequence, .icon-sign").classed("currentView", false);
       this.updateUrlImage(null);
       let that = this;
       let d2 = this.cachedImage(key);
       let viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(d2);
+      if (!viewer.empty()) viewer.datum(d2);
       this.setStyles(context, null, true);
       let wrap2 = context.container().select(".photoviewer .ms-wrapper");
       let attribution = wrap2.selectAll(".photo-attribution").html("");
       wrap2.selectAll(".pnlm-load-box").style("display", "block");
-      if (!d2)
-        return this;
+      if (!d2) return this;
       this.updateUrlImage(key);
       _sceneOptions.northOffset = d2.ca;
       let line1 = attribution.append("div").attr("class", "attribution-row");
   }
   function filterValues(allowUpperCase) {
     return function(d2) {
-      if (d2.value.match(/[;,]/) !== null)
-        return false;
-      if (!allowUpperCase && d2.value.match(/[A-Z*]/) !== null)
-        return false;
+      if (d2.value.match(/[;,]/) !== null) return false;
+      if (!allowUpperCase && d2.value.match(/[A-Z*]/) !== null) return false;
       return d2.count > 100 || d2.in_wiki;
     };
   }
   function filterRoles(geometry) {
     return function(d2) {
-      if (d2.role === "")
-        return false;
-      if (d2.role.match(/[A-Z*;,]/) !== null)
-        return false;
+      if (d2.role === "") return false;
+      if (d2.role.match(/[A-Z*;,]/) !== null) return false;
       return Number(d2[tag_members_fractions[geometry]]) > 0;
     };
   }
   }
   var debouncedRequest2 = debounce_default(request2, 300, { leading: false });
   function request2(url, params, exactMatch, callback, loaded) {
-    if (_inflight3[url])
-      return;
-    if (checkCache(url, params, exactMatch, callback))
-      return;
+    if (_inflight3[url]) return;
+    if (checkCache(url, params, exactMatch, callback)) return;
     var controller = new AbortController();
     _inflight3[url] = controller;
     json_default(url, { signal: controller.signal }).then(function(result) {
       delete _inflight3[url];
-      if (loaded)
-        loaded(null, result);
+      if (loaded) loaded(null, result);
     }).catch(function(err) {
       delete _inflight3[url];
-      if (err.name === "AbortError")
-        return;
-      if (loaded)
-        loaded(err.message);
+      if (err.name === "AbortError") return;
+      if (loaded) loaded(err.message);
     });
   }
   function checkCache(url, params, exactMatch, callback) {
         callback(null, hit);
         return true;
       }
-      if (exactMatch || !testQuery.length)
-        return false;
+      if (exactMatch || !testQuery.length) return false;
       testQuery = testQuery.slice(0, -1);
       testUrl = url.replace(/&query=(.*?)&/, "&query=" + testQuery + "&");
     } while (testQuery.length >= 0);
         lang: _mainLocalizer.languageCode()
       };
       this.keys(params, function(err, data) {
-        if (err)
-          return;
+        if (err) return;
         data.forEach(function(d2) {
-          if (d2.value === "opening_hours")
-            return;
+          if (d2.value === "opening_hours") return;
           _popularKeys[d2.value] = true;
         });
       });
       });
     },
     apibase: function(_2) {
-      if (!arguments.length)
-        return apibase4;
+      if (!arguments.length) return apibase4;
       apibase4 = _2;
       return this;
     }
   var import_fast_deep_equal11 = __toESM(require_fast_deep_equal());
   var import_fast_json_stable_stringify2 = __toESM(require_fast_json_stable_stringify());
   var import_polygon_clipping = __toESM(require_polygon_clipping_umd());
-  var import_pbf2 = __toESM(require_pbf());
-  var import_vector_tile2 = __toESM(require_vector_tile());
-  var tiler8 = utilTiler().tileSize(512).margin(1);
-  var dispatch12 = dispatch_default("loadedData");
+  var tiler7 = utilTiler().tileSize(512).margin(1);
+  var dispatch11 = dispatch_default("loadedData");
   var _vtCache;
-  function abortRequest7(controller) {
+  function abortRequest6(controller) {
     controller.abort();
   }
   function vtToGeoJSON(data, tile, mergeCache) {
-    var vectorTile = new import_vector_tile2.default.VectorTile(new import_pbf2.default(data));
+    var vectorTile = new VectorTile(new Pbf(data));
     var layers = Object.keys(vectorTile.layers);
     if (!Array.isArray(layers)) {
       layers = [layers];
           }
           var isClipped = false;
           if (geometry.type === "MultiPolygon") {
-            var featureClip = bboxClip(feature3, tile.extent.rectangle());
+            var featureClip = turf_bbox_clip_default(feature3, tile.extent.rectangle());
             if (!(0, import_fast_deep_equal11.default)(feature3.geometry, featureClip.geometry)) {
               isClipped = true;
             }
-            if (!feature3.geometry.coordinates.length)
-              continue;
-            if (!feature3.geometry.coordinates[0].length)
-              continue;
+            if (!feature3.geometry.coordinates.length) continue;
+            if (!feature3.geometry.coordinates[0].length) continue;
           }
           var featurehash = utilHashcode((0, import_fast_json_stable_stringify2.default)(feature3));
           var propertyhash = utilHashcode((0, import_fast_json_stable_stringify2.default)(feature3.properties || {}));
     return features;
   }
   function loadTile3(source, tile) {
-    if (source.loaded[tile.id] || source.inflight[tile.id])
-      return;
+    if (source.loaded[tile.id] || source.inflight[tile.id]) return;
     var url = source.template.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function(s2, r2) {
       var subdomains = r2.split(",");
       return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
         source.canMerge[z2] = {};
       }
       source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z2]);
-      dispatch12.call("loadedData");
+      dispatch11.call("loadedData");
     }).catch(function() {
       source.loaded[tile.id] = [];
       delete source.inflight[tile.id];
       if (!_vtCache) {
         this.reset();
       }
-      this.event = utilRebind(this, dispatch12, "on");
+      this.event = utilRebind(this, dispatch11, "on");
     },
     reset: function() {
       for (var sourceID in _vtCache) {
         var source = _vtCache[sourceID];
         if (source && source.inflight) {
-          Object.values(source.inflight).forEach(abortRequest7);
+          Object.values(source.inflight).forEach(abortRequest6);
         }
       }
       _vtCache = {};
     },
     data: function(sourceID, projection2) {
       var source = _vtCache[sourceID];
-      if (!source)
-        return [];
-      var tiles = tiler8.getTiles(projection2);
+      if (!source) return [];
+      var tiles = tiler7.getTiles(projection2);
       var seen = {};
       var results = [];
       for (var i3 = 0; i3 < tiles.length; i3++) {
         var features = source.loaded[tiles[i3].id];
-        if (!features || !features.length)
-          continue;
+        if (!features || !features.length) continue;
         for (var j2 = 0; j2 < features.length; j2++) {
           var feature3 = features[j2];
           var hash = feature3.__featurehash__;
-          if (seen[hash])
-            continue;
+          if (seen[hash]) continue;
           seen[hash] = true;
           results.push(Object.assign({}, feature3));
         }
       if (!source) {
         source = this.addSource(sourceID, template);
       }
-      var tiles = tiler8.getTiles(projection2);
+      var tiles = tiler7.getTiles(projection2);
       Object.keys(source.inflight).forEach(function(k2) {
         var wanted = tiles.find(function(tile) {
           return k2 === tile.id;
         });
         if (!wanted) {
-          abortRequest7(source.inflight[k2]);
+          abortRequest6(source.inflight[k2]);
           delete source.inflight[k2];
         }
       });
     // Search for Wikidata items matching the query
     itemsForSearchQuery: function(query, callback, language) {
       if (!query) {
-        if (callback)
-          callback("No query", {});
+        if (callback) callback("No query", {});
         return;
       }
       var lang = this.languagesToQuery()[0];
             throw new Error(result.error);
           }
         }
-        if (callback)
-          callback(null, result.search || {});
+        if (callback) callback(null, result.search || {});
       }).catch(function(err) {
-        if (callback)
-          callback(err.message, {});
+        if (callback) callback(err.message, {});
       });
     },
     // Given a Wikipedia language and article title,
     // return an array of corresponding Wikidata entities.
     itemsByTitle: function(lang, title, callback) {
       if (!title) {
-        if (callback)
-          callback("No title", {});
+        if (callback) callback("No title", {});
         return;
       }
       lang = lang || "en";
         if (result && result.error) {
           throw new Error(result.error);
         }
-        if (callback)
-          callback(null, result.entities || {});
+        if (callback) callback(null, result.entities || {});
       }).catch(function(err) {
-        if (callback)
-          callback(err.message, {});
+        if (callback) callback(err.message, {});
       });
     },
     languagesToQuery: function() {
         return;
       }
       if (_wikidataCache[qid]) {
-        if (callback)
-          callback(null, _wikidataCache[qid]);
+        if (callback) callback(null, _wikidataCache[qid]);
         return;
       }
       var langs = this.languagesToQuery();
         if (result && result.error) {
           throw new Error(result.error);
         }
-        if (callback)
-          callback(null, result.entities[qid] || {});
+        if (callback) callback(null, result.entities[qid] || {});
       }).catch(function(err) {
-        if (callback)
-          callback(err.message, {});
+        if (callback) callback(err.message, {});
       });
     },
     // Pass `params` object of the form:
             break;
           }
         }
-        if (!description && Object.values(entity.descriptions).length)
-          description = Object.values(entity.descriptions)[0];
+        if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0];
         var result = {
           title: entity.id,
           description: description ? description.value : "",
     },
     search: function(lang, query, callback) {
       if (!query) {
-        if (callback)
-          callback("No Query", []);
+        if (callback) callback("No Query", []);
         return;
       }
       lang = lang || "en";
           callback(null, titles);
         }
       }).catch(function(err) {
-        if (callback)
-          callback(err, []);
+        if (callback) callback(err, []);
       });
     },
     suggestions: function(lang, query, callback) {
       if (!query) {
-        if (callback)
-          callback("", []);
+        if (callback) callback("", []);
         return;
       }
       lang = lang || "en";
         } else if (!result || result.length < 2) {
           throw new Error("No Results");
         }
-        if (callback)
-          callback(null, result[1] || []);
+        if (callback) callback(null, result[1] || []);
       }).catch(function(err) {
-        if (callback)
-          callback(err.message, []);
+        if (callback) callback(err.message, []);
       });
     },
     translations: function(lang, title, callback) {
       if (!title) {
-        if (callback)
-          callback("No Title");
+        if (callback) callback("No Title");
         return;
       }
       var url = endpoint.replace("en", lang) + utilQsString({
           callback(null, translations);
         }
       }).catch(function(err) {
-        if (callback)
-          callback(err.message);
+        if (callback) callback(err.message);
       });
     }
   };
 
   // modules/services/mapilio.js
-  var import_pbf3 = __toESM(require_pbf());
-  var import_rbush12 = __toESM(require_rbush_min());
-  var import_vector_tile3 = __toESM(require_vector_tile());
   var apiUrl2 = "https://end.mapilio.com";
   var imageBaseUrl = "https://cdn.mapilio.com/im";
   var baseTileUrl2 = "https://geo.mapilio.com/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=mapilio:";
   var lineLayer = "map_roads_line";
   var tileStyle = "&STYLE=&TILEMATRIX=EPSG:900913:{z}&TILEMATRIXSET=EPSG:900913&FORMAT=application/vnd.mapbox-vector-tile&TILECOL={x}&TILEROW={y}";
   var minZoom3 = 14;
-  var dispatch13 = dispatch_default("loadedImages", "loadedLines");
+  var dispatch12 = dispatch_default("loadedImages", "loadedLines");
   var imgZoom3 = zoom_default2().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
   var pannellumViewerCSS3 = "pannellum/pannellum.css";
   var pannellumViewerJS3 = "pannellum/pannellum.js";
   var resolution = 1080;
   var _activeImage;
-  var _cache4;
+  var _cache3;
   var _loadViewerPromise5;
   var _pannellumViewer3;
   var _sceneOptions2 = {
   function partitionViewport5(projection2) {
     const z2 = geoScaleToZoom(projection2.scale());
     const z22 = Math.ceil(z2 * 2) / 2 + 2.5;
-    const tiler9 = utilTiler().zoomExtent([z22, z22]);
-    return tiler9.getTiles(projection2).map(function(tile) {
+    const tiler8 = utilTiler().zoomExtent([z22, z22]);
+    return tiler8.getTiles(projection2).map(function(tile) {
       return tile.extent;
     });
   }
     }, []);
   }
   function loadTiles4(which, url, maxZoom2, projection2) {
-    const tiler9 = utilTiler().zoomExtent([minZoom3, maxZoom2]).skipNullIsland(true);
-    const tiles = tiler9.getTiles(projection2);
+    const tiler8 = utilTiler().zoomExtent([minZoom3, maxZoom2]).skipNullIsland(true);
+    const tiles = tiler8.getTiles(projection2);
     tiles.forEach(function(tile) {
       loadTile4(which, url, tile);
     });
   }
   function loadTile4(which, url, tile) {
-    const cache = _cache4.requests;
+    const cache = _cache3.requests;
     const tileId = "".concat(tile.id, "-").concat(which);
-    if (cache.loaded[tileId] || cache.inflight[tileId])
-      return;
+    if (cache.loaded[tileId] || cache.inflight[tileId]) return;
     const controller = new AbortController();
     cache.inflight[tileId] = controller;
     const requestUrl = url.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace("{z}", tile.xyz[2]);
       }
       loadTileDataToCache2(data, tile, which);
       if (which === "images") {
-        dispatch13.call("loadedImages");
+        dispatch12.call("loadedImages");
       } else {
-        dispatch13.call("loadedLines");
+        dispatch12.call("loadedLines");
       }
     }).catch(function(e3) {
       if (e3.message === "No Data") {
     });
   }
   function loadTileDataToCache2(data, tile) {
-    const vectorTile = new import_vector_tile3.VectorTile(new import_pbf3.default(data));
+    const vectorTile = new VectorTile(new Pbf(data));
     let features, cache, layer, i3, feature3, loc, d2;
     if (vectorTile.layers.hasOwnProperty(pointLayer)) {
       features = [];
-      cache = _cache4.images;
+      cache = _cache3.images;
       layer = vectorTile.layers[pointLayer];
       for (i3 = 0; i3 < layer.length; i3++) {
         feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
       }
     }
     if (vectorTile.layers.hasOwnProperty(lineLayer)) {
-      cache = _cache4.sequences;
+      cache = _cache3.sequences;
       layer = vectorTile.layers[lineLayer];
       for (i3 = 0; i3 < layer.length; i3++) {
         feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
   var mapilio_default = {
     // Initialize Mapilio
     init: function() {
-      if (!_cache4) {
+      if (!_cache3) {
         this.reset();
       }
-      this.event = utilRebind(this, dispatch13, "on");
+      this.event = utilRebind(this, dispatch12, "on");
     },
     // Reset cache and state
     reset: function() {
-      if (_cache4) {
-        Object.values(_cache4.requests.inflight).forEach(function(request3) {
+      if (_cache3) {
+        Object.values(_cache3.requests.inflight).forEach(function(request3) {
           request3.abort();
         });
       }
-      _cache4 = {
-        images: { rtree: new import_rbush12.default(), forImageId: {} },
-        sequences: { rtree: new import_rbush12.default(), lineString: {} },
+      _cache3 = {
+        images: { rtree: new RBush(), forImageId: {} },
+        sequences: { rtree: new RBush(), lineString: {} },
         requests: { loaded: {}, inflight: {} }
       };
       _activeImage = null;
     // Get visible images
     images: function(projection2) {
       const limit = 5;
-      return searchLimited5(limit, projection2, _cache4.images.rtree);
+      return searchLimited5(limit, projection2, _cache3.images.rtree);
     },
     cachedImage: function(imageKey) {
-      return _cache4.images.forImageId[imageKey];
+      return _cache3.images.forImageId[imageKey];
     },
     // Load images in the visible area
     loadImages: function(projection2) {
       const bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
       const sequenceIds = {};
       let lineStrings = [];
-      _cache4.images.rtree.search(bbox2).forEach(function(d2) {
+      _cache3.images.rtree.search(bbox2).forEach(function(d2) {
         if (d2.data.sequence_id) {
           sequenceIds[d2.data.sequence_id] = true;
         }
       });
       Object.keys(sequenceIds).forEach(function(sequenceId) {
-        if (_cache4.sequences.lineString[sequenceId]) {
-          lineStrings = lineStrings.concat(_cache4.sequences.lineString[sequenceId]);
+        if (_cache3.sequences.lineString[sequenceId]) {
+          lineStrings = lineStrings.concat(_cache3.sequences.lineString[sequenceId]);
         }
       });
       return lineStrings;
       }
     },
     initViewer: function() {
-      if (!window.pannellum)
-        return;
-      if (_pannellumViewer3)
-        return;
+      if (!window.pannellum) return;
+      if (_pannellumViewer3) return;
       _currScene2 += 1;
       const sceneID = _currScene2.toString();
       const options2 = {
       this.setActiveImage(d2);
       this.updateUrlImage(d2.id);
       let viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(d2);
+      if (!viewer.empty()) viewer.datum(d2);
       this.setStyles(context, null);
-      if (!d2)
-        return this;
+      if (!d2) return this;
       let wrap2 = context.container().select(".photoviewer .mapilio-wrapper");
       let attribution = wrap2.selectAll(".photo-attribution").text("");
       if (d2.capture_time) {
       attribution.append("a").attr("class", "image-link").attr("target", "_blank").attr("href", "https://mapilio.com/app?lat=".concat(d2.loc[1], "&lng=").concat(d2.loc[0], "&zoom=17&pId=").concat(d2.id)).text("mapilio.com");
       wrap2.transition().duration(100).call(imgZoom3.transform, identity2);
       wrap2.selectAll("img").remove();
-      wrap2.selectAll("button.back").classed("hide", !_cache4.images.forImageId.hasOwnProperty(+id2 - 1));
-      wrap2.selectAll("button.forward").classed("hide", !_cache4.images.forImageId.hasOwnProperty(+id2 + 1));
+      wrap2.selectAll("button.back").classed("hide", !_cache3.images.forImageId.hasOwnProperty(+id2 - 1));
+      wrap2.selectAll("button.forward").classed("hide", !_cache3.images.forImageId.hasOwnProperty(+id2 + 1));
       getImageData(d2.id, d2.sequence_id).then(function() {
         if (d2.isPano) {
           if (!_pannellumViewer3) {
         }
       });
       function localeDateString2(s2) {
-        if (!s2)
-          return null;
+        if (!s2) return null;
         var options2 = { day: "numeric", month: "short", year: "numeric" };
         var d4 = new Date(s2);
-        if (isNaN(d4.getTime()))
-          return null;
+        if (isNaN(d4.getTime())) return null;
         return d4.toLocaleDateString(_mainLocalizer.localeCode(), options2);
       }
       return this;
       if (!imgWrap.empty()) {
         imgWrap.remove();
       }
-      if (_loadViewerPromise5)
-        return _loadViewerPromise5;
+      if (_loadViewerPromise5) return _loadViewerPromise5;
       let wrap2 = context.container().select(".photoviewer").selectAll(".mapilio-wrapper").data([0]);
       let wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper mapilio-wrapper").classed("hide", true).on("dblclick.zoom", null);
       wrapEnter.append("div").attr("class", "photo-attribution fillD");
         let loadedCount = 0;
         function loaded() {
           loadedCount += 1;
-          if (loadedCount === 2)
-            resolve();
+          if (loadedCount === 2) resolve();
         }
         const head = select_default2("head");
         head.selectAll("#ideditor-mapilio-viewercss").data([0]).enter().append("link").attr("id", "ideditor-mapilio-viewercss").attr("rel", "stylesheet").attr("crossorigin", "anonymous").attr("href", context.asset(pannellumViewerCSS3)).on("load.serviceMapilio", loaded).on("error.serviceMapilio", function() {
       });
       function step(stepBy) {
         return function() {
-          if (!_activeImage)
-            return;
+          if (!_activeImage) return;
           const imageId = _activeImage.id;
           const nextIndex = imageId + stepBy;
-          if (!nextIndex)
-            return;
-          const nextImage = _cache4.images.forImageId[nextIndex];
+          if (!nextIndex) return;
+          const nextImage = _cache3.images.forImageId[nextIndex];
           context.map().centerEase(nextImage.loc);
           that.selectImage(context, nextImage.id);
         };
      */
     hideViewer: function(context) {
       let viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(null);
+      if (!viewer.empty()) viewer.datum(null);
       this.updateUrlImage(null);
       viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
       context.container().selectAll(".viewfield-group, .sequence, .icon-sign").classed("currentView", false);
       return this.setStyles(context, null);
     },
     // Return the current cache
+    cache: function() {
+      return _cache3;
+    }
+  };
+
+  // modules/services/panoramax.js
+  var apiUrl3 = "https://api.panoramax.xyz/";
+  var tileUrl2 = apiUrl3 + "api/map/{z}/{x}/{y}.mvt";
+  var imageDataUrl = apiUrl3 + "api/collections/{collectionId}/items/{itemId}";
+  var userIdUrl = apiUrl3 + "api/users/search?q={username}";
+  var usernameURL = apiUrl3 + "api/users/{userId}";
+  var viewerUrl = apiUrl3;
+  var highDefinition = "hd";
+  var standardDefinition = "sd";
+  var pictureLayer = "pictures";
+  var sequenceLayer = "sequences";
+  var minZoom4 = 10;
+  var imageMinZoom = 15;
+  var lineMinZoom = 10;
+  var dispatch13 = dispatch_default("loadedImages", "loadedLines", "viewerChanged");
+  var _cache4;
+  var _loadViewerPromise6;
+  var _definition = standardDefinition;
+  var _isHD = false;
+  var _planeFrame2;
+  var _pannellumFrame2;
+  var _currentFrame2;
+  var _oldestDate;
+  var _currentScene = {
+    currentImage: null,
+    nextImage: null,
+    prevImage: null
+  };
+  var _activeImage2;
+  function partitionViewport6(projection2) {
+    const z2 = geoScaleToZoom(projection2.scale());
+    const z22 = Math.ceil(z2 * 2) / 2 + 2.5;
+    const tiler8 = utilTiler().zoomExtent([z22, z22]);
+    return tiler8.getTiles(projection2).map(function(tile) {
+      return tile.extent;
+    });
+  }
+  function searchLimited6(limit, projection2, rtree) {
+    limit = limit || 5;
+    return partitionViewport6(projection2).reduce(function(result, extent) {
+      let found = rtree.search(extent.bbox());
+      const spacing = Math.max(1, Math.floor(found.length / limit));
+      found = found.filter((d2, idx) => idx % spacing === 0 || d2.data.id === (_activeImage2 == null ? void 0 : _activeImage2.id)).sort((a2, b2) => {
+        if (a2.data.id === (_activeImage2 == null ? void 0 : _activeImage2.id)) return -1;
+        if (b2.data.id === (_activeImage2 == null ? void 0 : _activeImage2.id)) return 1;
+        return 0;
+      }).slice(0, limit).map((d2) => d2.data);
+      return found.length ? result.concat(found) : result;
+    }, []);
+  }
+  function loadTiles5(which, url, maxZoom2, projection2, zoom) {
+    const tiler8 = utilTiler().zoomExtent([minZoom4, maxZoom2]).skipNullIsland(true);
+    const tiles = tiler8.getTiles(projection2);
+    tiles.forEach(function(tile) {
+      loadTile5(which, url, tile, zoom);
+    });
+  }
+  function loadTile5(which, url, tile, zoom) {
+    const cache = _cache4.requests;
+    const tileId = "".concat(tile.id, "-").concat(which);
+    if (cache.loaded[tileId] || cache.inflight[tileId]) return;
+    const controller = new AbortController();
+    cache.inflight[tileId] = controller;
+    const requestUrl = url.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace("{z}", tile.xyz[2]);
+    fetch(requestUrl, { signal: controller.signal }).then(function(response) {
+      if (!response.ok) {
+        throw new Error(response.status + " " + response.statusText);
+      }
+      cache.loaded[tileId] = true;
+      delete cache.inflight[tileId];
+      return response.arrayBuffer();
+    }).then(function(data) {
+      if (data.byteLength === 0) {
+        throw new Error("No Data");
+      }
+      loadTileDataToCache3(data, tile, zoom);
+      if (which === "images") {
+        dispatch13.call("loadedImages");
+      } else {
+        dispatch13.call("loadedLines");
+      }
+    }).catch(function(e3) {
+      if (e3.message === "No Data") {
+        cache.loaded[tileId] = true;
+      } else {
+        console.error(e3);
+      }
+    });
+  }
+  function loadTileDataToCache3(data, tile, zoom) {
+    const vectorTile = new VectorTile(new Pbf(data));
+    let features, cache, layer, i3, feature3, loc, d2;
+    if (vectorTile.layers.hasOwnProperty(pictureLayer)) {
+      features = [];
+      cache = _cache4.images;
+      layer = vectorTile.layers[pictureLayer];
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        d2 = {
+          loc,
+          capture_time: feature3.properties.ts,
+          capture_time_parsed: new Date(feature3.properties.ts),
+          id: feature3.properties.id,
+          account_id: feature3.properties.account_id,
+          sequence_id: feature3.properties.sequences.split('"')[1],
+          heading: parseInt(feature3.properties.heading, 10),
+          image_path: "",
+          resolution: feature3.properties.resolution,
+          isPano: feature3.properties.type === "equirectangular",
+          model: feature3.properties.model
+        };
+        cache.forImageId[d2.id] = d2;
+        features.push({
+          minX: loc[0],
+          minY: loc[1],
+          maxX: loc[0],
+          maxY: loc[1],
+          data: d2
+        });
+        if (_oldestDate) {
+          if (d2.capture_time < _oldestDate) {
+            _oldestDate = d2.capture_time;
+          }
+        } else {
+          _oldestDate = d2.capture_time;
+        }
+      }
+      if (cache.rtree) {
+        cache.rtree.load(features);
+      }
+    }
+    if (vectorTile.layers.hasOwnProperty(sequenceLayer)) {
+      cache = _cache4.sequences;
+      if (zoom >= lineMinZoom && zoom < imageMinZoom) cache = _cache4.mockSequences;
+      layer = vectorTile.layers[sequenceLayer];
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        if (cache.lineString[feature3.properties.id]) {
+          cache.lineString[feature3.properties.id].push(feature3);
+        } else {
+          cache.lineString[feature3.properties.id] = [feature3];
+        }
+        if (_oldestDate) {
+          if (feature3.properties.date < _oldestDate) {
+            _oldestDate = feature3.properties.date;
+          }
+        } else {
+          _oldestDate = feature3.properties.date;
+        }
+      }
+    }
+  }
+  async function getImageData2(collection_id, image_id) {
+    const requestUrl = imageDataUrl.replace("{collectionId}", collection_id).replace("{itemId}", image_id);
+    const response = await fetch(requestUrl, { method: "GET" });
+    if (!response.ok) {
+      throw new Error(response.status + " " + response.statusText);
+    }
+    const data = await response.json();
+    return data;
+  }
+  async function getUsername(user_id) {
+    const requestUrl = usernameURL.replace("{userId}", user_id);
+    const response = await fetch(requestUrl, { method: "GET" });
+    if (!response.ok) {
+      throw new Error(response.status + " " + response.statusText);
+    }
+    const data = await response.json();
+    return data.name;
+  }
+  var panoramax_default = {
+    init: function() {
+      if (!_cache4) {
+        this.reset();
+      }
+      this.event = utilRebind(this, dispatch13, "on");
+    },
+    reset: function() {
+      if (_cache4) {
+        Object.values(_cache4.requests.inflight).forEach(function(request3) {
+          request3.abort();
+        });
+      }
+      _cache4 = {
+        images: { rtree: new RBush(), forImageId: {} },
+        sequences: { rtree: new RBush(), lineString: {} },
+        mockSequences: { rtree: new RBush(), lineString: {} },
+        requests: { loaded: {}, inflight: {} }
+      };
+      _currentScene.currentImage = null;
+      _activeImage2 = null;
+    },
+    // Get visible images
+    images: function(projection2) {
+      const limit = 5;
+      return searchLimited6(limit, projection2, _cache4.images.rtree);
+    },
+    cachedImage: function(imageKey) {
+      return _cache4.images.forImageId[imageKey];
+    },
+    // Load images in the visible area
+    loadImages: function(projection2) {
+      loadTiles5("images", tileUrl2, imageMinZoom, projection2);
+    },
+    // Load line in the visible area
+    loadLines: function(projection2, zoom) {
+      loadTiles5("line", tileUrl2, lineMinZoom, projection2, zoom);
+    },
+    getUserIds: async function(usernames) {
+      const requestUrls = usernames.map((username) => userIdUrl.replace("{username}", username));
+      const responses = await Promise.all(requestUrls.map((requestUrl) => fetch(requestUrl, { method: "GET" })));
+      if (responses.some((response) => !response.ok)) {
+        const response = responses.find((response2) => !response2.ok);
+        throw new Error(response.status + " " + response.statusText);
+      }
+      const data = await Promise.all(responses.map((response) => response.json()));
+      return data.flatMap((d2, i3) => d2.features.filter((f2) => f2.name === usernames[i3]).map((f2) => f2.id));
+    },
+    getOldestDate: function() {
+      return _oldestDate;
+    },
+    // Get visible sequences
+    sequences: function(projection2, zoom) {
+      const viewport = projection2.clipExtent();
+      const min3 = [viewport[0][0], viewport[1][1]];
+      const max3 = [viewport[1][0], viewport[0][1]];
+      const bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
+      const sequenceIds = {};
+      let lineStrings = [];
+      if (zoom >= imageMinZoom) {
+        _cache4.images.rtree.search(bbox2).forEach(function(d2) {
+          if (d2.data.sequence_id) {
+            sequenceIds[d2.data.sequence_id] = true;
+          }
+        });
+        Object.keys(sequenceIds).forEach(function(sequenceId) {
+          if (_cache4.sequences.lineString[sequenceId]) {
+            lineStrings = lineStrings.concat(_cache4.sequences.lineString[sequenceId]);
+          }
+        });
+        return lineStrings;
+      }
+      if (zoom >= lineMinZoom) {
+        Object.keys(_cache4.mockSequences.lineString).forEach(function(sequenceId) {
+          lineStrings = lineStrings.concat(_cache4.mockSequences.lineString[sequenceId]);
+        });
+      }
+      return lineStrings;
+    },
+    // Set the currently visible image
+    setActiveImage: function(image) {
+      if (image) {
+        _activeImage2 = {
+          id: image.id,
+          sequence_id: image.sequence_id
+        };
+      } else {
+        _activeImage2 = null;
+      }
+    },
+    getActiveImage: function() {
+      return _activeImage2;
+    },
+    // Update the currently highlighted sequence and selected bubble.
+    setStyles: function(context, hovered) {
+      const hoveredImageId = hovered && hovered.id;
+      const hoveredSequenceId = hovered && hovered.sequence_id;
+      const selectedSequenceId = _activeImage2 && _activeImage2.sequence_id;
+      const selectedImageId = _activeImage2 && _activeImage2.id;
+      const markers = context.container().selectAll(".layer-panoramax .viewfield-group");
+      const sequences = context.container().selectAll(".layer-panoramax .sequence");
+      markers.classed("highlighted", function(d2) {
+        return d2.sequence_id === selectedSequenceId || d2.id === hoveredImageId;
+      }).classed("hovered", function(d2) {
+        return d2.id === hoveredImageId;
+      }).classed("currentView", function(d2) {
+        return d2.id === selectedImageId;
+      });
+      sequences.classed("highlighted", function(d2) {
+        return d2.properties.id === hoveredSequenceId;
+      }).classed("currentView", function(d2) {
+        return d2.properties.id === selectedSequenceId;
+      });
+      context.container().selectAll(".layer-panoramax .viewfield-group .viewfield").attr("d", viewfieldPath);
+      function viewfieldPath() {
+        let d2 = this.parentNode.__data__;
+        if (d2.isPano && d2.id !== selectedImageId) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
+        } else {
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+        }
+      }
+      return this;
+    },
+    updateUrlImage: function(imageKey) {
+      if (!window.mocha) {
+        var hash = utilStringQs(window.location.hash);
+        if (imageKey) {
+          hash.photo = "panoramax/" + imageKey;
+        } else {
+          delete hash.photo;
+        }
+        window.location.replace("#" + utilQsString(hash, true));
+      }
+    },
+    selectImage: function(context, id2) {
+      let that = this;
+      let d2 = that.cachedImage(id2);
+      that.setActiveImage(d2);
+      that.updateUrlImage(d2.id);
+      const viewerLink = "".concat(viewerUrl, "#pic=").concat(d2.id, "&focus=pic");
+      let viewer = context.container().select(".photoviewer");
+      if (!viewer.empty()) viewer.datum(d2);
+      this.setStyles(context, null);
+      if (!d2) return this;
+      let wrap2 = context.container().select(".photoviewer .panoramax-wrapper");
+      let attribution = wrap2.selectAll(".photo-attribution").text("");
+      let line1 = attribution.append("div").attr("class", "attribution-row");
+      const hdDomId = utilUniqueDomId("panoramax-hd");
+      let label = line1.append("label").attr("for", hdDomId).attr("class", "panoramax-hd");
+      label.append("input").attr("type", "checkbox").attr("id", hdDomId).property("checked", _isHD).on("click", (d3_event) => {
+        d3_event.stopPropagation();
+        _isHD = !_isHD;
+        _definition = _isHD ? highDefinition : standardDefinition;
+        that.selectImage(context, d2.id).showViewer(context);
+      });
+      label.append("span").call(_t.append("panoramax.hd"));
+      if (d2.capture_time) {
+        attribution.append("span").attr("class", "captured_at").text(localeDateString2(d2.capture_time));
+        attribution.append("span").text("|");
+      }
+      attribution.append("a").attr("class", "report-photo").attr("href", "mailto:signalement.ign@panoramax.fr").call(_t.append("panoramax.report"));
+      attribution.append("span").text("|");
+      attribution.append("a").attr("class", "image-link").attr("target", "_blank").attr("href", viewerLink).text("panoramax.xyz");
+      getImageData2(d2.sequence_id, d2.id).then(function(data) {
+        _currentScene = {
+          currentImage: null,
+          nextImage: null,
+          prevImage: null
+        };
+        _currentScene.currentImage = data.assets[_definition];
+        const nextIndex = data.links.findIndex((x2) => x2.rel === "next");
+        const prevIndex = data.links.findIndex((x2) => x2.rel === "prev");
+        if (nextIndex !== -1) {
+          _currentScene.nextImage = data.links[nextIndex];
+        }
+        if (prevIndex !== -1) {
+          _currentScene.prevImage = data.links[prevIndex];
+        }
+        d2.image_path = _currentScene.currentImage.href;
+        wrap2.selectAll("button.back").classed("hide", _currentScene.prevImage === null);
+        wrap2.selectAll("button.forward").classed("hide", _currentScene.nextImage === null);
+        _currentFrame2 = d2.isPano ? _pannellumFrame2 : _planeFrame2;
+        _currentFrame2.showPhotoFrame(wrap2).selectPhoto(d2, true);
+      });
+      function localeDateString2(s2) {
+        if (!s2) return null;
+        var options2 = { day: "numeric", month: "short", year: "numeric" };
+        var d4 = new Date(s2);
+        if (isNaN(d4.getTime())) return null;
+        return d4.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+      }
+      if (d2.account_id) {
+        attribution.append("span").text("|");
+        let line2 = attribution.append("span").attr("class", "attribution-row");
+        getUsername(d2.account_id).then(function(username) {
+          line2.append("span").attr("class", "captured_by").text(_t("panoramax.captured_by", { username }));
+        });
+      }
+      return this;
+    },
+    photoFrame: function() {
+      return _currentFrame2;
+    },
+    ensureViewerLoaded: function(context) {
+      let that = this;
+      let imgWrap = context.container().select("#ideditor-viewer-panoramax-simple > img");
+      if (!imgWrap.empty()) {
+        imgWrap.remove();
+      }
+      if (_loadViewerPromise6) return _loadViewerPromise6;
+      let wrap2 = context.container().select(".photoviewer").selectAll(".panoramax-wrapper").data([0]);
+      let wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper panoramax-wrapper").classed("hide", true).on("dblclick.zoom", null);
+      wrapEnter.append("div").attr("class", "photo-attribution fillD");
+      const controlsEnter = wrapEnter.append("div").attr("class", "photo-controls-wrap").append("div").attr("class", "photo-controls-panoramax");
+      controlsEnter.append("button").classed("back", true).on("click.back", step(-1)).text("\u25C4");
+      controlsEnter.append("button").classed("forward", true).on("click.forward", step(1)).text("\u25BA");
+      _loadViewerPromise6 = Promise.all([
+        pannellum_photo_default.init(context, wrapEnter),
+        plane_photo_default.init(context, wrapEnter)
+      ]).then(([pannellumPhotoFrame, planePhotoFrame]) => {
+        _pannellumFrame2 = pannellumPhotoFrame;
+        _pannellumFrame2.event.on("viewerChanged", () => dispatch13.call("viewerChanged"));
+        _planeFrame2 = planePhotoFrame;
+        _planeFrame2.event.on("viewerChanged", () => dispatch13.call("viewerChanged"));
+      });
+      function step(stepBy) {
+        return function() {
+          if (!_currentScene.currentImage) return;
+          let nextId;
+          if (stepBy === 1) nextId = _currentScene.nextImage.id;
+          else nextId = _currentScene.prevImage.id;
+          if (!nextId) return;
+          const nextImage = _cache4.images.forImageId[nextId];
+          if (nextImage) {
+            context.map().centerEase(nextImage.loc);
+            that.selectImage(context, nextImage.id);
+          }
+        };
+      }
+      return _loadViewerPromise6;
+    },
+    showViewer: function(context) {
+      let wrap2 = context.container().select(".photoviewer").classed("hide", false);
+      let isHidden = wrap2.selectAll(".photo-wrapper.panoramax-wrapper.hide").size();
+      if (isHidden) {
+        wrap2.selectAll(".photo-wrapper:not(.panoramax-wrapper)").classed("hide", true);
+        wrap2.selectAll(".photo-wrapper.panoramax-wrapper").classed("hide", false);
+      }
+      return this;
+    },
+    hideViewer: function(context) {
+      let viewer = context.container().select(".photoviewer");
+      if (!viewer.empty()) viewer.datum(null);
+      this.updateUrlImage(null);
+      viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
+      context.container().selectAll(".viewfield-group, .sequence, .icon-sign").classed("currentView", false);
+      this.setActiveImage();
+      return this.setStyles(context, null);
+    },
     cache: function() {
       return _cache4;
     }
   var services = {
     geocoder: nominatim_default,
     keepRight: keepRight_default,
-    improveOSM: improveOSM_default,
     osmose: osmose_default,
     mapillary: mapillary_default,
     nsi: nsi_default,
     vectorTile: vector_tile_default,
     wikidata: wikidata_default,
     wikipedia: wikipedia_default,
-    mapilio: mapilio_default
+    mapilio: mapilio_default,
+    panoramax: panoramax_default
   };
 
   // modules/modes/drag_note.js
     var _lastLoc;
     var _note;
     function startNudge(d3_event, nudge) {
-      if (_nudgeInterval)
-        window.clearInterval(_nudgeInterval);
+      if (_nudgeInterval) window.clearInterval(_nudgeInterval);
       _nudgeInterval = window.setInterval(function() {
         context.map().pan(nudge);
         doMove(d3_event, nudge);
       context.enter(mode);
       context.selectedNoteID(_note.id);
     }
-    function move(d3_event, entity, point2) {
+    function move(d3_event, entity, point) {
       d3_event.stopPropagation();
-      _lastLoc = context.projection.invert(point2);
+      _lastLoc = context.projection.invert(point);
       doMove(d3_event);
-      var nudge = geoViewportEdge(point2, context.map().dimensions());
+      var nudge = geoViewportEdge(point, context.map().dimensions());
       if (nudge) {
         startNudge(d3_event, nudge);
       } else {
       }
     }
     function esc() {
-      if (context.container().select(".combobox").size())
-        return;
+      if (context.container().select(".combobox").size()) return;
       context.enter(modeBrowse(context));
     }
     mode.zoomToSelected = function() {
     function keydown(d3_event) {
       if (d3_event.keyCode === 32) {
         var activeNode = document.activeElement;
-        if (activeNode && (/* @__PURE__ */ new Set(["INPUT", "TEXTAREA"])).has(activeNode.nodeName))
-          return;
+        if (activeNode && (/* @__PURE__ */ new Set(["INPUT", "TEXTAREA"])).has(activeNode.nodeName)) return;
       }
       if (d3_event.keyCode === 93 || // context menu key
       d3_event.keyCode === 32) {
         d3_event.preventDefault();
       }
-      if (d3_event.repeat)
-        return;
+      if (d3_event.repeat) return;
       cancelLongPress();
       if (d3_event.shiftKey) {
         context.surface().classed("behavior-multiselect", true);
         var pointer = _downPointers.spacebar;
         if (pointer) {
           delete _downPointers.spacebar;
-          if (pointer.done)
-            return;
+          if (pointer.done) return;
           d3_event.preventDefault();
           _lastInteractionType = "spacebar";
           click(pointer.firstEvent, pointer.lastEvent, "spacebar");
     function pointerdown(d3_event) {
       var id2 = (d3_event.pointerId || "mouse").toString();
       cancelLongPress();
-      if (d3_event.buttons && d3_event.buttons !== 1)
-        return;
+      if (d3_event.buttons && d3_event.buttons !== 1) return;
       context.ui().closeEditMenu();
       if (d3_event.pointerType !== "mouse") {
         _longPressTimeout = window.setTimeout(didLongPress, 500, id2, "longdown-" + (d3_event.pointerType || "mouse"));
     }
     function didLongPress(id2, interactionType) {
       var pointer = _downPointers[id2];
-      if (!pointer)
-        return;
+      if (!pointer) return;
       for (var i3 in _downPointers) {
         _downPointers[i3].done = true;
       }
     function pointerup(d3_event) {
       var id2 = (d3_event.pointerId || "mouse").toString();
       var pointer = _downPointers[id2];
-      if (!pointer)
-        return;
+      if (!pointer) return;
       delete _downPointers[id2];
       if (_multiselectionPointerId === id2) {
         _multiselectionPointerId = null;
       }
-      if (pointer.done)
-        return;
+      if (pointer.done) return;
       click(pointer.firstEvent, d3_event, id2);
     }
     function pointercancel(d3_event) {
       var id2 = (d3_event.pointerId || "mouse").toString();
-      if (!_downPointers[id2])
-        return;
+      if (!_downPointers[id2]) return;
       delete _downPointers[id2];
       if (_multiselectionPointerId === id2) {
         _multiselectionPointerId = null;
         var mode = context.mode();
         var selectedIDs = mode.id === "select" ? mode.selectedIDs() : [];
         for (var pointerId2 in _downPointers) {
-          if (pointerId2 === "spacebar" || pointerId2 === skipPointerId)
-            continue;
+          if (pointerId2 === "spacebar" || pointerId2 === skipPointerId) continue;
           var pointerInfo = _downPointers[pointerId2];
           var p12 = pointGetter(pointerInfo.firstEvent);
           var p22 = pointGetter(pointerInfo.lastEvent);
-          if (geoVecLength(p12, p22) > _tolerancePx)
-            continue;
+          if (geoVecLength(p12, p22) > _tolerancePx) continue;
           var datum2 = pointerInfo.firstEvent.target.__data__;
           var entity = datum2 && datum2.properties && datum2.properties.entity || datum2;
           if (context.graph().hasEntity(entity.id)) {
         return null;
       }
     }
-    function processClick(datum2, isMultiselect, point2, alsoSelectId) {
+    function processClick(datum2, isMultiselect, point, alsoSelectId) {
       var mode = context.mode();
       var showMenu = _showMenu;
       var interactionType = _lastInteractionType;
       var entity = datum2 && datum2.properties && datum2.properties.entity;
-      if (entity)
-        datum2 = entity;
+      if (entity) datum2 = entity;
       if (datum2 && datum2.type === "midpoint") {
         datum2 = datum2.parents[0];
       }
         context.selectedErrorID(null);
         if (!isMultiselect) {
           if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum2.id) === -1) {
-            if (alsoSelectId === datum2.id)
-              alsoSelectId = null;
+            if (alsoSelectId === datum2.id) alsoSelectId = null;
             selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum2.id]);
             newMode = mode.id === "select" ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
             context.enter(newMode);
         }
       }
       context.ui().closeEditMenu();
-      if (showMenu)
-        context.ui().showEditMenu(point2, interactionType);
+      if (showMenu) context.ui().showEditMenu(point, interactionType);
       resetProperties();
     }
     function cancelLongPress() {
-      if (_longPressTimeout)
-        window.clearTimeout(_longPressTimeout);
+      if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
       _longPressTimeout = null;
     }
     function resetProperties() {
             if (way.nodes.indexOf(node.id) !== -1) {
               count += 1;
             }
-            if (count > 1)
-              break;
+            if (count > 1) break;
           }
           if (count > 1) {
             sharedActions.push(action);
       return _disconnectingVertexIds;
     };
     operation2.available = function() {
-      if (_actions.length === 0)
-        return false;
-      if (_otherIDs.length !== 0)
-        return false;
+      if (_actions.length === 0) return false;
+      if (_otherIDs.length !== 0) return false;
       if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function(wayID) {
         return _vertexIDs.some(function(vertexID) {
           var way = context.entity(wayID);
           return way.nodes.indexOf(vertexID) !== -1;
         });
-      }))
-        return false;
+      })) return false;
       return true;
     };
     operation2.disabled = function() {
       var reason;
       for (var actionIndex in _actions) {
         reason = _actions[actionIndex].disabled(context.graph());
-        if (reason)
-          return reason;
+        if (reason) return reason;
       }
       if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
         return "too_large." + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? "single" : "multiple");
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = _coords.filter(function(loc) {
       var graph = context.graph();
       var entity = graph.entity(entityID);
       var preset = _mainPresetIndex.match(entity, graph);
-      if (!preset || preset.isFallback())
-        return null;
+      if (!preset || preset.isFallback()) return null;
       if (entity.type === "node" && preset.id !== "address" && Object.keys(entity.tags).some(function(key) {
         return key.match(/^addr:.{1,}/);
       })) {
         for (var i3 in selectedIDs) {
           var entityID = selectedIDs[i3];
           var type2 = downgradeTypeForEntityID(entityID);
-          if (!type2)
-            continue;
+          if (!type2) continue;
           var tags = Object.assign({}, graph.entity(entityID).tags);
           for (var key in tags) {
-            if (type2 === "address" && addressKeysToKeep.indexOf(key) !== -1)
-              continue;
+            if (type2 === "address" && addressKeysToKeep.indexOf(key) !== -1) continue;
             if (type2 === "building") {
-              if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/))
-                continue;
+              if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
             }
             if (type2 !== "generic") {
-              if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/))
-                continue;
+              if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
             }
             delete tags[key];
           }
     var _actions = selectedIDs.map(function(entityID) {
       var graph = context.graph();
       var entity = graph.hasEntity(entityID);
-      if (!entity || !entity.hasInterestingTags())
-        return null;
-      if (entity.type === "node" && graph.parentWays(entity).length === 0)
-        return null;
+      if (!entity || !entity.hasInterestingTags()) return null;
+      if (entity.type === "node" && graph.parentWays(entity).length === 0) return null;
       if (entity.type !== "node") {
         var preset = _mainPresetIndex.match(entity, graph);
-        if (preset.geometry.indexOf("point") === -1)
-          return null;
+        if (preset.geometry.indexOf("point") === -1) return null;
       }
       _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
       return actionExtract(entityID, context.projection);
     var _action = getAction();
     function getAction() {
       var join = actionJoin(selectedIDs);
-      if (!join.disabled(context.graph()))
-        return join;
+      if (!join.disabled(context.graph())) return join;
       var merge2 = actionMerge(selectedIDs);
-      if (!merge2.disabled(context.graph()))
-        return merge2;
+      if (!merge2.disabled(context.graph())) return merge2;
       var mergePolygon = actionMergePolygon(selectedIDs);
-      if (!mergePolygon.disabled(context.graph()))
-        return mergePolygon;
+      if (!mergePolygon.disabled(context.graph())) return mergePolygon;
       var mergeNodes = actionMergeNodes(selectedIDs);
-      if (!mergeNodes.disabled(context.graph()))
-        return mergeNodes;
-      if (join.disabled(context.graph()) !== "not_eligible")
-        return join;
-      if (merge2.disabled(context.graph()) !== "not_eligible")
-        return merge2;
-      if (mergePolygon.disabled(context.graph()) !== "not_eligible")
-        return mergePolygon;
+      if (!mergeNodes.disabled(context.graph())) return mergeNodes;
+      if (join.disabled(context.graph()) !== "not_eligible") return join;
+      if (merge2.disabled(context.graph()) !== "not_eligible") return merge2;
+      if (mergePolygon.disabled(context.graph()) !== "not_eligible") return mergePolygon;
       return mergeNodes;
     }
     var operation2 = function() {
-      if (operation2.disabled())
-        return;
+      if (operation2.disabled()) return;
       context.perform(_action, operation2.annotation());
       context.validator().validate();
       var resultIDs = selectedIDs.filter(context.hasEntity);
         var interestingIDs = resultIDs.filter(function(id2) {
           return context.entity(id2).hasInterestingTags();
         });
-        if (interestingIDs.length)
-          resultIDs = interestingIDs;
+        if (interestingIDs.length) resultIDs = interestingIDs;
       }
       context.enter(modeSelect(context, resultIDs));
     };
     };
     operation2.disabled = function() {
       var actionDisabled = _action.disabled(context.graph());
-      if (actionDisabled)
-        return actionDisabled;
+      if (actionDisabled) return actionDisabled;
       var osm = context.connection();
       if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
         return "too_many_vertices";
   function operationPaste(context) {
     var _pastePoint;
     var operation2 = function() {
-      if (!_pastePoint)
-        return;
+      if (!_pastePoint) return;
       var oldIDs = context.copyIDs();
-      if (!oldIDs.length)
-        return;
+      if (!oldIDs.length) return;
       var projection2 = context.projection;
       var extent = geoExtent();
       var oldGraph = context.copyGraph();
     function actions(situation) {
       return selectedIDs.map(function(entityID) {
         var entity = context.hasEntity(entityID);
-        if (!entity)
-          return null;
+        if (!entity) return null;
         if (situation === "toolbar") {
-          if (entity.type === "way" && (!entity.isOneWay() && !entity.isSided()))
-            return null;
+          if (entity.type === "way" && (!entity.isOneWay() && !entity.isSided())) return null;
         }
         var geometry = entity.geometry(context.graph());
-        if (entity.type !== "node" && geometry !== "line")
-          return null;
+        if (entity.type !== "node" && geometry !== "line") return null;
         var action = actionReverse(entityID);
-        if (action.disabled(context.graph()))
-          return null;
+        if (action.disabled(context.graph())) return null;
         return action;
       }).filter(Boolean);
     }
         var entity = context.hasEntity(act.entityID());
         return entity && entity.type === "node";
       }).length;
-      if (nodeActionCount === 0)
-        return "line";
-      if (nodeActionCount === acts.length)
-        return "point";
+      if (nodeActionCount === 0) return "line";
+      if (nodeActionCount === acts.length) return "point";
       return "feature";
     }
     operation2.available = function(situation) {
     var _waysAmount = "single";
     var _nodesAmount = _vertexIds.length === 1 ? "single" : "multiple";
     if (_isAvailable) {
-      if (_selectedWayIds.length)
-        _action.limitWays(_selectedWayIds);
+      if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
       _ways = _action.ways(context.graph());
       var geometries = {};
       _ways.forEach(function(way) {
         endNodeIDs = endNodeIDs.filter(function(n3) {
           return endNodeIDs.indexOf(n3) === endNodeIDs.lastIndexOf(n3);
         });
-        if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2)
-          return null;
+        if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null;
         var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function(node) {
           return node.id;
         });
-        if (wayNodeIDs.length <= 2)
-          return null;
-        if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1))
-          return null;
+        if (wayNodeIDs.length <= 2) return null;
+        if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
         if (_nodeIDs.length) {
           _extent = utilTotalExtent(_nodeIDs, context.graph());
         }
       return null;
     }
     function operation2() {
-      if (!_action)
-        return;
+      if (!_action) return;
       context.perform(_action, operation2.annotation());
       window.setTimeout(function() {
         context.validator().validate();
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = _coords.filter(function(loc) {
     function checkFocusedParent() {
       if (_focusedParentWayId) {
         var parents = parentWaysIdsOfSelection(true);
-        if (parents.indexOf(_focusedParentWayId) === -1)
-          _focusedParentWayId = null;
+        if (parents.indexOf(_focusedParentWayId) === -1) _focusedParentWayId = null;
       }
     }
     function parentWayIdForVertexNavigation() {
       return parentIds.length ? parentIds[0] : null;
     }
     mode.selectedIDs = function(val) {
-      if (!arguments.length)
-        return selectedIDs;
+      if (!arguments.length) return selectedIDs;
       selectedIDs = val;
       return mode;
     };
       context.map().zoomToEase(selectedEntities());
     };
     mode.newFeature = function(val) {
-      if (!arguments.length)
-        return _newFeature;
+      if (!arguments.length) return _newFeature;
       _newFeature = val;
       return mode;
     };
     mode.selectBehavior = function(val) {
-      if (!arguments.length)
-        return _selectBehavior;
+      if (!arguments.length) return _selectBehavior;
       _selectBehavior = val;
       return mode;
     };
     mode.follow = function(val) {
-      if (!arguments.length)
-        return _follow;
+      if (!arguments.length) return _follow;
       _follow = val;
       return mode;
     };
       return _operations;
     };
     mode.enter = function() {
-      if (!checkSelectedIDs())
-        return;
+      if (!checkSelectedIDs()) return;
       context.features().forceVisible(selectedIDs);
       _modeDragNode.restoreSelectedIDs(selectedIDs);
       loadOperations();
       if (!_behaviors.length) {
-        if (!_selectBehavior)
-          _selectBehavior = behaviorSelect(context);
+        if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
         _behaviors = [
           behaviorPaste(context),
           _breatheBehavior,
       }
       function nudgeSelection(delta) {
         return function() {
-          if (!context.map().withinEditableZoom())
-            return;
+          if (!context.map().withinEditableZoom()) return;
           var moveOp = operationMove(context, selectedIDs);
           if (moveOp.disabled()) {
             context.ui().flash.duration(4e3).iconName("#iD-operation-" + moveOp.id).iconClass("operation disabled").label(moveOp.tooltip())();
       }
       function scaleSelection(factor) {
         return function() {
-          if (!context.map().withinEditableZoom())
-            return;
+          if (!context.map().withinEditableZoom()) return;
           let nodes = utilGetAllNodes(selectedIDs, context.graph());
           let isUp = factor > 1;
-          if (nodes.length <= 1)
-            return;
+          if (nodes.length <= 1) return;
           let extent2 = utilTotalExtent(selectedIDs, context.graph());
           function scalingDisabled() {
             if (tooSmall()) {
             }
             return false;
             function tooSmall() {
-              if (isUp)
-                return false;
+              if (isUp) return false;
               let dLon = Math.abs(extent2[1][0] - extent2[0][0]);
               let dLat = Math.abs(extent2[1][1] - extent2[0][1]);
               return dLon < geoMetersToLon(1, extent2[1][1]) && dLat < geoMetersToLat(1);
             }
             function someMissing() {
-              if (context.inIntro())
-                return false;
+              if (context.inIntro()) return false;
               let osm = context.connection();
               if (osm) {
                 let missing = nodes.filter(function(n3) {
         };
       }
       function didDoubleUp(d3_event, loc2) {
-        if (!context.map().withinEditableZoom())
-          return;
+        if (!context.map().withinEditableZoom()) return;
         var target = select_default2(d3_event.target);
         var datum2 = target.datum();
         var entity = datum2 && datum2.properties && datum2.properties.entity;
-        if (!entity)
-          return;
+        if (!entity) return;
         if (entity instanceof osmWay && target.classed("target")) {
           var choice = geoChooseEdge(context.graph().childNodes(entity), loc2, context.projection);
           var prev = entity.nodes[choice.index - 1];
         }
       }
       function selectElements() {
-        if (!checkSelectedIDs())
-          return;
+        if (!checkSelectedIDs()) return;
         var surface = context.surface();
         surface.selectAll(".selected-member").classed("selected-member", false);
         surface.selectAll(".selected").classed("selected", false);
         }
       }
       function esc() {
-        if (context.container().select(".combobox").size())
-          return;
+        if (context.container().select(".combobox").size()) return;
         context.enter(modeBrowse(context));
       }
       function firstVertex(d3_event) {
         d3_event.preventDefault();
         var parentId = parentWayIdForVertexNavigation();
         _focusedParentWayId = parentId;
-        if (!parentId)
-          return;
+        if (!parentId) return;
         var way = context.entity(parentId);
         var length2 = way.nodes.length;
         var curr = way.nodes.indexOf(selectedIDs[0]);
         d3_event.preventDefault();
         var parentId = parentWayIdForVertexNavigation();
         _focusedParentWayId = parentId;
-        if (!parentId)
-          return;
+        if (!parentId) return;
         var way = context.entity(parentId);
         var length2 = way.nodes.length;
         var curr = way.nodes.indexOf(selectedIDs[0]);
       function focusNextParent(d3_event) {
         d3_event.preventDefault();
         var parents = parentWaysIdsOfSelection(true);
-        if (!parents || parents.length < 2)
-          return;
+        if (!parents || parents.length < 2) return;
         var index = parents.indexOf(_focusedParentWayId);
         if (index < 0 || index > parents.length - 2) {
           _focusedParentWayId = parents[0];
         d3_event.preventDefault();
         var currentSelectedIds = mode.selectedIDs();
         var parentIds = _focusedParentWayId ? [_focusedParentWayId] : parentWaysIdsOfSelection(false);
-        if (!parentIds.length)
-          return;
+        if (!parentIds.length) return;
         context.enter(
           mode.selectedIDs(parentIds)
         );
         d3_event.preventDefault();
         var currentSelectedIds = mode.selectedIDs();
         var childIds = _focusedVertexIds ? _focusedVertexIds.filter((id2) => context.hasEntity(id2)) : childNodeIdsOfSelection(true);
-        if (!childIds || !childIds.length)
-          return;
-        if (currentSelectedIds.length === 1)
-          _focusedParentWayId = currentSelectedIds[0];
+        if (!childIds || !childIds.length) return;
+        if (currentSelectedIds.length === 1) _focusedParentWayId = currentSelectedIds[0];
         context.enter(
           mode.selectedIDs(childIds)
         );
         ];
       }
       function lassoed() {
-        if (!lasso)
-          return [];
+        if (!lasso) return [];
         var graph = context.graph();
         var limitToNodes;
         if (context.map().editableDataEnabled(
         }
         var bounds = lasso.extent().map(context.projection.invert);
         var extent = geoExtent(normalize2(bounds[0], bounds[1]));
-        var intersects = context.history().intersects(extent).filter(function(entity) {
+        var intersects2 = context.history().intersects(extent).filter(function(entity) {
           return entity.type === "node" && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
         });
-        intersects.sort(function(node1, node2) {
+        intersects2.sort(function(node1, node2) {
           var parents1 = graph.parentWays(node1);
           var parents2 = graph.parentWays(node2);
           if (parents1.length && parents2.length) {
           }
           return node1.loc[0] - node2.loc[0];
         });
-        return intersects.map(function(entity) {
+        return intersects2.map(function(entity) {
           return entity.id;
         });
       }
       function pointerup() {
         select_default2(window).on(_pointerPrefix + "move.lasso", null).on(_pointerPrefix + "up.lasso", null);
-        if (!lasso)
-          return;
+        if (!lasso) return;
         var ids = lassoed();
         lasso.close();
         if (ids.length) {
     var _selectBehavior;
     var _behaviors = [];
     mode.selectBehavior = function(val) {
-      if (!arguments.length)
-        return _selectBehavior;
+      if (!arguments.length) return _selectBehavior;
       _selectBehavior = val;
       return mode;
     };
     mode.enter = function() {
       if (!_behaviors.length) {
-        if (!_selectBehavior)
-          _selectBehavior = behaviorSelect(context);
+        if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
         _behaviors = [
           behaviorPaste(context),
           behaviorHover(context).on("hover", context.ui().sidebar.hover),
       }
     };
     mode.sidebar = function(_2) {
-      if (!arguments.length)
-        return sidebar;
+      if (!arguments.length) return sidebar;
       sidebar = _2;
       return mode;
     };
       });
       if (selected.length) {
         newParams.id = selected.join(",");
+      } else if (context.selectedNoteID()) {
+        newParams.id = "note/".concat(context.selectedNoteID());
       }
       newParams.map = zoom.toFixed(2) + "/" + center[1].toFixed(precision3) + "/" + center[0].toFixed(precision3);
       return Object.assign(oldParams, newParams);
       return baseTitle;
     }
     function updateTitle(includeChangeCount) {
-      if (!context.setsDocumentTitle())
-        return;
+      if (!context.setsDocumentTitle()) return;
       var newTitle = computedTitle(includeChangeCount);
       if (document.title !== newTitle) {
         document.title = newTitle;
       }
     }
     function updateHashIfNeeded() {
-      if (context.inIntro())
-        return;
+      if (context.inIntro()) return;
       var latestHash = computedHash();
       if (_cachedHash !== latestHash) {
         _cachedHash = latestHash;
       );
     }, 500);
     function hashchange() {
-      if (window.location.hash === _cachedHash)
-        return;
+      if (window.location.hash === _cachedHash) return;
       _cachedHash = window.location.hash;
       var q2 = utilStringQs(_cachedHash);
       var mapArgs = (q2.map || "").split("/").map(Number);
       if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
         updateHashIfNeeded();
       } else {
-        if (_cachedHash === computedHash())
-          return;
+        if (_cachedHash === computedHash()) return;
         var mode = context.mode();
         context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
         if (q2.id && mode) {
           var ids = q2.id.split(",").filter(function(id2) {
-            return context.hasEntity(id2);
+            return context.hasEntity(id2) || id2.startsWith("note/");
           });
-          if (ids.length && (mode.id === "browse" || mode.id === "select" && !utilArrayIdentical(mode.selectedIDs(), ids))) {
-            context.enter(modeSelect(context, ids));
+          if (ids.length && ["browse", "select-note", "select"].includes(mode.id)) {
+            if (ids.length === 1 && ids[0].startsWith("note/")) {
+              context.enter(modeSelectNote(context, ids[0]));
+            } else if (!utilArrayIdentical(mode.selectedIDs(), ids)) {
+              context.enter(modeSelect(context, ids));
+            }
             return;
           }
         }
       select_default2(window).on("hashchange.behaviorHash", hashchange);
       var q2 = utilStringQs(window.location.hash);
       if (q2.id) {
-        context.zoomToEntity(q2.id.split(",")[0], !q2.map);
+        const selectIds = q2.id.split(",");
+        if (selectIds.length === 1 && selectIds[0].startsWith("note/")) {
+          const noteId = selectIds[0].split("/")[1];
+          context.zoomToNote(noteId, !q2.map);
+        } else {
+          context.zoomToEntities(
+            // convert ids to short form id: node/123 -> n123
+            selectIds.map((id2) => id2.replace(/([nwr])[^/]*\//, "$1")),
+            !q2.map
+          );
+        }
       }
       if (q2.walkthrough === "true") {
         behavior.startWalkthrough = true;