]> git.openstreetmap.org Git - rails.git/blobdiff - vendor/assets/iD/iD.js
Update to iD v2.26.1
[rails.git] / vendor / assets / iD / iD.js
index 5c78af37936db3fa522f2896e3d3b93d737ad62a..d25b3398b8be23230aaaecfd3c6cc2b4742d9595 100644 (file)
     return to;
   };
   var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
+    // If the importer is in node compatibility mode or this is not an ESM
+    // file that has been converted to a CommonJS file using a Babel-
+    // compatible transform (i.e. "__esModule" has not been set), then set
+    // "default" to the CommonJS "module.exports" for node compatibility.
     isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
     mod
   ));
         [69216, 69247],
         [126064, 126143],
         [126464, 126719]
+        // Mathematical Alphabetic symbols https://www.unicode.org/charts/PDF/U1EE00.pdf
       ];
       function isArabic(char) {
         if (char.length > 1) {
         all: function() {
           return this._all(this.data, []);
         },
-        search: function(bbox) {
+        search: function(bbox2) {
           var node = this.data, result = [], toBBox = this.toBBox;
-          if (!intersects(bbox, node))
+          if (!intersects(bbox2, node))
             return result;
           var nodesToSearch = [], i2, len, child, childBBox;
           while (node) {
             for (i2 = 0, len = node.children.length; i2 < len; i2++) {
               child = node.children[i2];
               childBBox = node.leaf ? toBBox(child) : child;
-              if (intersects(bbox, childBBox)) {
+              if (intersects(bbox2, childBBox)) {
                 if (node.leaf)
                   result.push(child);
-                else if (contains(bbox, childBBox))
+                else if (contains(bbox2, childBBox))
                   this._all(child, result);
                 else
                   nodesToSearch.push(child);
           }
           return result;
         },
-        collides: function(bbox) {
+        collides: function(bbox2) {
           var node = this.data, toBBox = this.toBBox;
-          if (!intersects(bbox, node))
+          if (!intersects(bbox2, node))
             return false;
           var nodesToSearch = [], i2, len, child, childBBox;
           while (node) {
             for (i2 = 0, len = node.children.length; i2 < len; i2++) {
               child = node.children[i2];
               childBBox = node.leaf ? toBBox(child) : child;
-              if (intersects(bbox, childBBox)) {
-                if (node.leaf || contains(bbox, childBBox))
+              if (intersects(bbox2, childBBox)) {
+                if (node.leaf || contains(bbox2, childBBox))
                   return true;
                 nodesToSearch.push(child);
               }
         remove: function(item, equalsFn) {
           if (!item)
             return this;
-          var node = this.data, bbox = this.toBBox(item), path = [], indexes = [], i2, parent, index, goingUp;
+          var node = this.data, bbox2 = this.toBBox(item), path = [], indexes = [], i2, parent, index, goingUp;
           while (node || path.length) {
             if (!node) {
               node = path.pop();
                 return this;
               }
             }
-            if (!goingUp && !node.leaf && contains(node, bbox)) {
+            if (!goingUp && !node.leaf && contains(node, bbox2)) {
               path.push(node);
               indexes.push(i2);
               i2 = 0;
           calcBBox(node, this.toBBox);
           return node;
         },
-        _chooseSubtree: function(bbox, node, level, path) {
+        _chooseSubtree: function(bbox2, node, level, path) {
           var i2, len, child, targetNode, area, enlargement, minArea, minEnlargement;
           while (true) {
             path.push(node);
             for (i2 = 0, len = node.children.length; i2 < len; i2++) {
               child = node.children[i2];
               area = bboxArea(child);
-              enlargement = enlargedArea(bbox, child) - area;
+              enlargement = enlargedArea(bbox2, child) - area;
               if (enlargement < minEnlargement) {
                 minEnlargement = enlargement;
                 minArea = area < minArea ? area : minArea;
           return node;
         },
         _insert: function(item, level, isNode) {
-          var toBBox = this.toBBox, bbox = isNode ? item : toBBox(item), insertPath = [];
-          var node = this._chooseSubtree(bbox, this.data, level, insertPath);
+          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, bbox);
+          extend2(node, bbox2);
           while (level >= 0) {
             if (insertPath[level].children.length > this._maxEntries) {
               this._split(insertPath, level);
             } else
               break;
           }
-          this._adjustParentBBoxes(bbox, insertPath, level);
+          this._adjustParentBBoxes(bbox2, insertPath, level);
         },
+        // split overflowed node into two
         _split: function(insertPath, level) {
           var node = insertPath[level], M = node.children.length, m = this._minEntries;
           this._chooseSplitAxis(node, m, M);
           }
           return index;
         },
+        // sorts node children by the best axis for split
         _chooseSplitAxis: function(node, m, M) {
           var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX, compareMinY = node.leaf ? this.compareMinY : compareNodeMinY, xMargin = this._allDistMargin(node, m, M, compareMinX), yMargin = this._allDistMargin(node, m, M, 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, m, M, compare) {
           node.children.sort(compare);
           var toBBox = this.toBBox, leftBBox = distBBox(node, 0, m, toBBox), rightBBox = distBBox(node, M - m, M, toBBox), margin = bboxMargin(leftBBox) + bboxMargin(rightBBox), i2, child;
           }
           return margin;
         },
-        _adjustParentBBoxes: function(bbox, path, level) {
+        _adjustParentBBoxes: function(bbox2, path, level) {
           for (var i2 = level; i2 >= 0; i2--) {
-            extend2(path[i2], bbox);
+            extend2(path[i2], bbox2);
           }
         },
         _condense: function(path) {
       module2.exports = lineclip2;
       lineclip2.polyline = lineclip2;
       lineclip2.polygon = polygonclip2;
-      function lineclip2(points, bbox, result) {
-        var len = points.length, codeA = bitCode2(points[0], bbox), part = [], i2, a, b, codeB, lastCode;
+      function lineclip2(points, bbox2, result) {
+        var len = points.length, codeA = bitCode2(points[0], bbox2), part = [], i2, a, b, codeB, lastCode;
         if (!result)
           result = [];
         for (i2 = 1; i2 < len; i2++) {
           a = points[i2 - 1];
           b = points[i2];
-          codeB = lastCode = bitCode2(b, bbox);
+          codeB = lastCode = bitCode2(b, bbox2);
           while (true) {
             if (!(codeA | codeB)) {
               part.push(a);
             } else if (codeA & codeB) {
               break;
             } else if (codeA) {
-              a = intersect2(a, b, codeA, bbox);
-              codeA = bitCode2(a, bbox);
+              a = intersect2(a, b, codeA, bbox2);
+              codeA = bitCode2(a, bbox2);
             } else {
-              b = intersect2(a, b, codeB, bbox);
-              codeB = bitCode2(b, bbox);
+              b = intersect2(a, b, codeB, bbox2);
+              codeB = bitCode2(b, bbox2);
             }
           }
           codeA = lastCode;
           result.push(part);
         return result;
       }
-      function polygonclip2(points, bbox) {
+      function polygonclip2(points, bbox2) {
         var result, edge, prev, prevInside, i2, p, inside;
         for (edge = 1; edge <= 8; edge *= 2) {
           result = [];
           prev = points[points.length - 1];
-          prevInside = !(bitCode2(prev, bbox) & edge);
+          prevInside = !(bitCode2(prev, bbox2) & edge);
           for (i2 = 0; i2 < points.length; i2++) {
             p = points[i2];
-            inside = !(bitCode2(p, bbox) & edge);
+            inside = !(bitCode2(p, bbox2) & edge);
             if (inside !== prevInside)
-              result.push(intersect2(prev, p, edge, bbox));
+              result.push(intersect2(prev, p, edge, bbox2));
             if (inside)
               result.push(p);
             prev = p;
         }
         return result;
       }
-      function intersect2(a, b, edge, bbox) {
-        return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : null;
+      function intersect2(a, b, edge, bbox2) {
+        return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox2[3] - a[1]) / (b[1] - a[1]), bbox2[3]] : (
+          // top
+          edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox2[1] - a[1]) / (b[1] - a[1]), bbox2[1]] : (
+            // bottom
+            edge & 2 ? [bbox2[2], a[1] + (b[1] - a[1]) * (bbox2[2] - a[0]) / (b[0] - a[0])] : (
+              // right
+              edge & 1 ? [bbox2[0], a[1] + (b[1] - a[1]) * (bbox2[0] - a[0]) / (b[0] - a[0])] : (
+                // left
+                null
+              )
+            )
+          )
+        );
       }
-      function bitCode2(p, bbox) {
+      function bitCode2(p, bbox2) {
         var code = 0;
-        if (p[0] < bbox[0])
+        if (p[0] < bbox2[0])
           code |= 1;
-        else if (p[0] > bbox[2])
+        else if (p[0] > bbox2[2])
           code |= 2;
-        if (p[1] < bbox[1])
+        if (p[1] < bbox2[1])
           code |= 4;
-        else if (p[1] > bbox[3])
+        else if (p[1] > bbox2[3])
           code |= 8;
         return code;
       }
         var bboxes = [];
         for (var i2 = 0; i2 < data.features.length; i2++) {
           var feature3 = data.features[i2];
+          if (!feature3.geometry)
+            continue;
           var coords = feature3.geometry.coordinates;
           if (feature3.geometry.type === "Polygon") {
             bboxes.push(treeItem(coords, feature3.properties));
           return multi && output.length ? output : null;
         }
         query.tree = tree;
-        query.bbox = function queryBBox(bbox) {
+        query.bbox = function queryBBox(bbox2) {
           var output = [];
           var result = tree.search({
-            minX: bbox[0],
-            minY: bbox[1],
-            maxX: bbox[2],
-            maxY: bbox[3]
+            minX: bbox2[0],
+            minY: bbox2[1],
+            maxX: bbox2[2],
+            maxY: bbox2[3]
           });
           for (var i3 = 0; i3 < result.length; i3++) {
-            if (polygonIntersectsBBox(result[i3].coords, bbox)) {
+            if (polygonIntersectsBBox(result[i3].coords, bbox2)) {
               output.push(result[i3].props);
             }
           }
         };
         return query;
       }
-      function polygonIntersectsBBox(polygon2, bbox) {
+      function polygonIntersectsBBox(polygon2, bbox2) {
         var bboxCenter = [
-          (bbox[0] + bbox[2]) / 2,
-          (bbox[1] + bbox[3]) / 2
+          (bbox2[0] + bbox2[2]) / 2,
+          (bbox2[1] + bbox2[3]) / 2
         ];
         if (insidePolygon(polygon2, bboxCenter))
           return true;
         for (var i2 = 0; i2 < polygon2.length; i2++) {
-          if (lineclip2(polygon2[i2], bbox).length > 0)
+          if (lineclip2(polygon2[i2], bbox2).length > 0)
             return true;
         }
         return false;
             _defineProperties(Constructor, staticProps);
           return Constructor;
         }
-        var Node = function() {
-          function Node2(key, data) {
-            this.next = null;
-            this.key = key;
-            this.data = data;
-            this.left = null;
-            this.right = null;
-          }
-          return Node2;
-        }();
+        var Node = (
+          /** @class */
+          function() {
+            function Node2(key, data) {
+              this.next = null;
+              this.key = key;
+              this.data = data;
+              this.left = null;
+              this.right = null;
+            }
+            return Node2;
+          }()
+        );
         function DEFAULT_COMPARE(a, b) {
           return a > b ? 1 : a < b ? -1 : 0;
         }
             right
           };
         }
-        function merge3(left, right, comparator) {
+        function merge2(left, right, comparator) {
           if (right === null)
             return left;
           if (left === null)
               printRow(root3.right, indent2, true, out, printNode);
           }
         }
-        var Tree = function() {
-          function Tree2(comparator) {
-            if (comparator === void 0) {
-              comparator = DEFAULT_COMPARE;
-            }
-            this._root = null;
-            this._size = 0;
-            this._comparator = comparator;
-          }
-          Tree2.prototype.insert = function(key, data) {
-            this._size++;
-            return this._root = insert(key, data, this._root, this._comparator);
-          };
-          Tree2.prototype.add = function(key, data) {
-            var node = new Node(key, data);
-            if (this._root === null) {
-              node.left = node.right = null;
-              this._size++;
-              this._root = node;
-            }
-            var comparator = this._comparator;
-            var t = splay(key, this._root, comparator);
-            var cmp2 = comparator(key, t.key);
-            if (cmp2 === 0)
-              this._root = t;
-            else {
-              if (cmp2 < 0) {
-                node.left = t.left;
-                node.right = t;
-                t.left = null;
-              } else if (cmp2 > 0) {
-                node.right = t.right;
-                node.left = t;
-                t.right = null;
+        var Tree = (
+          /** @class */
+          function() {
+            function Tree2(comparator) {
+              if (comparator === void 0) {
+                comparator = DEFAULT_COMPARE;
               }
-              this._size++;
-              this._root = node;
+              this._root = null;
+              this._size = 0;
+              this._comparator = comparator;
             }
-            return this._root;
-          };
-          Tree2.prototype.remove = function(key) {
-            this._root = this._remove(key, this._root, this._comparator);
-          };
-          Tree2.prototype._remove = function(i2, t, comparator) {
-            var x;
-            if (t === null)
-              return null;
-            t = splay(i2, t, comparator);
-            var cmp2 = comparator(i2, t.key);
-            if (cmp2 === 0) {
-              if (t.left === null) {
-                x = t.right;
-              } else {
-                x = splay(i2, t.left, comparator);
-                x.right = t.right;
-              }
-              this._size--;
-              return x;
-            }
-            return t;
-          };
-          Tree2.prototype.pop = function() {
-            var node = this._root;
-            if (node) {
-              while (node.left) {
-                node = node.left;
+            Tree2.prototype.insert = function(key, data) {
+              this._size++;
+              return this._root = insert(key, data, this._root, this._comparator);
+            };
+            Tree2.prototype.add = function(key, data) {
+              var node = new Node(key, data);
+              if (this._root === null) {
+                node.left = node.right = null;
+                this._size++;
+                this._root = node;
               }
-              this._root = splay(node.key, this._root, this._comparator);
-              this._root = this._remove(node.key, this._root, this._comparator);
-              return {
-                key: node.key,
-                data: node.data
-              };
-            }
-            return null;
-          };
-          Tree2.prototype.findStatic = function(key) {
-            var current = this._root;
-            var compare = this._comparator;
-            while (current) {
-              var cmp2 = compare(key, current.key);
+              var comparator = this._comparator;
+              var t = splay(key, this._root, comparator);
+              var cmp2 = comparator(key, t.key);
               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)
+                this._root = t;
+              else {
+                if (cmp2 < 0) {
+                  node.left = t.left;
+                  node.right = t;
+                  t.left = null;
+                } else if (cmp2 > 0) {
+                  node.right = t.right;
+                  node.left = t;
+                  t.right = null;
+                }
+                this._size++;
+                this._root = node;
+              }
+              return this._root;
+            };
+            Tree2.prototype.remove = function(key) {
+              this._root = this._remove(key, this._root, this._comparator);
+            };
+            Tree2.prototype._remove = function(i2, t, comparator) {
+              var x;
+              if (t === null)
                 return null;
-            }
-            return this._root;
-          };
-          Tree2.prototype.contains = function(key) {
-            var current = this._root;
-            var compare = this._comparator;
-            while (current) {
-              var cmp2 = compare(key, current.key);
-              if (cmp2 === 0)
-                return true;
-              else if (cmp2 < 0)
-                current = current.left;
-              else
-                current = current.right;
-            }
-            return false;
-          };
-          Tree2.prototype.forEach = function(visitor, ctx) {
-            var current = this._root;
-            var Q = [];
-            var done = false;
-            while (!done) {
-              if (current !== null) {
-                Q.push(current);
-                current = current.left;
-              } else {
-                if (Q.length !== 0) {
-                  current = Q.pop();
-                  visitor.call(ctx, current);
-                  current = current.right;
-                } else
-                  done = true;
+              t = splay(i2, t, comparator);
+              var cmp2 = comparator(i2, t.key);
+              if (cmp2 === 0) {
+                if (t.left === null) {
+                  x = t.right;
+                } else {
+                  x = splay(i2, t.left, comparator);
+                  x.right = t.right;
+                }
+                this._size--;
+                return x;
               }
-            }
-            return this;
-          };
-          Tree2.prototype.range = function(low, high, fn, ctx) {
-            var Q = [];
-            var compare = this._comparator;
-            var node = this._root;
-            var cmp2;
-            while (Q.length !== 0 || node) {
+              return t;
+            };
+            Tree2.prototype.pop = function() {
+              var node = this._root;
               if (node) {
-                Q.push(node);
-                node = node.left;
-              } else {
-                node = Q.pop();
-                cmp2 = compare(node.key, high);
-                if (cmp2 > 0) {
-                  break;
-                } else if (compare(node.key, low) >= 0) {
-                  if (fn.call(ctx, node))
-                    return this;
+                while (node.left) {
+                  node = node.left;
                 }
-                node = node.right;
+                this._root = splay(node.key, this._root, this._comparator);
+                this._root = this._remove(node.key, this._root, this._comparator);
+                return {
+                  key: node.key,
+                  data: node.data
+                };
               }
-            }
-            return this;
-          };
-          Tree2.prototype.keys = function() {
-            var keys = [];
-            this.forEach(function(_a) {
-              var key = _a.key;
-              return keys.push(key);
-            });
-            return keys;
-          };
-          Tree2.prototype.values = function() {
-            var values = [];
-            this.forEach(function(_a) {
-              var data = _a.data;
-              return values.push(data);
-            });
-            return values;
-          };
-          Tree2.prototype.min = function() {
-            if (this._root)
-              return this.minNode(this._root).key;
-            return null;
-          };
-          Tree2.prototype.max = function() {
-            if (this._root)
-              return this.maxNode(this._root).key;
-            return null;
-          };
-          Tree2.prototype.minNode = function(t) {
-            if (t === void 0) {
-              t = this._root;
-            }
-            if (t)
-              while (t.left) {
-                t = t.left;
+              return null;
+            };
+            Tree2.prototype.findStatic = function(key) {
+              var current = this._root;
+              var compare = this._comparator;
+              while (current) {
+                var cmp2 = compare(key, current.key);
+                if (cmp2 === 0)
+                  return current;
+                else if (cmp2 < 0)
+                  current = current.left;
+                else
+                  current = current.right;
               }
-            return t;
-          };
-          Tree2.prototype.maxNode = function(t) {
-            if (t === void 0) {
-              t = this._root;
-            }
-            if (t)
-              while (t.right) {
-                t = t.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;
               }
-            return t;
-          };
-          Tree2.prototype.at = function(index2) {
-            var current = this._root;
-            var done = false;
-            var i2 = 0;
-            var Q = [];
-            while (!done) {
-              if (current) {
-                Q.push(current);
-                current = current.left;
-              } else {
-                if (Q.length > 0) {
-                  current = Q.pop();
-                  if (i2 === index2)
-                    return current;
-                  i2++;
+              return this._root;
+            };
+            Tree2.prototype.contains = function(key) {
+              var current = this._root;
+              var compare = this._comparator;
+              while (current) {
+                var cmp2 = compare(key, current.key);
+                if (cmp2 === 0)
+                  return true;
+                else if (cmp2 < 0)
+                  current = current.left;
+                else
                   current = current.right;
-                } else
-                  done = true;
               }
-            }
-            return null;
-          };
-          Tree2.prototype.next = function(d) {
-            var root3 = this._root;
-            var successor = null;
-            if (d.right) {
-              successor = d.right;
-              while (successor.left) {
-                successor = successor.left;
+              return false;
+            };
+            Tree2.prototype.forEach = function(visitor, ctx) {
+              var current = this._root;
+              var Q = [];
+              var done = false;
+              while (!done) {
+                if (current !== null) {
+                  Q.push(current);
+                  current = current.left;
+                } else {
+                  if (Q.length !== 0) {
+                    current = Q.pop();
+                    visitor.call(ctx, current);
+                    current = current.right;
+                  } else
+                    done = true;
+                }
+              }
+              return this;
+            };
+            Tree2.prototype.range = function(low, high, fn, ctx) {
+              var Q = [];
+              var compare = this._comparator;
+              var node = this._root;
+              var cmp2;
+              while (Q.length !== 0 || node) {
+                if (node) {
+                  Q.push(node);
+                  node = node.left;
+                } else {
+                  node = Q.pop();
+                  cmp2 = compare(node.key, high);
+                  if (cmp2 > 0) {
+                    break;
+                  } else if (compare(node.key, low) >= 0) {
+                    if (fn.call(ctx, node))
+                      return this;
+                  }
+                  node = node.right;
+                }
+              }
+              return this;
+            };
+            Tree2.prototype.keys = function() {
+              var keys2 = [];
+              this.forEach(function(_a) {
+                var key = _a.key;
+                return keys2.push(key);
+              });
+              return keys2;
+            };
+            Tree2.prototype.values = function() {
+              var values = [];
+              this.forEach(function(_a) {
+                var data = _a.data;
+                return values.push(data);
+              });
+              return values;
+            };
+            Tree2.prototype.min = function() {
+              if (this._root)
+                return this.minNode(this._root).key;
+              return null;
+            };
+            Tree2.prototype.max = function() {
+              if (this._root)
+                return this.maxNode(this._root).key;
+              return null;
+            };
+            Tree2.prototype.minNode = function(t) {
+              if (t === void 0) {
+                t = this._root;
+              }
+              if (t)
+                while (t.left) {
+                  t = t.left;
+                }
+              return t;
+            };
+            Tree2.prototype.maxNode = function(t) {
+              if (t === void 0) {
+                t = this._root;
+              }
+              if (t)
+                while (t.right) {
+                  t = t.right;
+                }
+              return t;
+            };
+            Tree2.prototype.at = function(index2) {
+              var current = this._root;
+              var done = false;
+              var i2 = 0;
+              var Q = [];
+              while (!done) {
+                if (current) {
+                  Q.push(current);
+                  current = current.left;
+                } else {
+                  if (Q.length > 0) {
+                    current = Q.pop();
+                    if (i2 === index2)
+                      return current;
+                    i2++;
+                    current = current.right;
+                  } else
+                    done = true;
+                }
+              }
+              return null;
+            };
+            Tree2.prototype.next = function(d) {
+              var root3 = this._root;
+              var successor = null;
+              if (d.right) {
+                successor = d.right;
+                while (successor.left) {
+                  successor = successor.left;
+                }
+                return successor;
+              }
+              var comparator = this._comparator;
+              while (root3) {
+                var cmp2 = comparator(d.key, root3.key);
+                if (cmp2 === 0)
+                  break;
+                else if (cmp2 < 0) {
+                  successor = root3;
+                  root3 = root3.left;
+                } else
+                  root3 = root3.right;
               }
               return successor;
-            }
-            var comparator = this._comparator;
-            while (root3) {
-              var cmp2 = comparator(d.key, root3.key);
-              if (cmp2 === 0)
-                break;
-              else if (cmp2 < 0) {
-                successor = root3;
-                root3 = root3.left;
-              } else
-                root3 = root3.right;
-            }
-            return successor;
-          };
-          Tree2.prototype.prev = function(d) {
-            var root3 = this._root;
-            var predecessor = null;
-            if (d.left !== null) {
-              predecessor = d.left;
-              while (predecessor.right) {
-                predecessor = predecessor.right;
+            };
+            Tree2.prototype.prev = function(d) {
+              var root3 = this._root;
+              var predecessor = null;
+              if (d.left !== null) {
+                predecessor = d.left;
+                while (predecessor.right) {
+                  predecessor = predecessor.right;
+                }
+                return predecessor;
+              }
+              var comparator = this._comparator;
+              while (root3) {
+                var cmp2 = comparator(d.key, root3.key);
+                if (cmp2 === 0)
+                  break;
+                else if (cmp2 < 0)
+                  root3 = root3.left;
+                else {
+                  predecessor = root3;
+                  root3 = root3.right;
+                }
               }
               return predecessor;
-            }
-            var comparator = this._comparator;
-            while (root3) {
-              var cmp2 = comparator(d.key, root3.key);
-              if (cmp2 === 0)
-                break;
-              else if (cmp2 < 0)
-                root3 = root3.left;
-              else {
-                predecessor = root3;
-                root3 = root3.right;
+            };
+            Tree2.prototype.clear = function() {
+              this._root = null;
+              this._size = 0;
+              return this;
+            };
+            Tree2.prototype.toList = function() {
+              return toList(this._root);
+            };
+            Tree2.prototype.load = function(keys2, values, presort) {
+              if (values === void 0) {
+                values = [];
               }
-            }
-            return predecessor;
-          };
-          Tree2.prototype.clear = function() {
-            this._root = null;
-            this._size = 0;
-            return this;
-          };
-          Tree2.prototype.toList = function() {
-            return toList(this._root);
-          };
-          Tree2.prototype.load = function(keys, values, presort) {
-            if (values === void 0) {
-              values = [];
-            }
-            if (presort === void 0) {
-              presort = false;
-            }
-            var size = keys.length;
-            var comparator = this._comparator;
-            if (presort)
-              sort(keys, values, 0, size - 1, comparator);
-            if (this._root === null) {
-              this._root = loadRecursive(keys, values, 0, size);
-              this._size = size;
-            } else {
-              var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
-              size = this._size + size;
-              this._root = sortedListToBST({
-                head: mergedList
-              }, 0, size);
-            }
-            return this;
-          };
-          Tree2.prototype.isEmpty = function() {
-            return this._root === null;
-          };
-          Object.defineProperty(Tree2.prototype, "size", {
-            get: function get4() {
-              return this._size;
-            },
-            enumerable: true,
-            configurable: true
-          });
-          Object.defineProperty(Tree2.prototype, "root", {
-            get: function get4() {
-              return this._root;
-            },
-            enumerable: true,
-            configurable: true
-          });
-          Tree2.prototype.toString = function(printNode) {
-            if (printNode === void 0) {
-              printNode = function printNode2(n2) {
-                return String(n2.key);
-              };
-            }
-            var out = [];
-            printRow(this._root, "", true, function(v) {
-              return out.push(v);
-            }, printNode);
-            return out.join("");
-          };
-          Tree2.prototype.update = function(key, newKey, newData) {
-            var comparator = this._comparator;
-            var _a = split(key, this._root, comparator), left = _a.left, right = _a.right;
-            if (comparator(key, newKey) < 0) {
-              right = insert(newKey, newData, right, comparator);
-            } else {
-              left = insert(newKey, newData, left, comparator);
-            }
-            this._root = merge3(left, right, comparator);
-          };
-          Tree2.prototype.split = function(key) {
-            return split(key, this._root, this._comparator);
-          };
-          return Tree2;
-        }();
-        function loadRecursive(keys, values, start2, end) {
+              if (presort === void 0) {
+                presort = false;
+              }
+              var size = keys2.length;
+              var comparator = this._comparator;
+              if (presort)
+                sort(keys2, values, 0, size - 1, comparator);
+              if (this._root === null) {
+                this._root = loadRecursive(keys2, values, 0, size);
+                this._size = size;
+              } else {
+                var mergedList = mergeLists(this.toList(), createList(keys2, values), comparator);
+                size = this._size + size;
+                this._root = sortedListToBST({
+                  head: mergedList
+                }, 0, size);
+              }
+              return this;
+            };
+            Tree2.prototype.isEmpty = function() {
+              return this._root === null;
+            };
+            Object.defineProperty(Tree2.prototype, "size", {
+              get: function get4() {
+                return this._size;
+              },
+              enumerable: true,
+              configurable: true
+            });
+            Object.defineProperty(Tree2.prototype, "root", {
+              get: function get4() {
+                return this._root;
+              },
+              enumerable: true,
+              configurable: true
+            });
+            Tree2.prototype.toString = function(printNode) {
+              if (printNode === void 0) {
+                printNode = function printNode2(n2) {
+                  return String(n2.key);
+                };
+              }
+              var out = [];
+              printRow(this._root, "", true, function(v) {
+                return out.push(v);
+              }, printNode);
+              return out.join("");
+            };
+            Tree2.prototype.update = function(key, newKey, newData) {
+              var comparator = this._comparator;
+              var _a = split(key, this._root, comparator), left = _a.left, right = _a.right;
+              if (comparator(key, newKey) < 0) {
+                right = insert(newKey, newData, right, comparator);
+              } else {
+                left = insert(newKey, newData, left, comparator);
+              }
+              this._root = merge2(left, right, comparator);
+            };
+            Tree2.prototype.split = function(key) {
+              return split(key, this._root, this._comparator);
+            };
+            return Tree2;
+          }()
+        );
+        function loadRecursive(keys2, values, start2, end) {
           var size = end - start2;
           if (size > 0) {
             var middle = start2 + Math.floor(size / 2);
-            var key = keys[middle];
+            var key = keys2[middle];
             var data = values[middle];
             var node = new Node(key, data);
-            node.left = loadRecursive(keys, values, start2, middle);
-            node.right = loadRecursive(keys, values, middle + 1, end);
+            node.left = loadRecursive(keys2, values, start2, middle);
+            node.right = loadRecursive(keys2, values, middle + 1, end);
             return node;
           }
           return null;
         }
-        function createList(keys, values) {
+        function createList(keys2, values) {
           var head = new Node(null, null);
           var p = head;
-          for (var i2 = 0; i2 < keys.length; i2++) {
-            p = p.next = new Node(keys[i2], values[i2]);
+          for (var i2 = 0; i2 < keys2.length; i2++) {
+            p = p.next = new Node(keys2[i2], values[i2]);
           }
           p.next = null;
           return head.next;
           }
           return head.next;
         }
-        function sort(keys, values, left, right, compare) {
+        function sort(keys2, values, left, right, compare) {
           if (left >= right)
             return;
-          var pivot = keys[left + right >> 1];
+          var pivot = keys2[left + right >> 1];
           var i2 = left - 1;
           var j2 = right + 1;
           while (true) {
             do {
               i2++;
-            } while (compare(keys[i2], pivot) < 0);
+            } while (compare(keys2[i2], pivot) < 0);
             do {
               j2--;
-            } while (compare(keys[j2], pivot) > 0);
+            } while (compare(keys2[j2], pivot) > 0);
             if (i2 >= j2)
               break;
-            var tmp = keys[i2];
-            keys[i2] = keys[j2];
-            keys[j2] = tmp;
+            var tmp = keys2[i2];
+            keys2[i2] = keys2[j2];
+            keys2[j2] = tmp;
             tmp = values[i2];
             values[i2] = values[j2];
             values[j2] = tmp;
           }
-          sort(keys, values, left, j2, compare);
-          sort(keys, values, j2 + 1, right, compare);
+          sort(keys2, values, left, j2, compare);
+          sort(keys2, values, j2 + 1, right, compare);
         }
-        var isInBbox = function isInBbox2(bbox, point) {
-          return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
+        var isInBbox = function isInBbox2(bbox2, point2) {
+          return bbox2.ll.x <= point2.x && point2.x <= bbox2.ur.x && bbox2.ll.y <= point2.y && point2.y <= bbox2.ur.y;
         };
         var getBboxOverlap = function 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)
         var SweepEvent = /* @__PURE__ */ function() {
           _createClass(SweepEvent2, null, [{
             key: "compare",
+            // for ordering sweep events in the sweep event queue
             value: function compare(a, b) {
               var ptCmp = SweepEvent2.comparePoints(a.point, b.point);
               if (ptCmp !== 0)
                 return a.isLeft ? 1 : -1;
               return Segment.compare(a.segment, b.segment);
             }
+            // for ordering points in sweep line order
           }, {
             key: "comparePoints",
             value: function comparePoints(aPt, bPt) {
                 return 1;
               return 0;
             }
+            // Warning: 'point' input will be modified and re-used (for performance)
           }]);
-          function SweepEvent2(point, isLeft) {
+          function SweepEvent2(point2, isLeft) {
             _classCallCheck(this, SweepEvent2);
-            if (point.events === void 0)
-              point.events = [this];
+            if (point2.events === void 0)
+              point2.events = [this];
             else
-              point.events.push(this);
-            this.point = point;
+              point2.events.push(this);
+            this.point = point2;
             this.isLeft = isLeft;
           }
           _createClass(SweepEvent2, [{
               }
               this.checkForConsuming();
             }
+            /* Do a pass over our linked events and check to see if any pair
+             * of segments match, and should be consumed. */
           }, {
             key: "checkForConsuming",
             value: function checkForConsuming() {
               }
               return events;
             }
+            /**
+             * Returns a comparator function for sorting linked events that will
+             * favor the event that will give us the smallest left-side angle.
+             * All ring construction starts as low as possible heading to the right,
+             * so by always turning left as sharp as possible we'll get polygons
+             * without uncessary loops & holes.
+             *
+             * The comparator function has a compute cache such that it avoids
+             * re-computing already-computed values.
+             */
           }, {
             key: "getLeftmostComparator",
             value: function getLeftmostComparator(baseEvent) {
         var Segment = /* @__PURE__ */ function() {
           _createClass(Segment2, null, [{
             key: "compare",
+            /* This compare() function is for ordering segments in the sweep
+             * line tree, and does so according to the following criteria:
+             *
+             * Consider the vertical line that lies an infinestimal step to the
+             * right of the right-more of the two left endpoints of the input
+             * segments. Imagine slowly moving a point up from negative infinity
+             * in the increasing y direction. Which of the two segments will that
+             * point intersect first? That segment comes 'before' the other one.
+             *
+             * If neither segment would be intersected by such a line, (if one
+             * or more of the segments are vertical) then the line to be considered
+             * is directly on the right-more of the two left inputs.
+             */
             value: function compare(a, b) {
               var alx = a.leftSE.point.x;
               var blx = b.leftSE.point.x;
                 return 1;
               return 0;
             }
+            /* Warning: a reference to ringWindings input will be stored,
+             *  and possibly will be later modified */
           }]);
           function Segment2(leftSE, rightSE, rings, windings) {
             _classCallCheck(this, Segment2);
           }
           _createClass(Segment2, [{
             key: "replaceRightSE",
+            /* When a segment is split, the rightSE is replaced with a new sweep event */
             value: function replaceRightSE(newRightSE) {
               this.rightSE = newRightSE;
               this.rightSE.segment = this;
             }
           }, {
             key: "bbox",
-            value: function bbox() {
+            value: function bbox2() {
               var y12 = this.leftSE.point.y;
               var y2 = this.rightSE.point.y;
               return {
                 }
               };
             }
+            /* A vector from the left point to the right */
           }, {
             key: "vector",
             value: function vector() {
             value: function isAnEndpoint(pt) {
               return pt.x === this.leftSE.point.x && pt.y === this.leftSE.point.y || pt.x === this.rightSE.point.x && pt.y === this.rightSE.point.y;
             }
+            /* Compare this segment with a point.
+             *
+             * A point P is considered to be colinear to a segment if there
+             * exists a distance D such that if we travel along the segment
+             * from one * endpoint towards the other a distance D, we find
+             * ourselves at point P.
+             *
+             * Return value indicates:
+             *
+             *   1: point lies above the segment (to the left of vertical)
+             *   0: point is colinear to segment
+             *  -1: point lies below the segment (to the right of vertical)
+             */
           }, {
             key: "comparePoint",
-            value: function comparePoint(point) {
-              if (this.isAnEndpoint(point))
+            value: function comparePoint(point2) {
+              if (this.isAnEndpoint(point2))
                 return 0;
               var lPt = this.leftSE.point;
               var rPt = this.rightSE.point;
               var v = this.vector();
               if (lPt.x === rPt.x) {
-                if (point.x === lPt.x)
+                if (point2.x === lPt.x)
                   return 0;
-                return point.x < lPt.x ? 1 : -1;
+                return point2.x < lPt.x ? 1 : -1;
               }
-              var yDist = (point.y - lPt.y) / v.y;
+              var yDist = (point2.y - lPt.y) / v.y;
               var xFromYDist = lPt.x + yDist * v.x;
-              if (point.x === xFromYDist)
+              if (point2.x === xFromYDist)
                 return 0;
-              var xDist = (point.x - lPt.x) / v.x;
+              var xDist = (point2.x - lPt.x) / v.x;
               var yFromXDist = lPt.y + xDist * v.y;
-              if (point.y === yFromXDist)
+              if (point2.y === yFromXDist)
                 return 0;
-              return point.y < yFromXDist ? -1 : 1;
-            }
+              return point2.y < yFromXDist ? -1 : 1;
+            }
+            /**
+             * Given another segment, returns the first non-trivial intersection
+             * between the two segments (in terms of sweep line ordering), if it exists.
+             *
+             * A 'non-trivial' intersection is one that will cause one or both of the
+             * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
+             *
+             *   * endpoint of segA with endpoint of segB --> trivial
+             *   * endpoint of segA with point along segB --> non-trivial
+             *   * endpoint of segB with point along segA --> non-trivial
+             *   * point along segA with point along segB --> non-trivial
+             *
+             * If no non-trivial intersection exists, return null
+             * Else, return null.
+             */
           }, {
             key: "getIntersection",
             value: function getIntersection(other) {
                 return null;
               return rounder.round(pt.x, pt.y);
             }
+            /**
+             * Split the given segment into multiple segments on the given points.
+             *  * Each existing segment will retain its leftSE and a new rightSE will be
+             *    generated for it.
+             *  * A new segment will be generated which will adopt the original segment's
+             *    rightSE, and a new leftSE will be generated for it.
+             *  * If there are more than two points given to split on, new segments
+             *    in the middle will be generated with new leftSE and rightSE's.
+             *  * An array of the newly generated SweepEvents will be returned.
+             *
+             * Warning: input array of points is modified
+             */
           }, {
             key: "split",
-            value: function split2(point) {
+            value: function split2(point2) {
               var newEvents = [];
-              var alreadyLinked = point.events !== void 0;
-              var newLeftSE = new SweepEvent(point, true);
-              var newRightSE = new SweepEvent(point, false);
+              var alreadyLinked = point2.events !== void 0;
+              var newLeftSE = new SweepEvent(point2, true);
+              var newRightSE = new SweepEvent(point2, false);
               var oldRightSE = this.rightSE;
               this.replaceRightSE(newRightSE);
               newEvents.push(newRightSE);
               }
               return newEvents;
             }
+            /* Swap which event is left and right */
           }, {
             key: "swapEvents",
             value: function swapEvents() {
                 this.windings[i2] *= -1;
               }
             }
+            /* Consume another segment. We take their rings under our wing
+             * and mark them as consumed. Use for perfectly overlapping segments */
           }, {
             key: "consume",
             value: function consume(other) {
               consumee.leftSE.consumedBy = consumer.leftSE;
               consumee.rightSE.consumedBy = consumer.rightSE;
             }
+            /* The first segment previous segment chain that is in the result */
           }, {
             key: "prevInResult",
             value: function prevInResult() {
               }
               return this._afterState;
             }
+            /* Is this segment part of the final result? */
           }, {
             key: "isInResult",
             value: function isInResult() {
               if (typeof geomRing[i2][0] !== "number" || typeof geomRing[i2][1] !== "number") {
                 throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
               }
-              var point = rounder.round(geomRing[i2][0], geomRing[i2][1]);
-              if (point.x === prevPoint.x && point.y === prevPoint.y)
+              var point2 = rounder.round(geomRing[i2][0], geomRing[i2][1]);
+              if (point2.x === prevPoint.x && point2.y === prevPoint.y)
                 continue;
-              this.segments.push(Segment.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;
+              this.segments.push(Segment.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;
             }
             if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
               this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
         var RingOut = /* @__PURE__ */ function() {
           _createClass(RingOut2, null, [{
             key: "factory",
+            /* Given the segments from the sweep line pass, compute & return a series
+             * of closed rings from all the segments marked to be part of the result */
             value: function factory(allSegments) {
               var ringsOut = [];
               for (var i2 = 0, iMax = allSegments.length; i2 < iMax; i2++) {
               }
               return this._enclosingRing;
             }
+            /* Returns the ring that encloses this one, if any */
           }, {
             key: "_calcEnclosingRing",
             value: function _calcEnclosingRing() {
               }
               return newEvents;
             }
+            /* Safely split a segment that is currently in the datastructures
+             * IE - a segment other than the one that is currently being processed. */
           }, {
             key: "_splitSafely",
             value: function _splitSafely(seg, pt) {
           }
           _createClass(Operation2, [{
             key: "run",
-            value: function run(type3, geom, moreGeoms) {
-              operation.type = type3;
+            value: function run(type2, geom, moreGeoms) {
+              operation.type = type2;
               rounder.reset();
               var multipolys = [new MultiPolyIn(geom, true)];
               for (var i2 = 0, iMax = moreGeoms.length; i2 < iMax; i2++) {
     "node_modules/geojson-precision/index.js"(exports2, module2) {
       (function() {
         function parse(t, coordinatePrecision, extrasPrecision) {
-          function point(p) {
+          function point2(p) {
             return p.map(function(e, index) {
               if (index < 2) {
                 return 1 * e.toFixed(coordinatePrecision);
             });
           }
           function multi(l) {
-            return l.map(point);
+            return l.map(point2);
           }
           function poly(p) {
             return p.map(multi);
             }
             switch (obj.type) {
               case "Point":
-                obj.coordinates = point(obj.coordinates);
+                obj.coordinates = point2(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 isObject2(obj) {
+      function isObject3(obj) {
         return typeof obj === "object" && obj !== null;
       }
       function forEach(obj, cb) {
         if (Array.isArray(obj)) {
           obj.forEach(cb);
-        } else if (isObject2(obj)) {
+        } else if (isObject3(obj)) {
           Object.keys(obj).forEach(function(key) {
             var val = obj[key];
             cb(val, key);
       }
       function getTreeDepth(obj) {
         var depth = 0;
-        if (Array.isArray(obj) || isObject2(obj)) {
+        if (Array.isArray(obj) || isObject3(obj)) {
           forEach(obj, function(val) {
-            if (Array.isArray(val) || isObject2(val)) {
+            if (Array.isArray(val) || isObject3(val)) {
               var tmpDepth = getTreeDepth(val);
               if (tmpDepth > depth) {
                 depth = tmpDepth;
               return prettified;
             }
           }
-          if (isObject2(obj2)) {
+          if (isObject3(obj2)) {
             var nextIndent = currentIndent + indent2;
             var items = [];
             var delimiters;
     }
   });
 
-  // node_modules/fast-deep-equal/index.js
-  var require_fast_deep_equal = __commonJS({
-    "node_modules/fast-deep-equal/index.js"(exports2, module2) {
-      "use strict";
-      module2.exports = function equal(a, b) {
-        if (a === b)
-          return true;
-        if (a && b && typeof a == "object" && typeof b == "object") {
-          if (a.constructor !== b.constructor)
-            return false;
-          var length, i2, keys;
-          if (Array.isArray(a)) {
-            length = a.length;
-            if (length != b.length)
-              return false;
-            for (i2 = length; i2-- !== 0; )
-              if (!equal(a[i2], b[i2]))
-                return false;
-            return true;
-          }
-          if (a.constructor === RegExp)
-            return a.source === b.source && a.flags === b.flags;
-          if (a.valueOf !== Object.prototype.valueOf)
-            return a.valueOf() === b.valueOf();
-          if (a.toString !== Object.prototype.toString)
-            return a.toString() === b.toString();
-          keys = Object.keys(a);
-          length = keys.length;
-          if (length !== Object.keys(b).length)
-            return false;
-          for (i2 = length; i2-- !== 0; )
-            if (!Object.prototype.hasOwnProperty.call(b, keys[i2]))
-              return false;
-          for (i2 = length; i2-- !== 0; ) {
-            var key = keys[i2];
-            if (!equal(a[key], b[key]))
-              return false;
-          }
-          return true;
-        }
-        return a !== a && b !== b;
-      };
-    }
-  });
-
   // node_modules/lodash/lodash.js
   var require_lodash = __commonJS({
     "node_modules/lodash/lodash.js"(exports2, module2) {
       (function() {
         var undefined2;
         var VERSION = "4.17.21";
-        var LARGE_ARRAY_SIZE = 200;
+        var LARGE_ARRAY_SIZE2 = 200;
         var CORE_ERROR_TEXT = "Unsupported core-js use. Try https://npms.io/search?q=ponyfill.", FUNC_ERROR_TEXT3 = "Expected a function", INVALID_TEMPL_VAR_ERROR_TEXT = "Invalid `variable` option passed into `_.template`";
-        var HASH_UNDEFINED = "__lodash_hash_undefined__";
+        var HASH_UNDEFINED4 = "__lodash_hash_undefined__";
         var MAX_MEMOIZE_SIZE = 500;
         var PLACEHOLDER = "__lodash_placeholder__";
         var CLONE_DEEP_FLAG = 1, CLONE_FLAT_FLAG = 2, CLONE_SYMBOLS_FLAG = 4;
-        var COMPARE_PARTIAL_FLAG = 1, COMPARE_UNORDERED_FLAG = 2;
+        var COMPARE_PARTIAL_FLAG5 = 1, COMPARE_UNORDERED_FLAG3 = 2;
         var WRAP_BIND_FLAG = 1, WRAP_BIND_KEY_FLAG = 2, WRAP_CURRY_BOUND_FLAG = 4, WRAP_CURRY_FLAG = 8, WRAP_CURRY_RIGHT_FLAG = 16, WRAP_PARTIAL_FLAG = 32, WRAP_PARTIAL_RIGHT_FLAG = 64, WRAP_ARY_FLAG = 128, WRAP_REARG_FLAG = 256, WRAP_FLIP_FLAG = 512;
         var DEFAULT_TRUNC_LENGTH = 30, DEFAULT_TRUNC_OMISSION = "...";
         var HOT_COUNT = 800, HOT_SPAN = 16;
         var LAZY_FILTER_FLAG = 1, LAZY_MAP_FLAG = 2, LAZY_WHILE_FLAG = 3;
-        var INFINITY2 = 1 / 0, MAX_SAFE_INTEGER = 9007199254740991, MAX_INTEGER = 17976931348623157e292, NAN2 = 0 / 0;
+        var INFINITY2 = 1 / 0, MAX_SAFE_INTEGER3 = 9007199254740991, MAX_INTEGER = 17976931348623157e292, NAN2 = 0 / 0;
         var MAX_ARRAY_LENGTH = 4294967295, MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
         var wrapFlags = [
           ["ary", WRAP_ARY_FLAG],
           ["partialRight", WRAP_PARTIAL_RIGHT_FLAG],
           ["rearg", WRAP_REARG_FLAG]
         ];
-        var argsTag = "[object Arguments]", arrayTag = "[object Array]", asyncTag = "[object AsyncFunction]", boolTag = "[object Boolean]", dateTag = "[object Date]", domExcTag = "[object DOMException]", errorTag = "[object Error]", funcTag = "[object Function]", genTag = "[object GeneratorFunction]", mapTag = "[object Map]", numberTag = "[object Number]", nullTag2 = "[object Null]", objectTag = "[object Object]", promiseTag = "[object Promise]", proxyTag = "[object Proxy]", regexpTag = "[object RegExp]", setTag = "[object Set]", stringTag = "[object String]", symbolTag2 = "[object Symbol]", undefinedTag2 = "[object Undefined]", weakMapTag = "[object WeakMap]", weakSetTag = "[object WeakSet]";
-        var arrayBufferTag = "[object ArrayBuffer]", dataViewTag = "[object DataView]", float32Tag = "[object Float32Array]", float64Tag = "[object Float64Array]", int8Tag = "[object Int8Array]", int16Tag = "[object Int16Array]", int32Tag = "[object Int32Array]", uint8Tag = "[object Uint8Array]", uint8ClampedTag = "[object Uint8ClampedArray]", uint16Tag = "[object Uint16Array]", uint32Tag = "[object Uint32Array]";
+        var argsTag4 = "[object Arguments]", arrayTag3 = "[object Array]", asyncTag2 = "[object AsyncFunction]", boolTag3 = "[object Boolean]", dateTag3 = "[object Date]", domExcTag = "[object DOMException]", errorTag3 = "[object Error]", funcTag3 = "[object Function]", genTag2 = "[object GeneratorFunction]", mapTag4 = "[object Map]", numberTag3 = "[object Number]", nullTag2 = "[object Null]", objectTag4 = "[object Object]", promiseTag2 = "[object Promise]", proxyTag2 = "[object Proxy]", regexpTag3 = "[object RegExp]", setTag4 = "[object Set]", stringTag3 = "[object String]", symbolTag3 = "[object Symbol]", undefinedTag2 = "[object Undefined]", weakMapTag3 = "[object WeakMap]", weakSetTag = "[object WeakSet]";
+        var arrayBufferTag3 = "[object ArrayBuffer]", dataViewTag4 = "[object DataView]", float32Tag2 = "[object Float32Array]", float64Tag2 = "[object Float64Array]", int8Tag2 = "[object Int8Array]", int16Tag2 = "[object Int16Array]", int32Tag2 = "[object Int32Array]", uint8Tag2 = "[object Uint8Array]", uint8ClampedTag2 = "[object Uint8ClampedArray]", uint16Tag2 = "[object Uint16Array]", uint32Tag2 = "[object Uint32Array]";
         var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
         var reEscapedHtml2 = /&(?:amp|lt|gt|quot|#39);/g, reUnescapedHtml2 = /[&<>"']/g, reHasEscapedHtml2 = RegExp(reEscapedHtml2.source), reHasUnescapedHtml2 = RegExp(reUnescapedHtml2.source);
         var reEscape = /<%-([\s\S]+?)%>/g, reEvaluate = /<%([\s\S]+?)%>/g, reInterpolate = /<%=([\s\S]+?)%>/g;
         var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/, rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
-        var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, reHasRegExpChar = RegExp(reRegExpChar.source);
+        var reRegExpChar2 = /[\\^$.*+?()[\]{}|]/g, reHasRegExpChar = RegExp(reRegExpChar2.source);
         var reTrimStart2 = /^\s+/;
         var reWhitespace2 = /\s/;
         var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, reSplitDetails = /,? & /;
         var reFlags = /\w*$/;
         var reIsBadHex2 = /^[-+]0x[0-9a-f]+$/i;
         var reIsBinary2 = /^0b[01]+$/i;
-        var reIsHostCtor = /^\[object .+?Constructor\]$/;
+        var reIsHostCtor2 = /^\[object .+?Constructor\]$/;
         var reIsOctal2 = /^0o[0-7]+$/i;
-        var reIsUint = /^(?:0|[1-9]\d*)$/;
+        var reIsUint2 = /^(?:0|[1-9]\d*)$/;
         var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
         var reNoMatch = /($^)/;
         var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
           "setTimeout"
         ];
         var templateCounter = -1;
-        var typedArrayTags = {};
-        typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true;
-        typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+        var typedArrayTags2 = {};
+        typedArrayTags2[float32Tag2] = typedArrayTags2[float64Tag2] = typedArrayTags2[int8Tag2] = typedArrayTags2[int16Tag2] = typedArrayTags2[int32Tag2] = typedArrayTags2[uint8Tag2] = typedArrayTags2[uint8ClampedTag2] = typedArrayTags2[uint16Tag2] = typedArrayTags2[uint32Tag2] = true;
+        typedArrayTags2[argsTag4] = typedArrayTags2[arrayTag3] = typedArrayTags2[arrayBufferTag3] = typedArrayTags2[boolTag3] = typedArrayTags2[dataViewTag4] = typedArrayTags2[dateTag3] = typedArrayTags2[errorTag3] = typedArrayTags2[funcTag3] = typedArrayTags2[mapTag4] = typedArrayTags2[numberTag3] = typedArrayTags2[objectTag4] = typedArrayTags2[regexpTag3] = typedArrayTags2[setTag4] = typedArrayTags2[stringTag3] = typedArrayTags2[weakMapTag3] = false;
         var cloneableTags = {};
-        cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[mapTag] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[setTag] = cloneableTags[stringTag] = cloneableTags[symbolTag2] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
-        cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false;
+        cloneableTags[argsTag4] = cloneableTags[arrayTag3] = cloneableTags[arrayBufferTag3] = cloneableTags[dataViewTag4] = cloneableTags[boolTag3] = cloneableTags[dateTag3] = cloneableTags[float32Tag2] = cloneableTags[float64Tag2] = cloneableTags[int8Tag2] = cloneableTags[int16Tag2] = cloneableTags[int32Tag2] = cloneableTags[mapTag4] = cloneableTags[numberTag3] = cloneableTags[objectTag4] = cloneableTags[regexpTag3] = cloneableTags[setTag4] = cloneableTags[stringTag3] = cloneableTags[symbolTag3] = cloneableTags[uint8Tag2] = cloneableTags[uint8ClampedTag2] = cloneableTags[uint16Tag2] = cloneableTags[uint32Tag2] = true;
+        cloneableTags[errorTag3] = cloneableTags[funcTag3] = cloneableTags[weakMapTag3] = false;
         var deburredLetters = {
+          // Latin-1 Supplement block.
           "\xC0": "A",
           "\xC1": "A",
           "\xC2": "A",
           "\xDE": "Th",
           "\xFE": "th",
           "\xDF": "ss",
+          // Latin Extended-A block.
           "\u0100": "A",
           "\u0102": "A",
           "\u0104": "A",
         var freeGlobal2 = typeof global == "object" && global && global.Object === Object && global;
         var freeSelf2 = typeof self == "object" && self && self.Object === Object && self;
         var root3 = freeGlobal2 || freeSelf2 || Function("return this")();
-        var freeExports = typeof exports2 == "object" && exports2 && !exports2.nodeType && exports2;
-        var freeModule = freeExports && typeof module2 == "object" && module2 && !module2.nodeType && module2;
-        var moduleExports = freeModule && freeModule.exports === freeExports;
-        var freeProcess = moduleExports && freeGlobal2.process;
-        var nodeUtil = function() {
+        var freeExports3 = typeof exports2 == "object" && exports2 && !exports2.nodeType && exports2;
+        var freeModule3 = freeExports3 && typeof module2 == "object" && module2 && !module2.nodeType && module2;
+        var moduleExports3 = freeModule3 && freeModule3.exports === freeExports3;
+        var freeProcess2 = moduleExports3 && freeGlobal2.process;
+        var nodeUtil2 = function() {
           try {
-            var types = freeModule && freeModule.require && freeModule.require("util").types;
+            var types = freeModule3 && freeModule3.require && freeModule3.require("util").types;
             if (types) {
               return types;
             }
-            return freeProcess && freeProcess.binding && freeProcess.binding("util");
+            return freeProcess2 && freeProcess2.binding && freeProcess2.binding("util");
           } catch (e) {
           }
         }();
-        var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, nodeIsDate = nodeUtil && nodeUtil.isDate, nodeIsMap = nodeUtil && nodeUtil.isMap, nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, nodeIsSet = nodeUtil && nodeUtil.isSet, nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
+        var nodeIsArrayBuffer = nodeUtil2 && nodeUtil2.isArrayBuffer, nodeIsDate = nodeUtil2 && nodeUtil2.isDate, nodeIsMap = nodeUtil2 && nodeUtil2.isMap, nodeIsRegExp = nodeUtil2 && nodeUtil2.isRegExp, nodeIsSet = nodeUtil2 && nodeUtil2.isSet, nodeIsTypedArray2 = nodeUtil2 && nodeUtil2.isTypedArray;
         function apply(func, thisArg, args) {
           switch (args.length) {
             case 0:
           }
           return true;
         }
-        function arrayFilter(array2, predicate) {
+        function arrayFilter2(array2, predicate) {
           var index = -1, length = array2 == null ? 0 : array2.length, resIndex = 0, result = [];
           while (++index < length) {
             var value = array2[index];
           }
           return result;
         }
-        function arrayPush(array2, values) {
+        function arrayPush2(array2, values) {
           var index = -1, length = values.length, offset = array2.length;
           while (++index < length) {
             array2[offset + index] = values[index];
           }
           return accumulator;
         }
-        function arraySome(array2, predicate) {
+        function arraySome2(array2, predicate) {
           var index = -1, length = array2 == null ? 0 : array2.length;
           while (++index < length) {
             if (predicate(array2[index], index, array2)) {
           }
           return result;
         }
-        function baseTimes(n2, iteratee) {
+        function baseTimes2(n2, iteratee) {
           var index = -1, result = Array(n2);
           while (++index < n2) {
             result[index] = iteratee(index);
         function baseTrim2(string) {
           return string ? string.slice(0, trimmedEndIndex2(string) + 1).replace(reTrimStart2, "") : string;
         }
-        function baseUnary(func) {
+        function baseUnary2(func) {
           return function(value) {
             return func(value);
           };
             return object[key];
           });
         }
-        function cacheHas(cache, key) {
+        function cacheHas2(cache, key) {
           return cache.has(key);
         }
         function charsStartIndex(strSymbols, chrSymbols) {
         function escapeStringChar(chr) {
           return "\\" + stringEscapes[chr];
         }
-        function getValue(object, key) {
+        function getValue2(object, key) {
           return object == null ? undefined2 : object[key];
         }
         function hasUnicode(string) {
           }
           return result;
         }
-        function mapToArray(map2) {
+        function mapToArray2(map2) {
           var index = -1, result = Array(map2.size);
           map2.forEach(function(value, key) {
             result[++index] = [key, value];
           });
           return result;
         }
-        function overArg(func, transform2) {
+        function overArg2(func, transform2) {
           return function(arg) {
             return func(transform2(arg));
           };
           }
           return result;
         }
-        function setToArray(set3) {
+        function setToArray2(set3) {
           var index = -1, result = Array(set3.size);
           set3.forEach(function(value) {
             result[++index] = value;
         var runInContext = function runInContext2(context) {
           context = context == null ? root3 : _.defaults(root3.Object(), context, _.pick(root3, contextProps));
           var Array2 = context.Array, Date2 = context.Date, Error2 = context.Error, Function2 = context.Function, Math2 = context.Math, Object2 = context.Object, RegExp2 = context.RegExp, String2 = context.String, TypeError2 = context.TypeError;
-          var arrayProto = Array2.prototype, funcProto = Function2.prototype, objectProto3 = Object2.prototype;
-          var coreJsData = context["__core-js_shared__"];
-          var funcToString = funcProto.toString;
-          var hasOwnProperty2 = objectProto3.hasOwnProperty;
+          var arrayProto2 = Array2.prototype, funcProto3 = Function2.prototype, objectProto13 = Object2.prototype;
+          var coreJsData2 = context["__core-js_shared__"];
+          var funcToString3 = funcProto3.toString;
+          var hasOwnProperty10 = objectProto13.hasOwnProperty;
           var idCounter = 0;
-          var maskSrcKey = function() {
-            var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || "");
+          var maskSrcKey2 = function() {
+            var uid = /[^.]+$/.exec(coreJsData2 && coreJsData2.keys && coreJsData2.keys.IE_PROTO || "");
             return uid ? "Symbol(src)_1." + uid : "";
           }();
-          var nativeObjectToString3 = objectProto3.toString;
-          var objectCtorString = funcToString.call(Object2);
+          var nativeObjectToString3 = objectProto13.toString;
+          var objectCtorString = funcToString3.call(Object2);
           var oldDash = root3._;
-          var reIsNative = RegExp2(
-            "^" + funcToString.call(hasOwnProperty2).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$"
+          var reIsNative2 = RegExp2(
+            "^" + funcToString3.call(hasOwnProperty10).replace(reRegExpChar2, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$"
           );
-          var Buffer2 = moduleExports ? context.Buffer : undefined2, Symbol3 = context.Symbol, Uint8Array2 = context.Uint8Array, allocUnsafe = Buffer2 ? Buffer2.allocUnsafe : undefined2, getPrototype = overArg(Object2.getPrototypeOf, Object2), objectCreate = Object2.create, propertyIsEnumerable = objectProto3.propertyIsEnumerable, splice = arrayProto.splice, spreadableSymbol = Symbol3 ? Symbol3.isConcatSpreadable : undefined2, symIterator = Symbol3 ? Symbol3.iterator : undefined2, symToStringTag3 = Symbol3 ? Symbol3.toStringTag : undefined2;
+          var Buffer3 = moduleExports3 ? context.Buffer : undefined2, Symbol3 = context.Symbol, Uint8Array3 = context.Uint8Array, allocUnsafe = Buffer3 ? Buffer3.allocUnsafe : undefined2, getPrototype = overArg2(Object2.getPrototypeOf, Object2), objectCreate = Object2.create, propertyIsEnumerable3 = objectProto13.propertyIsEnumerable, splice2 = arrayProto2.splice, spreadableSymbol = Symbol3 ? Symbol3.isConcatSpreadable : undefined2, symIterator = Symbol3 ? Symbol3.iterator : undefined2, symToStringTag3 = Symbol3 ? Symbol3.toStringTag : undefined2;
           var defineProperty = function() {
             try {
-              var func = getNative(Object2, "defineProperty");
+              var func = getNative2(Object2, "defineProperty");
               func({}, "", {});
               return func;
             } catch (e) {
             }
           }();
           var ctxClearTimeout = context.clearTimeout !== root3.clearTimeout && context.clearTimeout, ctxNow = Date2 && Date2.now !== root3.Date.now && Date2.now, ctxSetTimeout = context.setTimeout !== root3.setTimeout && context.setTimeout;
-          var nativeCeil = Math2.ceil, nativeFloor = Math2.floor, nativeGetSymbols = Object2.getOwnPropertySymbols, nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : undefined2, nativeIsFinite = context.isFinite, nativeJoin = arrayProto.join, nativeKeys = overArg(Object2.keys, Object2), nativeMax2 = Math2.max, nativeMin2 = Math2.min, nativeNow = Date2.now, nativeParseInt = context.parseInt, nativeRandom = Math2.random, nativeReverse = arrayProto.reverse;
-          var DataView2 = getNative(context, "DataView"), Map2 = getNative(context, "Map"), Promise2 = getNative(context, "Promise"), Set2 = getNative(context, "Set"), WeakMap = getNative(context, "WeakMap"), nativeCreate = getNative(Object2, "create");
-          var metaMap = WeakMap && new WeakMap();
+          var nativeCeil = Math2.ceil, nativeFloor = Math2.floor, nativeGetSymbols2 = Object2.getOwnPropertySymbols, nativeIsBuffer2 = Buffer3 ? Buffer3.isBuffer : undefined2, nativeIsFinite = context.isFinite, nativeJoin = arrayProto2.join, nativeKeys2 = overArg2(Object2.keys, Object2), nativeMax2 = Math2.max, nativeMin2 = Math2.min, nativeNow = Date2.now, nativeParseInt = context.parseInt, nativeRandom = Math2.random, nativeReverse = arrayProto2.reverse;
+          var DataView3 = getNative2(context, "DataView"), Map3 = getNative2(context, "Map"), Promise3 = getNative2(context, "Promise"), Set3 = getNative2(context, "Set"), WeakMap2 = getNative2(context, "WeakMap"), nativeCreate2 = getNative2(Object2, "create");
+          var metaMap = WeakMap2 && new WeakMap2();
           var realNames = {};
-          var dataViewCtorString = toSource(DataView2), mapCtorString = toSource(Map2), promiseCtorString = toSource(Promise2), setCtorString = toSource(Set2), weakMapCtorString = toSource(WeakMap);
-          var symbolProto2 = Symbol3 ? Symbol3.prototype : undefined2, symbolValueOf = symbolProto2 ? symbolProto2.valueOf : undefined2, symbolToString2 = symbolProto2 ? symbolProto2.toString : undefined2;
+          var dataViewCtorString2 = toSource2(DataView3), mapCtorString2 = toSource2(Map3), promiseCtorString2 = toSource2(Promise3), setCtorString2 = toSource2(Set3), weakMapCtorString2 = toSource2(WeakMap2);
+          var symbolProto3 = Symbol3 ? Symbol3.prototype : undefined2, symbolValueOf2 = symbolProto3 ? symbolProto3.valueOf : undefined2, symbolToString2 = symbolProto3 ? symbolProto3.toString : undefined2;
           function lodash(value) {
             if (isObjectLike2(value) && !isArray2(value) && !(value instanceof LazyWrapper)) {
               if (value instanceof LodashWrapper) {
                 return value;
               }
-              if (hasOwnProperty2.call(value, "__wrapped__")) {
+              if (hasOwnProperty10.call(value, "__wrapped__")) {
                 return wrapperClone(value);
               }
             }
             function object() {
             }
             return function(proto) {
-              if (!isObject2(proto)) {
+              if (!isObject3(proto)) {
                 return {};
               }
               if (objectCreate) {
             this.__values__ = undefined2;
           }
           lodash.templateSettings = {
+            /**
+             * Used to detect `data` property values to be HTML-escaped.
+             *
+             * @memberOf _.templateSettings
+             * @type {RegExp}
+             */
             "escape": reEscape,
+            /**
+             * Used to detect code to be evaluated.
+             *
+             * @memberOf _.templateSettings
+             * @type {RegExp}
+             */
             "evaluate": reEvaluate,
+            /**
+             * Used to detect `data` property values to inject.
+             *
+             * @memberOf _.templateSettings
+             * @type {RegExp}
+             */
             "interpolate": reInterpolate,
+            /**
+             * Used to reference the data object in the template text.
+             *
+             * @memberOf _.templateSettings
+             * @type {string}
+             */
             "variable": "",
+            /**
+             * Used to import variables into the compiled template.
+             *
+             * @memberOf _.templateSettings
+             * @type {Object}
+             */
             "imports": {
+              /**
+               * A reference to the `lodash` function.
+               *
+               * @memberOf _.templateSettings.imports
+               * @type {Function}
+               */
               "_": lodash
             }
           };
                 index += dir;
                 var iterIndex = -1, value = array2[index];
                 while (++iterIndex < iterLength) {
-                  var data = iteratees[iterIndex], iteratee2 = data.iteratee, type3 = data.type, computed = iteratee2(value);
-                  if (type3 == LAZY_MAP_FLAG) {
+                  var data = iteratees[iterIndex], iteratee2 = data.iteratee, type2 = data.type, computed = iteratee2(value);
+                  if (type2 == LAZY_MAP_FLAG) {
                     value = computed;
                   } else if (!computed) {
-                    if (type3 == LAZY_FILTER_FLAG) {
+                    if (type2 == LAZY_FILTER_FLAG) {
                       continue outer;
                     } else {
                       break outer;
           }
           LazyWrapper.prototype = baseCreate(baseLodash.prototype);
           LazyWrapper.prototype.constructor = LazyWrapper;
-          function Hash(entries) {
+          function Hash2(entries) {
             var index = -1, length = entries == null ? 0 : entries.length;
             this.clear();
             while (++index < length) {
               this.set(entry[0], entry[1]);
             }
           }
-          function hashClear() {
-            this.__data__ = nativeCreate ? nativeCreate(null) : {};
+          function hashClear2() {
+            this.__data__ = nativeCreate2 ? nativeCreate2(null) : {};
             this.size = 0;
           }
-          function hashDelete(key) {
+          function hashDelete2(key) {
             var result2 = this.has(key) && delete this.__data__[key];
             this.size -= result2 ? 1 : 0;
             return result2;
           }
-          function hashGet(key) {
+          function hashGet2(key) {
             var data = this.__data__;
-            if (nativeCreate) {
+            if (nativeCreate2) {
               var result2 = data[key];
-              return result2 === HASH_UNDEFINED ? undefined2 : result2;
+              return result2 === HASH_UNDEFINED4 ? undefined2 : result2;
             }
-            return hasOwnProperty2.call(data, key) ? data[key] : undefined2;
+            return hasOwnProperty10.call(data, key) ? data[key] : undefined2;
           }
-          function hashHas(key) {
+          function hashHas2(key) {
             var data = this.__data__;
-            return nativeCreate ? data[key] !== undefined2 : hasOwnProperty2.call(data, key);
+            return nativeCreate2 ? data[key] !== undefined2 : hasOwnProperty10.call(data, key);
           }
-          function hashSet(key, value) {
+          function hashSet2(key, value) {
             var data = this.__data__;
             this.size += this.has(key) ? 0 : 1;
-            data[key] = nativeCreate && value === undefined2 ? HASH_UNDEFINED : value;
+            data[key] = nativeCreate2 && value === undefined2 ? HASH_UNDEFINED4 : value;
             return this;
           }
-          Hash.prototype.clear = hashClear;
-          Hash.prototype["delete"] = hashDelete;
-          Hash.prototype.get = hashGet;
-          Hash.prototype.has = hashHas;
-          Hash.prototype.set = hashSet;
-          function ListCache(entries) {
+          Hash2.prototype.clear = hashClear2;
+          Hash2.prototype["delete"] = hashDelete2;
+          Hash2.prototype.get = hashGet2;
+          Hash2.prototype.has = hashHas2;
+          Hash2.prototype.set = hashSet2;
+          function ListCache2(entries) {
             var index = -1, length = entries == null ? 0 : entries.length;
             this.clear();
             while (++index < length) {
               this.set(entry[0], entry[1]);
             }
           }
-          function listCacheClear() {
+          function listCacheClear2() {
             this.__data__ = [];
             this.size = 0;
           }
-          function listCacheDelete(key) {
-            var data = this.__data__, index = assocIndexOf(data, key);
+          function listCacheDelete2(key) {
+            var data = this.__data__, index = assocIndexOf2(data, key);
             if (index < 0) {
               return false;
             }
             if (index == lastIndex) {
               data.pop();
             } else {
-              splice.call(data, index, 1);
+              splice2.call(data, index, 1);
             }
             --this.size;
             return true;
           }
-          function listCacheGet(key) {
-            var data = this.__data__, index = assocIndexOf(data, key);
+          function listCacheGet2(key) {
+            var data = this.__data__, index = assocIndexOf2(data, key);
             return index < 0 ? undefined2 : data[index][1];
           }
-          function listCacheHas(key) {
-            return assocIndexOf(this.__data__, key) > -1;
+          function listCacheHas2(key) {
+            return assocIndexOf2(this.__data__, key) > -1;
           }
-          function listCacheSet(key, value) {
-            var data = this.__data__, index = assocIndexOf(data, key);
+          function listCacheSet2(key, value) {
+            var data = this.__data__, index = assocIndexOf2(data, key);
             if (index < 0) {
               ++this.size;
               data.push([key, value]);
             }
             return this;
           }
-          ListCache.prototype.clear = listCacheClear;
-          ListCache.prototype["delete"] = listCacheDelete;
-          ListCache.prototype.get = listCacheGet;
-          ListCache.prototype.has = listCacheHas;
-          ListCache.prototype.set = listCacheSet;
-          function MapCache(entries) {
+          ListCache2.prototype.clear = listCacheClear2;
+          ListCache2.prototype["delete"] = listCacheDelete2;
+          ListCache2.prototype.get = listCacheGet2;
+          ListCache2.prototype.has = listCacheHas2;
+          ListCache2.prototype.set = listCacheSet2;
+          function MapCache2(entries) {
             var index = -1, length = entries == null ? 0 : entries.length;
             this.clear();
             while (++index < length) {
               this.set(entry[0], entry[1]);
             }
           }
-          function mapCacheClear() {
+          function mapCacheClear2() {
             this.size = 0;
             this.__data__ = {
-              "hash": new Hash(),
-              "map": new (Map2 || ListCache)(),
-              "string": new Hash()
+              "hash": new Hash2(),
+              "map": new (Map3 || ListCache2)(),
+              "string": new Hash2()
             };
           }
-          function mapCacheDelete(key) {
-            var result2 = getMapData(this, key)["delete"](key);
+          function mapCacheDelete2(key) {
+            var result2 = getMapData2(this, key)["delete"](key);
             this.size -= result2 ? 1 : 0;
             return result2;
           }
-          function mapCacheGet(key) {
-            return getMapData(this, key).get(key);
+          function mapCacheGet2(key) {
+            return getMapData2(this, key).get(key);
           }
-          function mapCacheHas(key) {
-            return getMapData(this, key).has(key);
+          function mapCacheHas2(key) {
+            return getMapData2(this, key).has(key);
           }
-          function mapCacheSet(key, value) {
-            var data = getMapData(this, key), size2 = data.size;
+          function mapCacheSet2(key, value) {
+            var data = getMapData2(this, key), size2 = data.size;
             data.set(key, value);
             this.size += data.size == size2 ? 0 : 1;
             return this;
           }
-          MapCache.prototype.clear = mapCacheClear;
-          MapCache.prototype["delete"] = mapCacheDelete;
-          MapCache.prototype.get = mapCacheGet;
-          MapCache.prototype.has = mapCacheHas;
-          MapCache.prototype.set = mapCacheSet;
-          function SetCache(values2) {
+          MapCache2.prototype.clear = mapCacheClear2;
+          MapCache2.prototype["delete"] = mapCacheDelete2;
+          MapCache2.prototype.get = mapCacheGet2;
+          MapCache2.prototype.has = mapCacheHas2;
+          MapCache2.prototype.set = mapCacheSet2;
+          function SetCache2(values2) {
             var index = -1, length = values2 == null ? 0 : values2.length;
-            this.__data__ = new MapCache();
+            this.__data__ = new MapCache2();
             while (++index < length) {
               this.add(values2[index]);
             }
           }
-          function setCacheAdd(value) {
-            this.__data__.set(value, HASH_UNDEFINED);
+          function setCacheAdd2(value) {
+            this.__data__.set(value, HASH_UNDEFINED4);
             return this;
           }
-          function setCacheHas(value) {
+          function setCacheHas2(value) {
             return this.__data__.has(value);
           }
-          SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
-          SetCache.prototype.has = setCacheHas;
-          function Stack(entries) {
-            var data = this.__data__ = new ListCache(entries);
+          SetCache2.prototype.add = SetCache2.prototype.push = setCacheAdd2;
+          SetCache2.prototype.has = setCacheHas2;
+          function Stack2(entries) {
+            var data = this.__data__ = new ListCache2(entries);
             this.size = data.size;
           }
-          function stackClear() {
-            this.__data__ = new ListCache();
+          function stackClear2() {
+            this.__data__ = new ListCache2();
             this.size = 0;
           }
-          function stackDelete(key) {
+          function stackDelete2(key) {
             var data = this.__data__, result2 = data["delete"](key);
             this.size = data.size;
             return result2;
           }
-          function stackGet(key) {
+          function stackGet2(key) {
             return this.__data__.get(key);
           }
-          function stackHas(key) {
+          function stackHas2(key) {
             return this.__data__.has(key);
           }
-          function stackSet(key, value) {
+          function stackSet2(key, value) {
             var data = this.__data__;
-            if (data instanceof ListCache) {
+            if (data instanceof ListCache2) {
               var pairs = data.__data__;
-              if (!Map2 || pairs.length < LARGE_ARRAY_SIZE - 1) {
+              if (!Map3 || pairs.length < LARGE_ARRAY_SIZE2 - 1) {
                 pairs.push([key, value]);
                 this.size = ++data.size;
                 return this;
               }
-              data = this.__data__ = new MapCache(pairs);
+              data = this.__data__ = new MapCache2(pairs);
             }
             data.set(key, value);
             this.size = data.size;
             return this;
           }
-          Stack.prototype.clear = stackClear;
-          Stack.prototype["delete"] = stackDelete;
-          Stack.prototype.get = stackGet;
-          Stack.prototype.has = stackHas;
-          Stack.prototype.set = stackSet;
-          function arrayLikeKeys(value, inherited) {
-            var isArr = isArray2(value), isArg = !isArr && isArguments(value), isBuff = !isArr && !isArg && isBuffer(value), isType = !isArr && !isArg && !isBuff && isTypedArray(value), skipIndexes = isArr || isArg || isBuff || isType, result2 = skipIndexes ? baseTimes(value.length, String2) : [], length = result2.length;
+          Stack2.prototype.clear = stackClear2;
+          Stack2.prototype["delete"] = stackDelete2;
+          Stack2.prototype.get = stackGet2;
+          Stack2.prototype.has = stackHas2;
+          Stack2.prototype.set = stackSet2;
+          function arrayLikeKeys2(value, inherited) {
+            var isArr = isArray2(value), isArg = !isArr && isArguments2(value), isBuff = !isArr && !isArg && isBuffer2(value), isType = !isArr && !isArg && !isBuff && isTypedArray2(value), skipIndexes = isArr || isArg || isBuff || isType, result2 = skipIndexes ? baseTimes2(value.length, String2) : [], length = result2.length;
             for (var key in value) {
-              if ((inherited || hasOwnProperty2.call(value, key)) && !(skipIndexes && (key == "length" || isBuff && (key == "offset" || key == "parent") || isType && (key == "buffer" || key == "byteLength" || key == "byteOffset") || isIndex(key, length)))) {
+              if ((inherited || hasOwnProperty10.call(value, key)) && !(skipIndexes && // Safari 9 has enumerable `arguments.length` in strict mode.
+              (key == "length" || // Node.js 0.10 has enumerable non-index properties on buffers.
+              isBuff && (key == "offset" || key == "parent") || // PhantomJS 2 has enumerable non-index properties on typed arrays.
+              isType && (key == "buffer" || key == "byteLength" || key == "byteOffset") || // Skip index properties.
+              isIndex2(key, length)))) {
                 result2.push(key);
               }
             }
             return shuffleSelf(copyArray(array2));
           }
           function assignMergeValue(object, key, value) {
-            if (value !== undefined2 && !eq(object[key], value) || value === undefined2 && !(key in object)) {
+            if (value !== undefined2 && !eq2(object[key], value) || value === undefined2 && !(key in object)) {
               baseAssignValue(object, key, value);
             }
           }
           function assignValue(object, key, value) {
             var objValue = object[key];
-            if (!(hasOwnProperty2.call(object, key) && eq(objValue, value)) || value === undefined2 && !(key in object)) {
+            if (!(hasOwnProperty10.call(object, key) && eq2(objValue, value)) || value === undefined2 && !(key in object)) {
               baseAssignValue(object, key, value);
             }
           }
-          function assocIndexOf(array2, key) {
+          function assocIndexOf2(array2, key) {
             var length = array2.length;
             while (length--) {
-              if (eq(array2[length][0], key)) {
+              if (eq2(array2[length][0], key)) {
                 return length;
               }
             }
             return accumulator;
           }
           function baseAssign(object, source) {
-            return object && copyObject(source, keys(source), object);
+            return object && copyObject(source, keys2(source), object);
           }
           function baseAssignIn(object, source) {
             return object && copyObject(source, keysIn(source), object);
             if (result2 !== undefined2) {
               return result2;
             }
-            if (!isObject2(value)) {
+            if (!isObject3(value)) {
               return value;
             }
             var isArr = isArray2(value);
                 return copyArray(value, result2);
               }
             } else {
-              var tag = getTag(value), isFunc = tag == funcTag || tag == genTag;
-              if (isBuffer(value)) {
+              var tag = getTag2(value), isFunc = tag == funcTag3 || tag == genTag2;
+              if (isBuffer2(value)) {
                 return cloneBuffer(value, isDeep);
               }
-              if (tag == objectTag || tag == argsTag || isFunc && !object) {
+              if (tag == objectTag4 || tag == argsTag4 || isFunc && !object) {
                 result2 = isFlat || isFunc ? {} : initCloneObject(value);
                 if (!isDeep) {
                   return isFlat ? copySymbolsIn(value, baseAssignIn(result2, value)) : copySymbols(value, baseAssign(result2, value));
                 result2 = initCloneByTag(value, tag, isDeep);
               }
             }
-            stack || (stack = new Stack());
+            stack || (stack = new Stack2());
             var stacked = stack.get(value);
             if (stacked) {
               return stacked;
                 result2.set(key2, baseClone(subValue, bitmask, customizer, key2, value, stack));
               });
             }
-            var keysFunc = isFull ? isFlat ? getAllKeysIn : getAllKeys : isFlat ? keysIn : keys;
+            var keysFunc = isFull ? isFlat ? getAllKeysIn : getAllKeys2 : isFlat ? keysIn : keys2;
             var props = isArr ? undefined2 : keysFunc(value);
             arrayEach(props || value, function(subValue, key2) {
               if (props) {
             return result2;
           }
           function baseConforms(source) {
-            var props = keys(source);
+            var props = keys2(source);
             return function(object) {
               return baseConformsTo(object, source, props);
             };
               return result2;
             }
             if (iteratee2) {
-              values2 = arrayMap2(values2, baseUnary(iteratee2));
+              values2 = arrayMap2(values2, baseUnary2(iteratee2));
             }
             if (comparator) {
               includes2 = arrayIncludesWith;
               isCommon = false;
-            } else if (values2.length >= LARGE_ARRAY_SIZE) {
-              includes2 = cacheHas;
+            } else if (values2.length >= LARGE_ARRAY_SIZE2) {
+              includes2 = cacheHas2;
               isCommon = false;
-              values2 = new SetCache(values2);
+              values2 = new SetCache2(values2);
             }
             outer:
               while (++index < length) {
                 if (depth > 1) {
                   baseFlatten(value, depth - 1, predicate, isStrict, result2);
                 } else {
-                  arrayPush(result2, value);
+                  arrayPush2(result2, value);
                 }
               } else if (!isStrict) {
                 result2[result2.length] = value;
           var baseFor = createBaseFor();
           var baseForRight = createBaseFor(true);
           function baseForOwn(object, iteratee2) {
-            return object && baseFor(object, iteratee2, keys);
+            return object && baseFor(object, iteratee2, keys2);
           }
           function baseForOwnRight(object, iteratee2) {
-            return object && baseForRight(object, iteratee2, keys);
+            return object && baseForRight(object, iteratee2, keys2);
           }
           function baseFunctions(object, props) {
-            return arrayFilter(props, function(key) {
-              return isFunction(object[key]);
+            return arrayFilter2(props, function(key) {
+              return isFunction2(object[key]);
             });
           }
           function baseGet(object, path) {
             }
             return index && index == length ? object : undefined2;
           }
-          function baseGetAllKeys(object, keysFunc, symbolsFunc) {
+          function baseGetAllKeys2(object, keysFunc, symbolsFunc) {
             var result2 = keysFunc(object);
-            return isArray2(object) ? result2 : arrayPush(result2, symbolsFunc(object));
+            return isArray2(object) ? result2 : arrayPush2(result2, symbolsFunc(object));
           }
           function baseGetTag2(value) {
             if (value == null) {
             return value > other;
           }
           function baseHas(object, key) {
-            return object != null && hasOwnProperty2.call(object, key);
+            return object != null && hasOwnProperty10.call(object, key);
           }
           function baseHasIn(object, key) {
             return object != null && key in Object2(object);
             while (othIndex--) {
               var array2 = arrays[othIndex];
               if (othIndex && iteratee2) {
-                array2 = arrayMap2(array2, baseUnary(iteratee2));
+                array2 = arrayMap2(array2, baseUnary2(iteratee2));
               }
               maxLength = nativeMin2(array2.length, maxLength);
-              caches[othIndex] = !comparator && (iteratee2 || length >= 120 && array2.length >= 120) ? new SetCache(othIndex && array2) : undefined2;
+              caches[othIndex] = !comparator && (iteratee2 || length >= 120 && array2.length >= 120) ? new SetCache2(othIndex && array2) : undefined2;
             }
             array2 = arrays[0];
             var index = -1, seen = caches[0];
               while (++index < length && result2.length < maxLength) {
                 var value = array2[index], computed = iteratee2 ? iteratee2(value) : value;
                 value = comparator || value !== 0 ? value : 0;
-                if (!(seen ? cacheHas(seen, computed) : includes2(result2, computed, comparator))) {
+                if (!(seen ? cacheHas2(seen, computed) : includes2(result2, computed, comparator))) {
                   othIndex = othLength;
                   while (--othIndex) {
                     var cache = caches[othIndex];
-                    if (!(cache ? cacheHas(cache, computed) : includes2(arrays[othIndex], computed, comparator))) {
+                    if (!(cache ? cacheHas2(cache, computed) : includes2(arrays[othIndex], computed, comparator))) {
                       continue outer;
                     }
                   }
             var func = object == null ? object : object[toKey(last(path))];
             return func == null ? undefined2 : apply(func, object, args);
           }
-          function baseIsArguments(value) {
-            return isObjectLike2(value) && baseGetTag2(value) == argsTag;
+          function baseIsArguments2(value) {
+            return isObjectLike2(value) && baseGetTag2(value) == argsTag4;
           }
           function baseIsArrayBuffer(value) {
-            return isObjectLike2(value) && baseGetTag2(value) == arrayBufferTag;
+            return isObjectLike2(value) && baseGetTag2(value) == arrayBufferTag3;
           }
           function baseIsDate(value) {
-            return isObjectLike2(value) && baseGetTag2(value) == dateTag;
+            return isObjectLike2(value) && baseGetTag2(value) == dateTag3;
           }
-          function baseIsEqual(value, other, bitmask, customizer, stack) {
+          function baseIsEqual2(value, other, bitmask, customizer, stack) {
             if (value === other) {
               return true;
             }
             if (value == null || other == null || !isObjectLike2(value) && !isObjectLike2(other)) {
               return value !== value && other !== other;
             }
-            return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
+            return baseIsEqualDeep2(value, other, bitmask, customizer, baseIsEqual2, stack);
           }
-          function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
-            var objIsArr = isArray2(object), othIsArr = isArray2(other), objTag = objIsArr ? arrayTag : getTag(object), othTag = othIsArr ? arrayTag : getTag(other);
-            objTag = objTag == argsTag ? objectTag : objTag;
-            othTag = othTag == argsTag ? objectTag : othTag;
-            var objIsObj = objTag == objectTag, othIsObj = othTag == objectTag, isSameTag = objTag == othTag;
-            if (isSameTag && isBuffer(object)) {
-              if (!isBuffer(other)) {
+          function baseIsEqualDeep2(object, other, bitmask, customizer, equalFunc, stack) {
+            var objIsArr = isArray2(object), othIsArr = isArray2(other), objTag = objIsArr ? arrayTag3 : getTag2(object), othTag = othIsArr ? arrayTag3 : getTag2(other);
+            objTag = objTag == argsTag4 ? objectTag4 : objTag;
+            othTag = othTag == argsTag4 ? objectTag4 : othTag;
+            var objIsObj = objTag == objectTag4, othIsObj = othTag == objectTag4, isSameTag = objTag == othTag;
+            if (isSameTag && isBuffer2(object)) {
+              if (!isBuffer2(other)) {
                 return false;
               }
               objIsArr = true;
               objIsObj = false;
             }
             if (isSameTag && !objIsObj) {
-              stack || (stack = new Stack());
-              return objIsArr || isTypedArray(object) ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
+              stack || (stack = new Stack2());
+              return objIsArr || isTypedArray2(object) ? equalArrays2(object, other, bitmask, customizer, equalFunc, stack) : equalByTag2(object, other, objTag, bitmask, customizer, equalFunc, stack);
             }
-            if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
-              var objIsWrapped = objIsObj && hasOwnProperty2.call(object, "__wrapped__"), othIsWrapped = othIsObj && hasOwnProperty2.call(other, "__wrapped__");
+            if (!(bitmask & COMPARE_PARTIAL_FLAG5)) {
+              var objIsWrapped = objIsObj && hasOwnProperty10.call(object, "__wrapped__"), othIsWrapped = othIsObj && hasOwnProperty10.call(other, "__wrapped__");
               if (objIsWrapped || othIsWrapped) {
                 var objUnwrapped = objIsWrapped ? object.value() : object, othUnwrapped = othIsWrapped ? other.value() : other;
-                stack || (stack = new Stack());
+                stack || (stack = new Stack2());
                 return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
               }
             }
             if (!isSameTag) {
               return false;
             }
-            stack || (stack = new Stack());
-            return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
+            stack || (stack = new Stack2());
+            return equalObjects2(object, other, bitmask, customizer, equalFunc, stack);
           }
           function baseIsMap(value) {
-            return isObjectLike2(value) && getTag(value) == mapTag;
+            return isObjectLike2(value) && getTag2(value) == mapTag4;
           }
           function baseIsMatch(object, source, matchData, customizer) {
             var index = matchData.length, length = index, noCustomizer = !customizer;
                   return false;
                 }
               } else {
-                var stack = new Stack();
+                var stack = new Stack2();
                 if (customizer) {
                   var result2 = customizer(objValue, srcValue, key, object, source, stack);
                 }
-                if (!(result2 === undefined2 ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) : result2)) {
+                if (!(result2 === undefined2 ? baseIsEqual2(srcValue, objValue, COMPARE_PARTIAL_FLAG5 | COMPARE_UNORDERED_FLAG3, customizer, stack) : result2)) {
                   return false;
                 }
               }
             }
             return true;
           }
-          function baseIsNative(value) {
-            if (!isObject2(value) || isMasked(value)) {
+          function baseIsNative2(value) {
+            if (!isObject3(value) || isMasked2(value)) {
               return false;
             }
-            var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
-            return pattern.test(toSource(value));
+            var pattern = isFunction2(value) ? reIsNative2 : reIsHostCtor2;
+            return pattern.test(toSource2(value));
           }
           function baseIsRegExp(value) {
-            return isObjectLike2(value) && baseGetTag2(value) == regexpTag;
+            return isObjectLike2(value) && baseGetTag2(value) == regexpTag3;
           }
           function baseIsSet(value) {
-            return isObjectLike2(value) && getTag(value) == setTag;
+            return isObjectLike2(value) && getTag2(value) == setTag4;
           }
-          function baseIsTypedArray(value) {
-            return isObjectLike2(value) && isLength(value.length) && !!typedArrayTags[baseGetTag2(value)];
+          function baseIsTypedArray2(value) {
+            return isObjectLike2(value) && isLength2(value.length) && !!typedArrayTags2[baseGetTag2(value)];
           }
           function baseIteratee(value) {
             if (typeof value == "function") {
             }
             return property(value);
           }
-          function baseKeys(object) {
-            if (!isPrototype(object)) {
-              return nativeKeys(object);
+          function baseKeys2(object) {
+            if (!isPrototype2(object)) {
+              return nativeKeys2(object);
             }
             var result2 = [];
             for (var key in Object2(object)) {
-              if (hasOwnProperty2.call(object, key) && key != "constructor") {
+              if (hasOwnProperty10.call(object, key) && key != "constructor") {
                 result2.push(key);
               }
             }
             return result2;
           }
           function baseKeysIn(object) {
-            if (!isObject2(object)) {
+            if (!isObject3(object)) {
               return nativeKeysIn(object);
             }
-            var isProto = isPrototype(object), result2 = [];
+            var isProto = isPrototype2(object), result2 = [];
             for (var key in object) {
-              if (!(key == "constructor" && (isProto || !hasOwnProperty2.call(object, key)))) {
+              if (!(key == "constructor" && (isProto || !hasOwnProperty10.call(object, key)))) {
                 result2.push(key);
               }
             }
             return value < other;
           }
           function baseMap(collection, iteratee2) {
-            var index = -1, result2 = isArrayLike(collection) ? Array2(collection.length) : [];
+            var index = -1, result2 = isArrayLike2(collection) ? Array2(collection.length) : [];
             baseEach(collection, function(value, key, collection2) {
               result2[++index] = iteratee2(value, key, collection2);
             });
             }
             return function(object) {
               var objValue = get4(object, path);
-              return objValue === undefined2 && objValue === srcValue ? hasIn(object, path) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
+              return objValue === undefined2 && objValue === srcValue ? hasIn(object, path) : baseIsEqual2(srcValue, objValue, COMPARE_PARTIAL_FLAG5 | COMPARE_UNORDERED_FLAG3);
             };
           }
           function baseMerge(object, source, srcIndex, customizer, stack) {
               return;
             }
             baseFor(source, function(srcValue, key) {
-              stack || (stack = new Stack());
-              if (isObject2(srcValue)) {
+              stack || (stack = new Stack2());
+              if (isObject3(srcValue)) {
                 baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
               } else {
                 var newValue = customizer ? customizer(safeGet(object, key), srcValue, key + "", object, source, stack) : undefined2;
             var newValue = customizer ? customizer(objValue, srcValue, key + "", object, source, stack) : undefined2;
             var isCommon = newValue === undefined2;
             if (isCommon) {
-              var isArr = isArray2(srcValue), isBuff = !isArr && isBuffer(srcValue), isTyped = !isArr && !isBuff && isTypedArray(srcValue);
+              var isArr = isArray2(srcValue), isBuff = !isArr && isBuffer2(srcValue), isTyped = !isArr && !isBuff && isTypedArray2(srcValue);
               newValue = srcValue;
               if (isArr || isBuff || isTyped) {
                 if (isArray2(objValue)) {
                 } else {
                   newValue = [];
                 }
-              } else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+              } else if (isPlainObject(srcValue) || isArguments2(srcValue)) {
                 newValue = objValue;
-                if (isArguments(objValue)) {
+                if (isArguments2(objValue)) {
                   newValue = toPlainObject(objValue);
-                } else if (!isObject2(objValue) || isFunction(objValue)) {
+                } else if (!isObject3(objValue) || isFunction2(objValue)) {
                   newValue = initCloneObject(srcValue);
                 }
               } else {
               return;
             }
             n2 += n2 < 0 ? length : 0;
-            return isIndex(n2, length) ? array2[n2] : undefined2;
+            return isIndex2(n2, length) ? array2[n2] : undefined2;
           }
           function baseOrderBy(collection, iteratees, orders) {
             if (iteratees.length) {
               iteratees = [identity4];
             }
             var index = -1;
-            iteratees = arrayMap2(iteratees, baseUnary(getIteratee()));
+            iteratees = arrayMap2(iteratees, baseUnary2(getIteratee()));
             var result2 = baseMap(collection, function(value, key, collection2) {
               var criteria = arrayMap2(iteratees, function(iteratee2) {
                 return iteratee2(value);
               values2 = copyArray(values2);
             }
             if (iteratee2) {
-              seen = arrayMap2(array2, baseUnary(iteratee2));
+              seen = arrayMap2(array2, baseUnary2(iteratee2));
             }
             while (++index < length) {
               var fromIndex = 0, value = values2[index], computed = iteratee2 ? iteratee2(value) : value;
               while ((fromIndex = indexOf2(seen, computed, fromIndex, comparator)) > -1) {
                 if (seen !== array2) {
-                  splice.call(seen, fromIndex, 1);
+                  splice2.call(seen, fromIndex, 1);
                 }
-                splice.call(array2, fromIndex, 1);
+                splice2.call(array2, fromIndex, 1);
               }
             }
             return array2;
               var index = indexes[length];
               if (length == lastIndex || index !== previous) {
                 var previous = index;
-                if (isIndex(index)) {
-                  splice.call(array2, index, 1);
+                if (isIndex2(index)) {
+                  splice2.call(array2, index, 1);
                 } else {
                   baseUnset(array2, index);
                 }
           }
           function baseRepeat(string, n2) {
             var result2 = "";
-            if (!string || n2 < 1 || n2 > MAX_SAFE_INTEGER) {
+            if (!string || n2 < 1 || n2 > MAX_SAFE_INTEGER3) {
               return result2;
             }
             do {
             return shuffleSelf(array2, baseClamp(n2, 0, array2.length));
           }
           function baseSet(object, path, value, customizer) {
-            if (!isObject2(object)) {
+            if (!isObject3(object)) {
               return object;
             }
             path = castPath(path, object);
                 var objValue = nested[key];
                 newValue = customizer ? customizer(objValue, key, nested) : undefined2;
                 if (newValue === undefined2) {
-                  newValue = isObject2(objValue) ? objValue : isIndex(path[index + 1]) ? [] : {};
+                  newValue = isObject3(objValue) ? objValue : isIndex2(path[index + 1]) ? [] : {};
                 }
               }
               assignValue(nested, key, newValue);
             var index = -1, length = array2.length, resIndex = 0, result2 = [];
             while (++index < length) {
               var value = array2[index], computed = iteratee2 ? iteratee2(value) : value;
-              if (!index || !eq(computed, seen)) {
+              if (!index || !eq2(computed, seen)) {
                 var seen = computed;
                 result2[resIndex++] = value === 0 ? 0 : value;
               }
             if (comparator) {
               isCommon = false;
               includes2 = arrayIncludesWith;
-            } else if (length >= LARGE_ARRAY_SIZE) {
+            } else if (length >= LARGE_ARRAY_SIZE2) {
               var set4 = iteratee2 ? null : createSet(array2);
               if (set4) {
-                return setToArray(set4);
+                return setToArray2(set4);
               }
               isCommon = false;
-              includes2 = cacheHas;
-              seen = new SetCache();
+              includes2 = cacheHas2;
+              seen = new SetCache2();
             } else {
               seen = iteratee2 ? [] : result2;
             }
               result2 = result2.value();
             }
             return arrayReduce(actions, function(result3, action) {
-              return action.func.apply(action.thisArg, arrayPush([result3], action.args));
+              return action.func.apply(action.thisArg, arrayPush2([result3], action.args));
             }, result2);
           }
           function baseXor(arrays, iteratee2, comparator) {
           }
           function cloneArrayBuffer(arrayBuffer) {
             var result2 = new arrayBuffer.constructor(arrayBuffer.byteLength);
-            new Uint8Array2(result2).set(new Uint8Array2(arrayBuffer));
+            new Uint8Array3(result2).set(new Uint8Array3(arrayBuffer));
             return result2;
           }
           function cloneDataView(dataView, isDeep) {
             return result2;
           }
           function cloneSymbol(symbol) {
-            return symbolValueOf ? Object2(symbolValueOf.call(symbol)) : {};
+            return symbolValueOf2 ? Object2(symbolValueOf2.call(symbol)) : {};
           }
           function cloneTypedArray(typedArray, isDeep) {
             var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
             return object;
           }
           function copySymbols(source, object) {
-            return copyObject(source, getSymbols(source), object);
+            return copyObject(source, getSymbols2(source), object);
           }
           function copySymbolsIn(source, object) {
             return copyObject(source, getSymbolsIn(source), object);
               if (collection == null) {
                 return collection;
               }
-              if (!isArrayLike(collection)) {
+              if (!isArrayLike2(collection)) {
                 return eachFunc(collection, iteratee2);
               }
               var length = collection.length, index = fromRight ? length : -1, iterable = Object2(collection);
                   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 isObject2(result2) ? result2 : thisBinding;
+              return isObject3(result2) ? result2 : thisBinding;
             };
           }
           function createCurry(func, bitmask, arity) {
           function createFind(findIndexFunc) {
             return function(collection, predicate, fromIndex) {
               var iterable = Object2(collection);
-              if (!isArrayLike(collection)) {
+              if (!isArrayLike2(collection)) {
                 var iteratee2 = getIteratee(predicate, 3);
-                collection = keys(collection);
+                collection = keys2(collection);
                 predicate = function(key) {
                   return iteratee2(iterable[key], key, iterable);
                 };
           }
           function createOver(arrayFunc) {
             return flatRest(function(iteratees) {
-              iteratees = arrayMap2(iteratees, baseUnary(getIteratee()));
+              iteratees = arrayMap2(iteratees, baseUnary2(getIteratee()));
               return baseRest(function(args) {
                 var thisArg = this;
                 return arrayFunc(iteratees, function(iteratee2) {
           function createRelationalOperation(operator) {
             return function(value, other) {
               if (!(typeof value == "string" && typeof other == "string")) {
-                value = toNumber2(value);
-                other = toNumber2(other);
+                value = toNumber3(value);
+                other = toNumber3(other);
               }
               return operator(value, other);
             };
           function createRound(methodName) {
             var func = Math2[methodName];
             return function(number3, precision2) {
-              number3 = toNumber2(number3);
+              number3 = toNumber3(number3);
               precision2 = precision2 == null ? 0 : nativeMin2(toInteger(precision2), 292);
               if (precision2 && nativeIsFinite(number3)) {
                 var pair2 = (toString2(number3) + "e").split("e"), value = func(pair2[0] + "e" + (+pair2[1] + precision2));
               return func(number3);
             };
           }
-          var createSet = !(Set2 && 1 / setToArray(new Set2([, -0]))[1] == INFINITY2) ? noop3 : function(values2) {
-            return new Set2(values2);
+          var createSet = !(Set3 && 1 / setToArray2(new Set3([, -0]))[1] == INFINITY2) ? noop3 : function(values2) {
+            return new Set3(values2);
           };
           function createToPairs(keysFunc) {
             return function(object) {
-              var tag = getTag(object);
-              if (tag == mapTag) {
-                return mapToArray(object);
+              var tag = getTag2(object);
+              if (tag == mapTag4) {
+                return mapToArray2(object);
               }
-              if (tag == setTag) {
+              if (tag == setTag4) {
                 return setToPairs(object);
               }
               return baseToPairs(object, keysFunc(object));
             return setWrapToString(setter(result2, newData), func, bitmask);
           }
           function customDefaultsAssignIn(objValue, srcValue, key, object) {
-            if (objValue === undefined2 || eq(objValue, objectProto3[key]) && !hasOwnProperty2.call(object, key)) {
+            if (objValue === undefined2 || eq2(objValue, objectProto13[key]) && !hasOwnProperty10.call(object, key)) {
               return srcValue;
             }
             return objValue;
           }
           function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
-            if (isObject2(objValue) && isObject2(srcValue)) {
+            if (isObject3(objValue) && isObject3(srcValue)) {
               stack.set(srcValue, objValue);
               baseMerge(objValue, srcValue, undefined2, customDefaultsMerge, stack);
               stack["delete"](srcValue);
           function customOmitClone(value) {
             return isPlainObject(value) ? undefined2 : value;
           }
-          function equalArrays(array2, other, bitmask, customizer, equalFunc, stack) {
-            var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array2.length, othLength = other.length;
+          function equalArrays2(array2, other, bitmask, customizer, equalFunc, stack) {
+            var isPartial = bitmask & COMPARE_PARTIAL_FLAG5, arrLength = array2.length, othLength = other.length;
             if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
               return false;
             }
             if (arrStacked && othStacked) {
               return arrStacked == other && othStacked == array2;
             }
-            var index = -1, result2 = true, seen = bitmask & COMPARE_UNORDERED_FLAG ? new SetCache() : undefined2;
+            var index = -1, result2 = true, seen = bitmask & COMPARE_UNORDERED_FLAG3 ? new SetCache2() : undefined2;
             stack.set(array2, other);
             stack.set(other, array2);
             while (++index < arrLength) {
                 break;
               }
               if (seen) {
-                if (!arraySome(other, function(othValue2, othIndex) {
-                  if (!cacheHas(seen, othIndex) && (arrValue === othValue2 || equalFunc(arrValue, othValue2, bitmask, customizer, stack))) {
+                if (!arraySome2(other, function(othValue2, othIndex) {
+                  if (!cacheHas2(seen, othIndex) && (arrValue === othValue2 || equalFunc(arrValue, othValue2, bitmask, customizer, stack))) {
                     return seen.push(othIndex);
                   }
                 })) {
             stack["delete"](other);
             return result2;
           }
-          function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
+          function equalByTag2(object, other, tag, bitmask, customizer, equalFunc, stack) {
             switch (tag) {
-              case dataViewTag:
+              case dataViewTag4:
                 if (object.byteLength != other.byteLength || object.byteOffset != other.byteOffset) {
                   return false;
                 }
                 object = object.buffer;
                 other = other.buffer;
-              case arrayBufferTag:
-                if (object.byteLength != other.byteLength || !equalFunc(new Uint8Array2(object), new Uint8Array2(other))) {
+              case arrayBufferTag3:
+                if (object.byteLength != other.byteLength || !equalFunc(new Uint8Array3(object), new Uint8Array3(other))) {
                   return false;
                 }
                 return true;
-              case boolTag:
-              case dateTag:
-              case numberTag:
-                return eq(+object, +other);
-              case errorTag:
+              case boolTag3:
+              case dateTag3:
+              case numberTag3:
+                return eq2(+object, +other);
+              case errorTag3:
                 return object.name == other.name && object.message == other.message;
-              case regexpTag:
-              case stringTag:
+              case regexpTag3:
+              case stringTag3:
                 return object == other + "";
-              case mapTag:
-                var convert = mapToArray;
-              case setTag:
-                var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
-                convert || (convert = setToArray);
+              case mapTag4:
+                var convert = mapToArray2;
+              case setTag4:
+                var isPartial = bitmask & COMPARE_PARTIAL_FLAG5;
+                convert || (convert = setToArray2);
                 if (object.size != other.size && !isPartial) {
                   return false;
                 }
                 if (stacked) {
                   return stacked == other;
                 }
-                bitmask |= COMPARE_UNORDERED_FLAG;
+                bitmask |= COMPARE_UNORDERED_FLAG3;
                 stack.set(object, other);
-                var result2 = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
+                var result2 = equalArrays2(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
                 stack["delete"](object);
                 return result2;
-              case symbolTag2:
-                if (symbolValueOf) {
-                  return symbolValueOf.call(object) == symbolValueOf.call(other);
+              case symbolTag3:
+                if (symbolValueOf2) {
+                  return symbolValueOf2.call(object) == symbolValueOf2.call(other);
                 }
             }
             return false;
           }
-          function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
-            var isPartial = bitmask & COMPARE_PARTIAL_FLAG, objProps = getAllKeys(object), objLength = objProps.length, othProps = getAllKeys(other), othLength = othProps.length;
+          function equalObjects2(object, other, bitmask, customizer, equalFunc, stack) {
+            var isPartial = bitmask & COMPARE_PARTIAL_FLAG5, objProps = getAllKeys2(object), objLength = objProps.length, othProps = getAllKeys2(other), othLength = othProps.length;
             if (objLength != othLength && !isPartial) {
               return false;
             }
             var index = objLength;
             while (index--) {
               var key = objProps[index];
-              if (!(isPartial ? key in other : hasOwnProperty2.call(other, key))) {
+              if (!(isPartial ? key in other : hasOwnProperty10.call(other, key))) {
                 return false;
               }
             }
           function flatRest(func) {
             return setToString(overRest(func, undefined2, flatten2), func + "");
           }
-          function getAllKeys(object) {
-            return baseGetAllKeys(object, keys, getSymbols);
+          function getAllKeys2(object) {
+            return baseGetAllKeys2(object, keys2, getSymbols2);
           }
           function getAllKeysIn(object) {
-            return baseGetAllKeys(object, keysIn, getSymbolsIn);
+            return baseGetAllKeys2(object, keysIn, getSymbolsIn);
           }
           var getData = !metaMap ? noop3 : function(func) {
             return metaMap.get(func);
           };
           function getFuncName(func) {
-            var result2 = func.name + "", array2 = realNames[result2], length = hasOwnProperty2.call(realNames, result2) ? array2.length : 0;
+            var result2 = func.name + "", array2 = realNames[result2], length = hasOwnProperty10.call(realNames, result2) ? array2.length : 0;
             while (length--) {
               var data = array2[length], otherFunc = data.func;
               if (otherFunc == null || otherFunc == func) {
             return result2;
           }
           function getHolder(func) {
-            var object = hasOwnProperty2.call(lodash, "placeholder") ? lodash : func;
+            var object = hasOwnProperty10.call(lodash, "placeholder") ? lodash : func;
             return object.placeholder;
           }
           function getIteratee() {
             result2 = result2 === iteratee ? baseIteratee : result2;
             return arguments.length ? result2(arguments[0], arguments[1]) : result2;
           }
-          function getMapData(map3, key) {
+          function getMapData2(map3, key) {
             var data = map3.__data__;
-            return isKeyable(key) ? data[typeof key == "string" ? "string" : "hash"] : data.map;
+            return isKeyable2(key) ? data[typeof key == "string" ? "string" : "hash"] : data.map;
           }
           function getMatchData(object) {
-            var result2 = keys(object), length = result2.length;
+            var result2 = keys2(object), length = result2.length;
             while (length--) {
               var key = result2[length], value = object[key];
               result2[length] = [key, value, isStrictComparable(value)];
             }
             return result2;
           }
-          function getNative(object, key) {
-            var value = getValue(object, key);
-            return baseIsNative(value) ? value : undefined2;
+          function getNative2(object, key) {
+            var value = getValue2(object, key);
+            return baseIsNative2(value) ? value : undefined2;
           }
           function getRawTag2(value) {
-            var isOwn = hasOwnProperty2.call(value, symToStringTag3), tag = value[symToStringTag3];
+            var isOwn = hasOwnProperty10.call(value, symToStringTag3), tag = value[symToStringTag3];
             try {
               value[symToStringTag3] = undefined2;
               var unmasked = true;
             }
             return result2;
           }
-          var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
+          var getSymbols2 = !nativeGetSymbols2 ? stubArray2 : function(object) {
             if (object == null) {
               return [];
             }
             object = Object2(object);
-            return arrayFilter(nativeGetSymbols(object), function(symbol) {
-              return propertyIsEnumerable.call(object, symbol);
+            return arrayFilter2(nativeGetSymbols2(object), function(symbol) {
+              return propertyIsEnumerable3.call(object, symbol);
             });
           };
-          var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
+          var getSymbolsIn = !nativeGetSymbols2 ? stubArray2 : function(object) {
             var result2 = [];
             while (object) {
-              arrayPush(result2, getSymbols(object));
+              arrayPush2(result2, getSymbols2(object));
               object = getPrototype(object);
             }
             return result2;
           };
-          var getTag = baseGetTag2;
-          if (DataView2 && getTag(new DataView2(new ArrayBuffer(1))) != dataViewTag || Map2 && getTag(new Map2()) != mapTag || Promise2 && getTag(Promise2.resolve()) != promiseTag || Set2 && getTag(new Set2()) != setTag || WeakMap && getTag(new WeakMap()) != weakMapTag) {
-            getTag = function(value) {
-              var result2 = baseGetTag2(value), Ctor = result2 == objectTag ? value.constructor : undefined2, ctorString = Ctor ? toSource(Ctor) : "";
+          var getTag2 = baseGetTag2;
+          if (DataView3 && getTag2(new DataView3(new ArrayBuffer(1))) != dataViewTag4 || Map3 && getTag2(new Map3()) != mapTag4 || Promise3 && getTag2(Promise3.resolve()) != promiseTag2 || Set3 && getTag2(new Set3()) != setTag4 || WeakMap2 && getTag2(new WeakMap2()) != weakMapTag3) {
+            getTag2 = function(value) {
+              var result2 = baseGetTag2(value), Ctor = result2 == objectTag4 ? value.constructor : undefined2, ctorString = Ctor ? toSource2(Ctor) : "";
               if (ctorString) {
                 switch (ctorString) {
-                  case dataViewCtorString:
-                    return dataViewTag;
-                  case mapCtorString:
-                    return mapTag;
-                  case promiseCtorString:
-                    return promiseTag;
-                  case setCtorString:
-                    return setTag;
-                  case weakMapCtorString:
-                    return weakMapTag;
+                  case dataViewCtorString2:
+                    return dataViewTag4;
+                  case mapCtorString2:
+                    return mapTag4;
+                  case promiseCtorString2:
+                    return promiseTag2;
+                  case setCtorString2:
+                    return setTag4;
+                  case weakMapCtorString2:
+                    return weakMapTag3;
                 }
               }
               return result2;
               return result2;
             }
             length = object == null ? 0 : object.length;
-            return !!length && isLength(length) && isIndex(key, length) && (isArray2(object) || isArguments(object));
+            return !!length && isLength2(length) && isIndex2(key, length) && (isArray2(object) || isArguments2(object));
           }
           function initCloneArray(array2) {
             var length = array2.length, result2 = new array2.constructor(length);
-            if (length && typeof array2[0] == "string" && hasOwnProperty2.call(array2, "index")) {
+            if (length && typeof array2[0] == "string" && hasOwnProperty10.call(array2, "index")) {
               result2.index = array2.index;
               result2.input = array2.input;
             }
             return result2;
           }
           function initCloneObject(object) {
-            return typeof object.constructor == "function" && !isPrototype(object) ? baseCreate(getPrototype(object)) : {};
+            return typeof object.constructor == "function" && !isPrototype2(object) ? baseCreate(getPrototype(object)) : {};
           }
           function initCloneByTag(object, tag, isDeep) {
             var Ctor = object.constructor;
             switch (tag) {
-              case arrayBufferTag:
+              case arrayBufferTag3:
                 return cloneArrayBuffer(object);
-              case boolTag:
-              case dateTag:
+              case boolTag3:
+              case dateTag3:
                 return new Ctor(+object);
-              case dataViewTag:
+              case dataViewTag4:
                 return cloneDataView(object, isDeep);
-              case float32Tag:
-              case float64Tag:
-              case int8Tag:
-              case int16Tag:
-              case int32Tag:
-              case uint8Tag:
-              case uint8ClampedTag:
-              case uint16Tag:
-              case uint32Tag:
+              case float32Tag2:
+              case float64Tag2:
+              case int8Tag2:
+              case int16Tag2:
+              case int32Tag2:
+              case uint8Tag2:
+              case uint8ClampedTag2:
+              case uint16Tag2:
+              case uint32Tag2:
                 return cloneTypedArray(object, isDeep);
-              case mapTag:
+              case mapTag4:
                 return new Ctor();
-              case numberTag:
-              case stringTag:
+              case numberTag3:
+              case stringTag3:
                 return new Ctor(object);
-              case regexpTag:
+              case regexpTag3:
                 return cloneRegExp(object);
-              case setTag:
+              case setTag4:
                 return new Ctor();
-              case symbolTag2:
+              case symbolTag3:
                 return cloneSymbol(object);
             }
           }
             return source.replace(reWrapComment, "{\n/* [wrapped with " + details + "] */\n");
           }
           function isFlattenable(value) {
-            return isArray2(value) || isArguments(value) || !!(spreadableSymbol && value && value[spreadableSymbol]);
+            return isArray2(value) || isArguments2(value) || !!(spreadableSymbol && value && value[spreadableSymbol]);
           }
-          function isIndex(value, length) {
-            var type3 = typeof value;
-            length = length == null ? MAX_SAFE_INTEGER : length;
-            return !!length && (type3 == "number" || type3 != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length);
+          function isIndex2(value, length) {
+            var type2 = typeof value;
+            length = length == null ? MAX_SAFE_INTEGER3 : length;
+            return !!length && (type2 == "number" || type2 != "symbol" && reIsUint2.test(value)) && (value > -1 && value % 1 == 0 && value < length);
           }
           function isIterateeCall(value, index, object) {
-            if (!isObject2(object)) {
+            if (!isObject3(object)) {
               return false;
             }
-            var type3 = typeof index;
-            if (type3 == "number" ? isArrayLike(object) && isIndex(index, object.length) : type3 == "string" && index in object) {
-              return eq(object[index], value);
+            var type2 = typeof index;
+            if (type2 == "number" ? isArrayLike2(object) && isIndex2(index, object.length) : type2 == "string" && index in object) {
+              return eq2(object[index], value);
             }
             return false;
           }
             if (isArray2(value)) {
               return false;
             }
-            var type3 = typeof value;
-            if (type3 == "number" || type3 == "symbol" || type3 == "boolean" || value == null || isSymbol2(value)) {
+            var type2 = typeof value;
+            if (type2 == "number" || type2 == "symbol" || type2 == "boolean" || value == null || isSymbol2(value)) {
               return true;
             }
             return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || object != null && value in Object2(object);
           }
-          function isKeyable(value) {
-            var type3 = typeof value;
-            return type3 == "string" || type3 == "number" || type3 == "symbol" || type3 == "boolean" ? value !== "__proto__" : value === null;
+          function isKeyable2(value) {
+            var type2 = typeof value;
+            return type2 == "string" || type2 == "number" || type2 == "symbol" || type2 == "boolean" ? value !== "__proto__" : value === null;
           }
           function isLaziable(func) {
             var funcName = getFuncName(func), other = lodash[funcName];
             var data = getData(other);
             return !!data && func === data[0];
           }
-          function isMasked(func) {
-            return !!maskSrcKey && maskSrcKey in func;
+          function isMasked2(func) {
+            return !!maskSrcKey2 && maskSrcKey2 in func;
           }
-          var isMaskable = coreJsData ? isFunction : stubFalse;
-          function isPrototype(value) {
-            var Ctor = value && value.constructor, proto = typeof Ctor == "function" && Ctor.prototype || objectProto3;
+          var isMaskable = coreJsData2 ? isFunction2 : stubFalse2;
+          function isPrototype2(value) {
+            var Ctor = value && value.constructor, proto = typeof Ctor == "function" && Ctor.prototype || objectProto13;
             return value === proto;
           }
           function isStrictComparable(value) {
-            return value === value && !isObject2(value);
+            return value === value && !isObject3(value);
           }
           function matchesStrictComparable(key, srcValue) {
             return function(object) {
             var arrLength = array2.length, length = nativeMin2(indexes.length, arrLength), oldArray = copyArray(array2);
             while (length--) {
               var index = indexes[length];
-              array2[length] = isIndex(index, arrLength) ? oldArray[index] : undefined2;
+              array2[length] = isIndex2(index, arrLength) ? oldArray[index] : undefined2;
             }
             return array2;
           }
             var result2 = value + "";
             return result2 == "0" && 1 / value == -INFINITY2 ? "-0" : result2;
           }
-          function toSource(func) {
+          function toSource2(func) {
             if (func != null) {
               try {
-                return funcToString.call(func);
+                return funcToString3.call(func);
               } catch (e) {
               }
               try {
             while (index--) {
               args[index - 1] = arguments[index];
             }
-            return arrayPush(isArray2(array2) ? copyArray(array2) : [array2], baseFlatten(args, 1));
+            return arrayPush2(isArray2(array2) ? copyArray(array2) : [array2], baseFlatten(args, 1));
           }
           var difference = baseRest(function(array2, values2) {
             return isArrayLikeObject(array2) ? baseDifference(array2, baseFlatten(values2, 1, isArrayLikeObject, true)) : [];
           var pullAt = flatRest(function(array2, indexes) {
             var length = array2 == null ? 0 : array2.length, result2 = baseAt(array2, indexes);
             basePullAt(array2, arrayMap2(indexes, function(index) {
-              return isIndex(index, length) ? +index : index;
+              return isIndex2(index, length) ? +index : index;
             }).sort(compareAscending));
             return result2;
           });
             var length = array2 == null ? 0 : array2.length;
             if (length) {
               var index = baseSortedIndex(array2, value);
-              if (index < length && eq(array2[index], value)) {
+              if (index < length && eq2(array2[index], value)) {
                 return index;
               }
             }
             var length = array2 == null ? 0 : array2.length;
             if (length) {
               var index = baseSortedIndex(array2, value, true) - 1;
-              if (eq(array2[index], value)) {
+              if (eq2(array2[index], value)) {
                 return index;
               }
             }
               return [];
             }
             var length = 0;
-            array2 = arrayFilter(array2, function(group) {
+            array2 = arrayFilter2(array2, function(group) {
               if (isArrayLikeObject(group)) {
                 length = nativeMax2(group.length, length);
                 return true;
               }
             });
-            return baseTimes(length, function(index) {
+            return baseTimes2(length, function(index) {
               return arrayMap2(array2, baseProperty(index));
             });
           }
             return isArrayLikeObject(array2) ? baseDifference(array2, values2) : [];
           });
           var xor = baseRest(function(arrays) {
-            return baseXor(arrayFilter(arrays, isArrayLikeObject));
+            return baseXor(arrayFilter2(arrays, isArrayLikeObject));
           });
           var xorBy = baseRest(function(arrays) {
             var iteratee2 = last(arrays);
             if (isArrayLikeObject(iteratee2)) {
               iteratee2 = undefined2;
             }
-            return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee2, 2));
+            return baseXor(arrayFilter2(arrays, isArrayLikeObject), getIteratee(iteratee2, 2));
           });
           var xorWith = baseRest(function(arrays) {
             var comparator = last(arrays);
             comparator = typeof comparator == "function" ? comparator : undefined2;
-            return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined2, comparator);
+            return baseXor(arrayFilter2(arrays, isArrayLikeObject), undefined2, comparator);
           });
           var zip = baseRest(unzip);
           function zipObject(props, values2) {
             var length = paths.length, start2 = length ? paths[0] : 0, value = this.__wrapped__, interceptor = function(object) {
               return baseAt(object, paths);
             };
-            if (length > 1 || this.__actions__.length || !(value instanceof LazyWrapper) || !isIndex(start2)) {
+            if (length > 1 || this.__actions__.length || !(value instanceof LazyWrapper) || !isIndex2(start2)) {
               return this.thru(interceptor);
             }
             value = value.slice(start2, +start2 + (length ? 1 : 0));
             return baseWrapperValue(this.__wrapped__, this.__actions__);
           }
           var countBy = createAggregator(function(result2, value, key) {
-            if (hasOwnProperty2.call(result2, key)) {
+            if (hasOwnProperty10.call(result2, key)) {
               ++result2[key];
             } else {
               baseAssignValue(result2, key, 1);
             return func(collection, getIteratee(predicate, 3));
           }
           function filter2(collection, predicate) {
-            var func = isArray2(collection) ? arrayFilter : baseFilter;
+            var func = isArray2(collection) ? arrayFilter2 : baseFilter;
             return func(collection, getIteratee(predicate, 3));
           }
           var find2 = createFind(findIndex);
             return func(collection, getIteratee(iteratee2, 3));
           }
           var groupBy = createAggregator(function(result2, value, key) {
-            if (hasOwnProperty2.call(result2, key)) {
+            if (hasOwnProperty10.call(result2, key)) {
               result2[key].push(value);
             } else {
               baseAssignValue(result2, key, [value]);
             }
           });
           function includes(collection, value, fromIndex, guard) {
-            collection = isArrayLike(collection) ? collection : values(collection);
+            collection = isArrayLike2(collection) ? collection : values(collection);
             fromIndex = fromIndex && !guard ? toInteger(fromIndex) : 0;
             var length = collection.length;
             if (fromIndex < 0) {
             return isString(collection) ? fromIndex <= length && collection.indexOf(value, fromIndex) > -1 : !!length && baseIndexOf(collection, value, fromIndex) > -1;
           }
           var invokeMap = baseRest(function(collection, path, args) {
-            var index = -1, isFunc = typeof path == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
+            var index = -1, isFunc = typeof path == "function", result2 = isArrayLike2(collection) ? Array2(collection.length) : [];
             baseEach(collection, function(value) {
               result2[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
             });
             return func(collection, getIteratee(iteratee2, 4), accumulator, initAccum, baseEachRight);
           }
           function reject(collection, predicate) {
-            var func = isArray2(collection) ? arrayFilter : baseFilter;
+            var func = isArray2(collection) ? arrayFilter2 : baseFilter;
             return func(collection, negate(getIteratee(predicate, 3)));
           }
           function sample(collection) {
             if (collection == null) {
               return 0;
             }
-            if (isArrayLike(collection)) {
+            if (isArrayLike2(collection)) {
               return isString(collection) ? stringSize(collection) : collection.length;
             }
-            var tag = getTag(collection);
-            if (tag == mapTag || tag == setTag) {
+            var tag = getTag2(collection);
+            if (tag == mapTag4 || tag == setTag4) {
               return collection.size;
             }
-            return baseKeys(collection).length;
+            return baseKeys2(collection).length;
           }
           function some(collection, predicate, guard) {
-            var func = isArray2(collection) ? arraySome : baseSome;
+            var func = isArray2(collection) ? arraySome2 : baseSome;
             if (guard && isIterateeCall(collection, predicate, guard)) {
               predicate = undefined2;
             }
             if (typeof func != "function") {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             }
-            wait = toNumber2(wait) || 0;
-            if (isObject2(options2)) {
+            wait = toNumber3(wait) || 0;
+            if (isObject3(options2)) {
               leading = !!options2.leading;
               maxing = "maxWait" in options2;
-              maxWait = maxing ? nativeMax2(toNumber2(options2.maxWait) || 0, wait) : maxWait;
+              maxWait = maxing ? nativeMax2(toNumber3(options2.maxWait) || 0, wait) : maxWait;
               trailing = "trailing" in options2 ? !!options2.trailing : trailing;
             }
             function invokeFunc(time) {
             return baseDelay(func, 1, args);
           });
           var delay = baseRest(function(func, wait, args) {
-            return baseDelay(func, toNumber2(wait) || 0, args);
+            return baseDelay(func, toNumber3(wait) || 0, args);
           });
           function flip(func) {
             return createWrap(func, WRAP_FLIP_FLAG);
               memoized.cache = cache.set(key, result2) || cache;
               return result2;
             };
-            memoized.cache = new (memoize.Cache || MapCache)();
+            memoized.cache = new (memoize.Cache || MapCache2)();
             return memoized;
           }
-          memoize.Cache = MapCache;
+          memoize.Cache = MapCache2;
           function negate(predicate) {
             if (typeof predicate != "function") {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             return before(2, func);
           }
           var overArgs = castRest(function(func, transforms) {
-            transforms = transforms.length == 1 && isArray2(transforms[0]) ? arrayMap2(transforms[0], baseUnary(getIteratee())) : arrayMap2(baseFlatten(transforms, 1), baseUnary(getIteratee()));
+            transforms = transforms.length == 1 && isArray2(transforms[0]) ? arrayMap2(transforms[0], baseUnary2(getIteratee())) : arrayMap2(baseFlatten(transforms, 1), baseUnary2(getIteratee()));
             var funcsLength = transforms.length;
             return baseRest(function(args) {
               var index = -1, length = nativeMin2(args.length, funcsLength);
             return baseRest(function(args) {
               var array2 = args[start2], otherArgs = castSlice(args, 0, start2);
               if (array2) {
-                arrayPush(otherArgs, array2);
+                arrayPush2(otherArgs, array2);
               }
               return apply(func, this, otherArgs);
             });
             if (typeof func != "function") {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             }
-            if (isObject2(options2)) {
+            if (isObject3(options2)) {
               leading = "leading" in options2 ? !!options2.leading : leading;
               trailing = "trailing" in options2 ? !!options2.trailing : trailing;
             }
             return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
           }
           function conformsTo(object, source) {
-            return source == null || baseConformsTo(object, source, keys(source));
+            return source == null || baseConformsTo(object, source, keys2(source));
           }
-          function eq(value, other) {
+          function eq2(value, other) {
             return value === other || value !== value && other !== other;
           }
           var gt = createRelationalOperation(baseGt);
           var gte = createRelationalOperation(function(value, other) {
             return value >= other;
           });
-          var isArguments = baseIsArguments(function() {
+          var isArguments2 = baseIsArguments2(function() {
             return arguments;
-          }()) ? baseIsArguments : function(value) {
-            return isObjectLike2(value) && hasOwnProperty2.call(value, "callee") && !propertyIsEnumerable.call(value, "callee");
+          }()) ? baseIsArguments2 : function(value) {
+            return isObjectLike2(value) && hasOwnProperty10.call(value, "callee") && !propertyIsEnumerable3.call(value, "callee");
           };
           var isArray2 = Array2.isArray;
-          var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
-          function isArrayLike(value) {
-            return value != null && isLength(value.length) && !isFunction(value);
+          var isArrayBuffer = nodeIsArrayBuffer ? baseUnary2(nodeIsArrayBuffer) : baseIsArrayBuffer;
+          function isArrayLike2(value) {
+            return value != null && isLength2(value.length) && !isFunction2(value);
           }
           function isArrayLikeObject(value) {
-            return isObjectLike2(value) && isArrayLike(value);
+            return isObjectLike2(value) && isArrayLike2(value);
           }
           function isBoolean(value) {
-            return value === true || value === false || isObjectLike2(value) && baseGetTag2(value) == boolTag;
+            return value === true || value === false || isObjectLike2(value) && baseGetTag2(value) == boolTag3;
           }
-          var isBuffer = nativeIsBuffer || stubFalse;
-          var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
+          var isBuffer2 = nativeIsBuffer2 || stubFalse2;
+          var isDate = nodeIsDate ? baseUnary2(nodeIsDate) : baseIsDate;
           function isElement2(value) {
             return isObjectLike2(value) && value.nodeType === 1 && !isPlainObject(value);
           }
             if (value == null) {
               return true;
             }
-            if (isArrayLike(value) && (isArray2(value) || typeof value == "string" || typeof value.splice == "function" || isBuffer(value) || isTypedArray(value) || isArguments(value))) {
+            if (isArrayLike2(value) && (isArray2(value) || typeof value == "string" || typeof value.splice == "function" || isBuffer2(value) || isTypedArray2(value) || isArguments2(value))) {
               return !value.length;
             }
-            var tag = getTag(value);
-            if (tag == mapTag || tag == setTag) {
+            var tag = getTag2(value);
+            if (tag == mapTag4 || tag == setTag4) {
               return !value.size;
             }
-            if (isPrototype(value)) {
-              return !baseKeys(value).length;
+            if (isPrototype2(value)) {
+              return !baseKeys2(value).length;
             }
             for (var key in value) {
-              if (hasOwnProperty2.call(value, key)) {
+              if (hasOwnProperty10.call(value, key)) {
                 return false;
               }
             }
             return true;
           }
-          function isEqual(value, other) {
-            return baseIsEqual(value, other);
+          function isEqual4(value, other) {
+            return baseIsEqual2(value, other);
           }
           function isEqualWith(value, other, customizer) {
             customizer = typeof customizer == "function" ? customizer : undefined2;
             var result2 = customizer ? customizer(value, other) : undefined2;
-            return result2 === undefined2 ? baseIsEqual(value, other, undefined2, customizer) : !!result2;
+            return result2 === undefined2 ? baseIsEqual2(value, other, undefined2, customizer) : !!result2;
           }
           function isError(value) {
             if (!isObjectLike2(value)) {
               return false;
             }
             var tag = baseGetTag2(value);
-            return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject(value);
+            return tag == errorTag3 || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject(value);
           }
           function isFinite2(value) {
             return typeof value == "number" && nativeIsFinite(value);
           }
-          function isFunction(value) {
-            if (!isObject2(value)) {
+          function isFunction2(value) {
+            if (!isObject3(value)) {
               return false;
             }
             var tag = baseGetTag2(value);
-            return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
+            return tag == funcTag3 || tag == genTag2 || tag == asyncTag2 || tag == proxyTag2;
           }
           function isInteger(value) {
             return typeof value == "number" && value == toInteger(value);
           }
-          function isLength(value) {
-            return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+          function isLength2(value) {
+            return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER3;
           }
-          function isObject2(value) {
-            var type3 = typeof value;
-            return value != null && (type3 == "object" || type3 == "function");
+          function isObject3(value) {
+            var type2 = typeof value;
+            return value != null && (type2 == "object" || type2 == "function");
           }
           function isObjectLike2(value) {
             return value != null && typeof value == "object";
           }
-          var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;
+          var isMap = nodeIsMap ? baseUnary2(nodeIsMap) : baseIsMap;
           function isMatch(object, source) {
             return object === source || baseIsMatch(object, source, getMatchData(source));
           }
             if (isMaskable(value)) {
               throw new Error2(CORE_ERROR_TEXT);
             }
-            return baseIsNative(value);
+            return baseIsNative2(value);
           }
           function isNull(value) {
             return value === null;
             return value == null;
           }
           function isNumber2(value) {
-            return typeof value == "number" || isObjectLike2(value) && baseGetTag2(value) == numberTag;
+            return typeof value == "number" || isObjectLike2(value) && baseGetTag2(value) == numberTag3;
           }
           function isPlainObject(value) {
-            if (!isObjectLike2(value) || baseGetTag2(value) != objectTag) {
+            if (!isObjectLike2(value) || baseGetTag2(value) != objectTag4) {
               return false;
             }
             var proto = getPrototype(value);
             if (proto === null) {
               return true;
             }
-            var Ctor = hasOwnProperty2.call(proto, "constructor") && proto.constructor;
-            return typeof Ctor == "function" && Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString;
+            var Ctor = hasOwnProperty10.call(proto, "constructor") && proto.constructor;
+            return typeof Ctor == "function" && Ctor instanceof Ctor && funcToString3.call(Ctor) == objectCtorString;
           }
-          var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
+          var isRegExp = nodeIsRegExp ? baseUnary2(nodeIsRegExp) : baseIsRegExp;
           function isSafeInteger(value) {
-            return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
+            return isInteger(value) && value >= -MAX_SAFE_INTEGER3 && value <= MAX_SAFE_INTEGER3;
           }
-          var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
+          var isSet = nodeIsSet ? baseUnary2(nodeIsSet) : baseIsSet;
           function isString(value) {
-            return typeof value == "string" || !isArray2(value) && isObjectLike2(value) && baseGetTag2(value) == stringTag;
+            return typeof value == "string" || !isArray2(value) && isObjectLike2(value) && baseGetTag2(value) == stringTag3;
           }
           function isSymbol2(value) {
-            return typeof value == "symbol" || isObjectLike2(value) && baseGetTag2(value) == symbolTag2;
+            return typeof value == "symbol" || isObjectLike2(value) && baseGetTag2(value) == symbolTag3;
           }
-          var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
+          var isTypedArray2 = nodeIsTypedArray2 ? baseUnary2(nodeIsTypedArray2) : baseIsTypedArray2;
           function isUndefined(value) {
             return value === undefined2;
           }
           function isWeakMap(value) {
-            return isObjectLike2(value) && getTag(value) == weakMapTag;
+            return isObjectLike2(value) && getTag2(value) == weakMapTag3;
           }
           function isWeakSet(value) {
             return isObjectLike2(value) && baseGetTag2(value) == weakSetTag;
             if (!value) {
               return [];
             }
-            if (isArrayLike(value)) {
+            if (isArrayLike2(value)) {
               return isString(value) ? stringToArray(value) : copyArray(value);
             }
             if (symIterator && value[symIterator]) {
               return iteratorToArray(value[symIterator]());
             }
-            var tag = getTag(value), func = tag == mapTag ? mapToArray : tag == setTag ? setToArray : values;
+            var tag = getTag2(value), func = tag == mapTag4 ? mapToArray2 : tag == setTag4 ? setToArray2 : values;
             return func(value);
           }
           function toFinite(value) {
             if (!value) {
               return value === 0 ? value : 0;
             }
-            value = toNumber2(value);
+            value = toNumber3(value);
             if (value === INFINITY2 || value === -INFINITY2) {
               var sign2 = value < 0 ? -1 : 1;
               return sign2 * MAX_INTEGER;
           function toLength(value) {
             return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
           }
-          function toNumber2(value) {
+          function toNumber3(value) {
             if (typeof value == "number") {
               return value;
             }
             if (isSymbol2(value)) {
               return NAN2;
             }
-            if (isObject2(value)) {
+            if (isObject3(value)) {
               var other = typeof value.valueOf == "function" ? value.valueOf() : value;
-              value = isObject2(other) ? other + "" : other;
+              value = isObject3(other) ? other + "" : other;
             }
             if (typeof value != "string") {
               return value === 0 ? value : +value;
             return copyObject(value, keysIn(value));
           }
           function toSafeInteger(value) {
-            return value ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) : value === 0 ? value : 0;
+            return value ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER3, MAX_SAFE_INTEGER3) : value === 0 ? value : 0;
           }
           function toString2(value) {
             return value == null ? "" : baseToString2(value);
           }
           var assign = createAssigner(function(object, source) {
-            if (isPrototype(source) || isArrayLike(source)) {
-              copyObject(source, keys(source), object);
+            if (isPrototype2(source) || isArrayLike2(source)) {
+              copyObject(source, keys2(source), object);
               return;
             }
             for (var key in source) {
-              if (hasOwnProperty2.call(source, key)) {
+              if (hasOwnProperty10.call(source, key)) {
                 assignValue(object, key, source[key]);
               }
             }
             copyObject(source, keysIn(source), object, customizer);
           });
           var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
-            copyObject(source, keys(source), object, customizer);
+            copyObject(source, keys2(source), object, customizer);
           });
           var at = flatRest(baseAt);
           function create2(prototype, properties) {
               while (++propsIndex < propsLength) {
                 var key = props[propsIndex];
                 var value = object[key];
-                if (value === undefined2 || eq(value, objectProto3[key]) && !hasOwnProperty2.call(object, key)) {
+                if (value === undefined2 || eq2(value, objectProto13[key]) && !hasOwnProperty10.call(object, key)) {
                   object[key] = source[key];
                 }
               }
             return object && baseForOwnRight(object, getIteratee(iteratee2, 3));
           }
           function functions(object) {
-            return object == null ? [] : baseFunctions(object, keys(object));
+            return object == null ? [] : baseFunctions(object, keys2(object));
           }
           function functionsIn(object) {
             return object == null ? [] : baseFunctions(object, keysIn(object));
             if (value != null && typeof value.toString != "function") {
               value = nativeObjectToString3.call(value);
             }
-            if (hasOwnProperty2.call(result2, value)) {
+            if (hasOwnProperty10.call(result2, value)) {
               result2[value].push(key);
             } else {
               result2[value] = [key];
             }
           }, getIteratee);
           var invoke = baseRest(baseInvoke);
-          function keys(object) {
-            return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
+          function keys2(object) {
+            return isArrayLike2(object) ? arrayLikeKeys2(object) : baseKeys2(object);
           }
           function keysIn(object) {
-            return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
+            return isArrayLike2(object) ? arrayLikeKeys2(object, true) : baseKeysIn(object);
           }
           function mapKeys(object, iteratee2) {
             var result2 = {};
             });
             return result2;
           }
-          var merge3 = createAssigner(function(object, source, srcIndex) {
+          var merge2 = createAssigner(function(object, source, srcIndex) {
             baseMerge(object, source, srcIndex);
           });
           var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
                 index = length;
                 value = defaultValue;
               }
-              object = isFunction(value) ? value.call(object) : value;
+              object = isFunction2(value) ? value.call(object) : value;
             }
             return object;
           }
             customizer = typeof customizer == "function" ? customizer : undefined2;
             return object == null ? object : baseSet(object, path, value, customizer);
           }
-          var toPairs = createToPairs(keys);
+          var toPairs = createToPairs(keys2);
           var toPairsIn = createToPairs(keysIn);
           function transform2(object, iteratee2, accumulator) {
-            var isArr = isArray2(object), isArrLike = isArr || isBuffer(object) || isTypedArray(object);
+            var isArr = isArray2(object), isArrLike = isArr || isBuffer2(object) || isTypedArray2(object);
             iteratee2 = getIteratee(iteratee2, 4);
             if (accumulator == null) {
               var Ctor = object && object.constructor;
               if (isArrLike) {
                 accumulator = isArr ? new Ctor() : [];
-              } else if (isObject2(object)) {
-                accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
+              } else if (isObject3(object)) {
+                accumulator = isFunction2(Ctor) ? baseCreate(getPrototype(object)) : {};
               } else {
                 accumulator = {};
               }
             return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
           }
           function values(object) {
-            return object == null ? [] : baseValues(object, keys(object));
+            return object == null ? [] : baseValues(object, keys2(object));
           }
           function valuesIn(object) {
             return object == null ? [] : baseValues(object, keysIn(object));
               lower2 = undefined2;
             }
             if (upper !== undefined2) {
-              upper = toNumber2(upper);
+              upper = toNumber3(upper);
               upper = upper === upper ? upper : 0;
             }
             if (lower2 !== undefined2) {
-              lower2 = toNumber2(lower2);
+              lower2 = toNumber3(lower2);
               lower2 = lower2 === lower2 ? lower2 : 0;
             }
-            return baseClamp(toNumber2(number3), lower2, upper);
+            return baseClamp(toNumber3(number3), lower2, upper);
           }
           function inRange(number3, start2, end) {
             start2 = toFinite(start2);
             } else {
               end = toFinite(end);
             }
-            number3 = toNumber2(number3);
+            number3 = toNumber3(number3);
             return baseInRange(number3, start2, end);
           }
           function random(lower2, upper, floating) {
           }
           function escapeRegExp(string) {
             string = toString2(string);
-            return string && reHasRegExpChar.test(string) ? string.replace(reRegExpChar, "\\$&") : string;
+            return string && reHasRegExpChar.test(string) ? string.replace(reRegExpChar2, "\\$&") : string;
           }
           var kebabCase = createCompounder(function(result2, word, index) {
             return result2 + (index ? "-" : "") + word.toLowerCase();
             }
             string = toString2(string);
             options2 = assignInWith({}, options2, settings, customDefaultsAssignIn);
-            var imports = assignInWith({}, options2.imports, settings.imports, customDefaultsAssignIn), importsKeys = keys(imports), importsValues = baseValues(imports, importsKeys);
+            var imports = assignInWith({}, options2.imports, settings.imports, customDefaultsAssignIn), importsKeys = keys2(imports), importsValues = baseValues(imports, importsKeys);
             var isEscaping, isEvaluating, index = 0, interpolate = options2.interpolate || reNoMatch, source = "__p += '";
             var reDelimiters = RegExp2(
               (options2.escape || reNoMatch).source + "|" + interpolate.source + "|" + (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + "|" + (options2.evaluate || reNoMatch).source + "|$",
               "g"
             );
-            var sourceURL = "//# sourceURL=" + (hasOwnProperty2.call(options2, "sourceURL") ? (options2.sourceURL + "").replace(/\s/g, " ") : "lodash.templateSources[" + ++templateCounter + "]") + "\n";
+            var sourceURL = "//# sourceURL=" + (hasOwnProperty10.call(options2, "sourceURL") ? (options2.sourceURL + "").replace(/\s/g, " ") : "lodash.templateSources[" + ++templateCounter + "]") + "\n";
             string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
               interpolateValue || (interpolateValue = esTemplateValue);
               source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
               return match;
             });
             source += "';\n";
-            var variable = hasOwnProperty2.call(options2, "variable") && options2.variable;
+            var variable = hasOwnProperty10.call(options2, "variable") && options2.variable;
             if (!variable) {
               source = "with (obj) {\n" + source + "\n}\n";
             } else if (reForbiddenIdentifierChars.test(variable)) {
           }
           function truncate(string, options2) {
             var length = DEFAULT_TRUNC_LENGTH, omission = DEFAULT_TRUNC_OMISSION;
-            if (isObject2(options2)) {
+            if (isObject3(options2)) {
               var separator = "separator" in options2 ? options2.separator : separator;
               length = "length" in options2 ? toInteger(options2.length) : length;
               omission = "omission" in options2 ? baseToString2(options2.omission) : omission;
             };
           });
           function mixin(object, source, options2) {
-            var props = keys(source), methodNames = baseFunctions(source, props);
-            if (options2 == null && !(isObject2(source) && (methodNames.length || !props.length))) {
+            var props = keys2(source), methodNames = baseFunctions(source, props);
+            if (options2 == null && !(isObject3(source) && (methodNames.length || !props.length))) {
               options2 = source;
               source = object;
               object = this;
-              methodNames = baseFunctions(source, keys(source));
+              methodNames = baseFunctions(source, keys2(source));
             }
-            var chain2 = !(isObject2(options2) && "chain" in options2) || !!options2.chain, isFunc = isFunction(object);
+            var chain2 = !(isObject3(options2) && "chain" in options2) || !!options2.chain, isFunc = isFunction2(object);
             arrayEach(methodNames, function(methodName) {
               var func = source[methodName];
               object[methodName] = func;
                     result2.__chain__ = chainAll;
                     return result2;
                   }
-                  return func.apply(object, arrayPush([this.value()], arguments));
+                  return func.apply(object, arrayPush2([this.value()], arguments));
                 };
               }
             });
           }
           var over = createOver(arrayMap2);
           var overEvery = createOver(arrayEvery);
-          var overSome = createOver(arraySome);
+          var overSome = createOver(arraySome2);
           function property(path) {
             return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
           }
           }
           var range3 = createRange();
           var rangeRight = createRange(true);
-          function stubArray() {
+          function stubArray2() {
             return [];
           }
-          function stubFalse() {
+          function stubFalse2() {
             return false;
           }
           function stubObject() {
           }
           function times(n2, iteratee2) {
             n2 = toInteger(n2);
-            if (n2 < 1 || n2 > MAX_SAFE_INTEGER) {
+            if (n2 < 1 || n2 > MAX_SAFE_INTEGER3) {
               return [];
             }
             var index = MAX_ARRAY_LENGTH, length = nativeMin2(n2, MAX_ARRAY_LENGTH);
             iteratee2 = getIteratee(iteratee2);
             n2 -= MAX_ARRAY_LENGTH;
-            var result2 = baseTimes(length, iteratee2);
+            var result2 = baseTimes2(length, iteratee2);
             while (++index < n2) {
               iteratee2(index);
             }
           lodash.invokeMap = invokeMap;
           lodash.iteratee = iteratee;
           lodash.keyBy = keyBy;
-          lodash.keys = keys;
+          lodash.keys = keys2;
           lodash.keysIn = keysIn;
           lodash.map = map2;
           lodash.mapKeys = mapKeys;
           lodash.matches = matches;
           lodash.matchesProperty = matchesProperty;
           lodash.memoize = memoize;
-          lodash.merge = merge3;
+          lodash.merge = merge2;
           lodash.mergeWith = mergeWith;
           lodash.method = method;
           lodash.methodOf = methodOf;
           lodash.defaultTo = defaultTo;
           lodash.divide = divide;
           lodash.endsWith = endsWith;
-          lodash.eq = eq;
+          lodash.eq = eq2;
           lodash.escape = escape6;
           lodash.escapeRegExp = escapeRegExp;
           lodash.every = every;
           lodash.indexOf = indexOf;
           lodash.inRange = inRange;
           lodash.invoke = invoke;
-          lodash.isArguments = isArguments;
+          lodash.isArguments = isArguments2;
           lodash.isArray = isArray2;
           lodash.isArrayBuffer = isArrayBuffer;
-          lodash.isArrayLike = isArrayLike;
+          lodash.isArrayLike = isArrayLike2;
           lodash.isArrayLikeObject = isArrayLikeObject;
           lodash.isBoolean = isBoolean;
-          lodash.isBuffer = isBuffer;
+          lodash.isBuffer = isBuffer2;
           lodash.isDate = isDate;
           lodash.isElement = isElement2;
           lodash.isEmpty = isEmpty;
-          lodash.isEqual = isEqual;
+          lodash.isEqual = isEqual4;
           lodash.isEqualWith = isEqualWith;
           lodash.isError = isError;
           lodash.isFinite = isFinite2;
-          lodash.isFunction = isFunction;
+          lodash.isFunction = isFunction2;
           lodash.isInteger = isInteger;
-          lodash.isLength = isLength;
+          lodash.isLength = isLength2;
           lodash.isMap = isMap;
           lodash.isMatch = isMatch;
           lodash.isMatchWith = isMatchWith;
           lodash.isNil = isNil;
           lodash.isNull = isNull;
           lodash.isNumber = isNumber2;
-          lodash.isObject = isObject2;
+          lodash.isObject = isObject3;
           lodash.isObjectLike = isObjectLike2;
           lodash.isPlainObject = isPlainObject;
           lodash.isRegExp = isRegExp;
           lodash.isSet = isSet;
           lodash.isString = isString;
           lodash.isSymbol = isSymbol2;
-          lodash.isTypedArray = isTypedArray;
+          lodash.isTypedArray = isTypedArray2;
           lodash.isUndefined = isUndefined;
           lodash.isWeakMap = isWeakMap;
           lodash.isWeakSet = isWeakSet;
           lodash.meanBy = meanBy;
           lodash.min = min3;
           lodash.minBy = minBy;
-          lodash.stubArray = stubArray;
-          lodash.stubFalse = stubFalse;
+          lodash.stubArray = stubArray2;
+          lodash.stubFalse = stubFalse2;
           lodash.stubObject = stubObject;
           lodash.stubString = stubString;
           lodash.stubTrue = stubTrue;
           lodash.toInteger = toInteger;
           lodash.toLength = toLength;
           lodash.toLower = toLower;
-          lodash.toNumber = toNumber2;
+          lodash.toNumber = toNumber3;
           lodash.toSafeInteger = toSafeInteger;
           lodash.toString = toString2;
           lodash.toUpper = toUpper;
           mixin(lodash, function() {
             var source = {};
             baseForOwn(lodash, function(func, methodName) {
-              if (!hasOwnProperty2.call(lodash.prototype, methodName)) {
+              if (!hasOwnProperty10.call(lodash.prototype, methodName)) {
                 source[methodName] = func;
               }
             });
             };
           });
           arrayEach(["filter", "map", "takeWhile"], function(methodName, index) {
-            var type3 = index + 1, isFilter = type3 == LAZY_FILTER_FLAG || type3 == LAZY_WHILE_FLAG;
+            var type2 = index + 1, isFilter = type2 == LAZY_FILTER_FLAG || type2 == LAZY_WHILE_FLAG;
             LazyWrapper.prototype[methodName] = function(iteratee2) {
               var result2 = this.clone();
               result2.__iteratees__.push({
                 "iteratee": getIteratee(iteratee2, 3),
-                "type": type3
+                "type": type2
               });
               result2.__filtered__ = result2.__filtered__ || isFilter;
               return result2;
             lodash.prototype[methodName] = function() {
               var value = this.__wrapped__, args = isTaker ? [1] : arguments, isLazy = value instanceof LazyWrapper, iteratee2 = args[0], useLazy = isLazy || isArray2(value);
               var interceptor = function(value2) {
-                var result3 = lodashFunc.apply(lodash, arrayPush([value2], args));
+                var result3 = lodashFunc.apply(lodash, arrayPush2([value2], args));
                 return isTaker && chainAll ? result3[0] : result3;
               };
               if (useLazy && checkIteratee && typeof iteratee2 == "function" && iteratee2.length != 1) {
             };
           });
           arrayEach(["pop", "push", "shift", "sort", "splice", "unshift"], function(methodName) {
-            var func = arrayProto[methodName], chainName = /^(?:push|sort|unshift)$/.test(methodName) ? "tap" : "thru", retUnwrapped = /^(?:pop|shift)$/.test(methodName);
+            var func = arrayProto2[methodName], chainName = /^(?:push|sort|unshift)$/.test(methodName) ? "tap" : "thru", retUnwrapped = /^(?:pop|shift)$/.test(methodName);
             lodash.prototype[methodName] = function() {
               var args = arguments;
               if (retUnwrapped && !this.__chain__) {
             var lodashFunc = lodash[methodName];
             if (lodashFunc) {
               var key = lodashFunc.name + "";
-              if (!hasOwnProperty2.call(realNames, key)) {
+              if (!hasOwnProperty10.call(realNames, key)) {
                 realNames[key] = [];
               }
               realNames[key].push({ "name": methodName, "func": lodashFunc });
           define(function() {
             return _;
           });
-        } else if (freeModule) {
-          (freeModule.exports = _)._ = _;
-          freeExports._ = _;
+        } else if (freeModule3) {
+          (freeModule3.exports = _)._ = _;
+          freeExports3._ = _;
         } else {
           root3._ = _;
         }
     }
   });
 
+  // node_modules/fast-deep-equal/index.js
+  var require_fast_deep_equal = __commonJS({
+    "node_modules/fast-deep-equal/index.js"(exports2, module2) {
+      "use strict";
+      module2.exports = function equal(a, b) {
+        if (a === b)
+          return true;
+        if (a && b && typeof a == "object" && typeof b == "object") {
+          if (a.constructor !== b.constructor)
+            return false;
+          var length, i2, keys2;
+          if (Array.isArray(a)) {
+            length = a.length;
+            if (length != b.length)
+              return false;
+            for (i2 = length; i2-- !== 0; )
+              if (!equal(a[i2], b[i2]))
+                return false;
+            return true;
+          }
+          if (a.constructor === RegExp)
+            return a.source === b.source && a.flags === b.flags;
+          if (a.valueOf !== Object.prototype.valueOf)
+            return a.valueOf() === b.valueOf();
+          if (a.toString !== Object.prototype.toString)
+            return a.toString() === b.toString();
+          keys2 = Object.keys(a);
+          length = keys2.length;
+          if (length !== Object.keys(b).length)
+            return false;
+          for (i2 = length; i2-- !== 0; )
+            if (!Object.prototype.hasOwnProperty.call(b, keys2[i2]))
+              return false;
+          for (i2 = length; i2-- !== 0; ) {
+            var key = keys2[i2];
+            if (!equal(a[key], b[key]))
+              return false;
+          }
+          return true;
+        }
+        return a !== a && b !== b;
+      };
+    }
+  });
+
   // node_modules/rbush/rbush.min.js
   var require_rbush_min = __commonJS({
     "node_modules/rbush/rbush.min.js"(exports2, module2) {
         destroy: function() {
           this.buf = null;
         },
+        // === READING =================================================================
         readFields: function(readField, result, end) {
           end = end || this.length;
           while (this.pos < end) {
           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;
           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));
           return arr;
         },
         skip: function(val) {
-          var type3 = val & 7;
-          if (type3 === Pbf.Varint)
+          var type2 = val & 7;
+          if (type2 === Pbf.Varint)
             while (this.buf[this.pos++] > 127) {
             }
-          else if (type3 === Pbf.Bytes)
+          else if (type2 === Pbf.Bytes)
             this.pos = this.readVarint() + this.pos;
-          else if (type3 === Pbf.Fixed32)
+          else if (type2 === Pbf.Fixed32)
             this.pos += 4;
-          else if (type3 === Pbf.Fixed64)
+          else if (type2 === Pbf.Fixed64)
             this.pos += 8;
           else
-            throw new Error("Unimplemented type: " + type3);
+            throw new Error("Unimplemented type: " + type2);
         },
-        writeTag: function(tag, type3) {
-          this.writeVarint(tag << 3 | type3);
+        // === WRITING =================================================================
+        writeTag: function(tag, type2) {
+          this.writeVarint(tag << 3 | type2);
         },
         realloc: function(min3) {
           var length = this.length || 16;
         this.y = y;
       }
       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(p) {
           return this.clone()._add(p);
         },
+        /**
+         * 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(p) {
           return this.clone()._sub(p);
         },
+        /**
+         * 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(p) {
           return this.clone()._multByPoint(p);
         },
+        /**
+         * 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(p) {
           return this.clone()._divByPoint(p);
         },
+        /**
+         * Multiply this point's x & y coordinates by a factor,
+         * yielding a new point.
+         * @param {Point} k factor
+         * @return {Point} output point
+         */
         mult: function(k) {
           return this.clone()._mult(k);
         },
+        /**
+         * Divide this point's x & y coordinates by a factor,
+         * yielding a new point.
+         * @param {Point} k factor
+         * @return {Point} output point
+         */
         div: function(k) {
           return this.clone()._div(k);
         },
+        /**
+         * 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(a) {
           return this.clone()._rotate(a);
         },
+        /**
+         * 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(a, p) {
           return this.clone()._rotateAround(a, p);
         },
+        /**
+         * Multiply this point by a 4x1 transformation matrix
+         * @param {Array<Number>} m transformation matrix
+         * @return {Point} output point
+         */
         matMult: function(m) {
           return this.clone()._matMult(m);
         },
+        /**
+         * 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(p) {
           return Math.sqrt(this.distSqr(p));
         },
+        /**
+         * 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(p) {
           var dx = p.x - this.x, dy = p.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(b) {
           return Math.atan2(this.y - b.y, this.x - b.x);
         },
+        /**
+         * Get the angle between this point and another point, in radians
+         * @param {Point} b the other point
+         * @return {Number} angle
+         */
         angleWith: function(b) {
           return this.angleWithSep(b.x, b.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(x, y) {
           return Math.atan2(
             this.x * y - this.y * x,
       "use strict";
       var Point = require_point_geometry();
       module2.exports = VectorTileFeature;
-      function VectorTileFeature(pbf, end, extent, keys, values) {
+      function VectorTileFeature(pbf, end, extent, keys2, values) {
         this.properties = {};
         this.extent = extent;
         this.type = 0;
         this._pbf = pbf;
         this._geometry = -1;
-        this._keys = keys;
+        this._keys = keys2;
         this._values = values;
         pbf.readFields(readFeature, this, end);
       }
         return [x12, y12, x2, y2];
       };
       VectorTileFeature.prototype.toGeoJSON = function(x, y, z) {
-        var size = this.extent * Math.pow(2, z), x05 = this.extent * x, y05 = this.extent * y, coords = this.loadGeometry(), type3 = VectorTileFeature.types[this.type], i2, j2;
+        var size = this.extent * Math.pow(2, z), x05 = this.extent * x, y05 = this.extent * y, coords = this.loadGeometry(), type2 = VectorTileFeature.types[this.type], i2, j2;
         function project(line) {
           for (var j3 = 0; j3 < line.length; j3++) {
             var p = line[j3], y2 = 180 - (p.y + y05) * 360 / size;
         if (coords.length === 1) {
           coords = coords[0];
         } else {
-          type3 = "Multi" + type3;
+          type2 = "Multi" + type2;
         }
         var result = {
           type: "Feature",
           geometry: {
-            type: type3,
+            type: type2,
             coordinates: coords
           },
           properties: this.properties
             throw new TypeError("Converting circular structure to JSON");
           }
           var seenIndex = seen.push(node) - 1;
-          var keys = Object.keys(node).sort(cmp && cmp(node));
+          var keys2 = Object.keys(node).sort(cmp && cmp(node));
           out = "";
-          for (i2 = 0; i2 < keys.length; i2++) {
-            var key = keys[i2];
+          for (i2 = 0; i2 < keys2.length; i2++) {
+            var key = keys2[i2];
             var value = stringify3(node[key]);
             if (!value)
               continue;
         map: map2,
         pluck,
         isList,
-        isFunction,
-        isObject: isObject2,
+        isFunction: isFunction2,
+        isObject: isObject3,
         Global
       };
       function make_assign() {
       function isList(val) {
         return val != null && typeof val != "function" && typeof val.length == "number";
       }
-      function isFunction(val) {
+      function isFunction2(val) {
         return val && {}.toString.call(val) === "[object Function]";
       }
-      function isObject2(val) {
+      function isObject3(val) {
         return val && {}.toString.call(val) === "[object Object]";
       }
     }
       var bind = util.bind;
       var create2 = util.create;
       var isList = util.isList;
-      var isFunction = util.isFunction;
-      var isObject2 = util.isObject;
+      var isFunction2 = util.isFunction;
+      var isObject3 = util.isObject;
       module2.exports = {
         createStore
       };
       var storeAPI = {
         version: "2.0.12",
         enabled: false,
+        // get returns the value of the given key. If that value
+        // is undefined, it returns optionalDefaultValue instead.
         get: function(key, optionalDefaultValue) {
           var data = this.storage.read(this._namespacePrefix + key);
           return this._deserialize(data, optionalDefaultValue);
         },
+        // set will store the given value at key and returns value.
+        // Calling set with value === undefined is equivalent to calling remove.
         set: function(key, value) {
           if (value === void 0) {
             return this.remove(key);
           this.storage.write(this._namespacePrefix + key, this._serialize(value));
           return value;
         },
+        // remove deletes the key and value stored at the given key.
         remove: function(key) {
           this.storage.remove(this._namespacePrefix + key);
         },
+        // each will call the given callback once for each key-value pair
+        // in this store.
         each: function(callback) {
           var self2 = this;
           this.storage.each(function(val, namespacedKey) {
             callback.call(self2, self2._deserialize(val), (namespacedKey || "").replace(self2._namespaceRegexp, ""));
           });
         },
+        // clearAll will remove all the stored key-value pairs in this store.
         clearAll: function() {
           this.storage.clearAll();
         },
+        // additional functionality that can't live in plugins
+        // ---------------------------------------------------
+        // hasNamespace returns true if this store instance has the given namespace.
         hasNamespace: function(namespace) {
           return this._namespacePrefix == "__storejs_" + namespace + "_";
         },
+        // createStore creates a store.js instance with the first
+        // functioning storage in the list of storage candidates,
+        // and applies the the given mixins to the instance.
         createStore: function() {
           return createStore.apply(this, arguments);
         },
               return;
             }
             this.plugins.push(plugin);
-            if (!isFunction(plugin)) {
+            if (!isFunction2(plugin)) {
               throw new Error("Plugins must be function values that return objects");
             }
             var pluginProperties = plugin.call(this);
-            if (!isObject2(pluginProperties)) {
+            if (!isObject3(pluginProperties)) {
               throw new Error("Plugins must return an object of function properties");
             }
             each(pluginProperties, function(pluginFnProp, propName) {
-              if (!isFunction(pluginFnProp)) {
+              if (!isFunction2(pluginFnProp)) {
                 throw new Error("Bad plugin property: " + propName + " from plugin " + plugin.name + ". Plugins should only return functions.");
               }
               self2._assignPluginFnProp(pluginFnProp, propName);
             });
           },
+          // Put deprecated properties in the private API, so as to not expose it to accidential
+          // discovery through inspection of the store object.
+          // Deprecated: addStorage
           addStorage: function(storage) {
             _warn("store.addStorage(storage) is deprecated. Use createStore([storages])");
             this._addStorage(storage);
         });
         store2.raw = {};
         each(store2, function(prop, propName) {
-          if (isFunction(prop)) {
+          if (isFunction2(prop)) {
             store2.raw[propName] = bind(store2, prop);
           }
         });
   var require_all = __commonJS({
     "node_modules/store/storages/all.js"(exports2, module2) {
       module2.exports = [
+        // Listed in order of usage preference
         require_localStorage(),
         require_oldFF_globalStorage(),
         require_oldIE_userDataStorage(),
         }
         if (typeof JSON.stringify !== "function") {
           meta = {
+            // table of character substitutions
             "\b": "\\b",
             "  ": "\\t",
             "\n": "\\n",
       if (options2.cache === "no-store" || options2.cache === "no-cache") {
         var reParamSearch = /([?&])_=[^&]*/;
         if (reParamSearch.test(this.url)) {
-          this.url = this.url.replace(reParamSearch, "$1_=" + new Date().getTime());
+          this.url = this.url.replace(reParamSearch, "$1_=" + (/* @__PURE__ */ new Date()).getTime());
         } else {
           var reQueryString = /\?/;
-          this.url += (reQueryString.test(this.url) ? "&" : "?") + "_=" + new Date().getTime();
+          this.url += (reQueryString.test(this.url) ? "&" : "?") + "_=" + (/* @__PURE__ */ new Date()).getTime();
         }
       }
     }
         _defineProperties(Constructor.prototype, protoProps);
       if (staticProps)
         _defineProperties(Constructor, staticProps);
+      Object.defineProperty(Constructor, "prototype", {
+        writable: false
+      });
       return Constructor;
     }
     function _inherits(subClass, superClass) {
           configurable: true
         }
       });
+      Object.defineProperty(subClass, "prototype", {
+        writable: false
+      });
       if (superClass)
         _setPrototypeOf(subClass, superClass);
     }
     function _getPrototypeOf(o) {
-      _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf2(o2) {
+      _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf2(o2) {
         return o2.__proto__ || Object.getPrototypeOf(o2);
       };
       return _getPrototypeOf(o);
     }
     function _setPrototypeOf(o, p) {
-      _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf2(o2, p2) {
+      _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf2(o2, p2) {
         o2.__proto__ = p2;
         return o2;
       };
     function _possibleConstructorReturn(self2, call) {
       if (call && (typeof call === "object" || typeof call === "function")) {
         return call;
+      } else if (call !== void 0) {
+        throw new TypeError("Derived constructors may only return object or undefined");
       }
       return _assertThisInitialized(self2);
     }
       }
       return object;
     }
-    function _get(target, property, receiver) {
+    function _get() {
       if (typeof Reflect !== "undefined" && Reflect.get) {
-        _get = Reflect.get;
+        _get = Reflect.get.bind();
       } else {
-        _get = function _get2(target2, property2, receiver2) {
-          var base = _superPropBase(target2, property2);
+        _get = function _get2(target, property, receiver) {
+          var base = _superPropBase(target, property);
           if (!base)
             return;
-          var desc = Object.getOwnPropertyDescriptor(base, property2);
+          var desc = Object.getOwnPropertyDescriptor(base, property);
           if (desc.get) {
-            return desc.get.call(receiver2);
+            return desc.get.call(arguments.length < 3 ? target : receiver);
           }
           return desc.value;
         };
       }
-      return _get(target, property, receiver || target);
+      return _get.apply(this, arguments);
     }
     var Emitter = /* @__PURE__ */ function() {
       function Emitter2() {
       }
       _createClass(Emitter2, [{
         key: "addEventListener",
-        value: function addEventListener(type3, callback, options2) {
-          if (!(type3 in this.listeners)) {
-            this.listeners[type3] = [];
+        value: function addEventListener(type2, callback, options2) {
+          if (!(type2 in this.listeners)) {
+            this.listeners[type2] = [];
           }
-          this.listeners[type3].push({
+          this.listeners[type2].push({
             callback,
             options: options2
           });
         }
       }, {
         key: "removeEventListener",
-        value: function removeEventListener(type3, callback) {
-          if (!(type3 in this.listeners)) {
+        value: function removeEventListener(type2, callback) {
+          if (!(type2 in this.listeners)) {
             return;
           }
-          var stack = this.listeners[type3];
+          var stack = this.listeners[type2];
           for (var i2 = 0, l = stack.length; i2 < l; i2++) {
             if (stack[i2].callback === callback) {
               stack.splice(i2, 1);
           writable: true,
           configurable: true
         });
+        Object.defineProperty(_assertThisInitialized(_this), "reason", {
+          value: void 0,
+          writable: true,
+          configurable: true
+        });
         return _this;
       }
       _createClass(AbortSignal2, [{
       }
       _createClass(AbortController3, [{
         key: "abort",
-        value: function abort() {
+        value: function abort(reason) {
           var event;
           try {
             event = new Event("abort");
               };
             }
           }
+          var signalReason = reason;
+          if (signalReason === void 0) {
+            if (typeof document === "undefined") {
+              signalReason = new Error("This operation was aborted");
+              signalReason.name = "AbortError";
+            } else {
+              try {
+                signalReason = new DOMException("signal is aborted without reason");
+              } catch (err) {
+                signalReason = new Error("This operation was aborted");
+                signalReason.name = "AbortError";
+              }
+            }
+          }
+          this.signal.reason = signalReason;
           this.signal.dispatchEvent(event);
         }
       }, {
   // modules/index.js
   var modules_exports = {};
   __export(modules_exports, {
+    LocationManager: () => LocationManager,
     QAItem: () => QAItem,
     actionAddEntity: () => actionAddEntity,
     actionAddMember: () => actionAddMember,
     coreGraph: () => coreGraph,
     coreHistory: () => coreHistory,
     coreLocalizer: () => coreLocalizer,
-    coreLocations: () => coreLocations,
     coreTree: () => coreTree,
     coreUploader: () => coreUploader,
     coreValidator: () => coreValidator,
     geoVecSubtract: () => geoVecSubtract,
     geoViewportEdge: () => geoViewportEdge,
     geoZoomToScale: () => geoZoomToScale,
+    likelyRawNumberFormat: () => likelyRawNumberFormat,
     localizer: () => _mainLocalizer,
-    locationManager: () => _mainLocations,
+    locationManager: () => _sharedLocationManager,
     modeAddArea: () => modeAddArea,
     modeAddLine: () => modeAddLine,
     modeAddNote: () => modeAddNote,
     uiFieldAccess: () => uiFieldAccess,
     uiFieldAddress: () => uiFieldAddress,
     uiFieldCheck: () => uiFieldCheck,
+    uiFieldColour: () => uiFieldText,
     uiFieldCombo: () => uiFieldCombo,
-    uiFieldCycleway: () => uiFieldCycleway,
     uiFieldDefaultCheck: () => uiFieldCheck,
+    uiFieldDirectionalCombo: () => uiFieldDirectionalCombo,
     uiFieldEmail: () => uiFieldText,
     uiFieldHelp: () => uiFieldHelp,
     uiFieldIdentifier: () => uiFieldText,
     uiKeepRightEditor: () => uiKeepRightEditor,
     uiKeepRightHeader: () => uiKeepRightHeader,
     uiLasso: () => uiLasso,
+    uiLengthIndicator: () => uiLengthIndicator,
     uiLoading: () => uiLoading,
     uiMapInMap: () => uiMapInMap,
     uiModal: () => uiModal,
     utilArrayUniq: () => utilArrayUniq,
     utilArrayUniqBy: () => utilArrayUniqBy,
     utilAsyncMap: () => utilAsyncMap,
+    utilCleanOsmString: () => utilCleanOsmString,
     utilCleanTags: () => utilCleanTags,
     utilCombinedTags: () => utilCombinedTags,
     utilCompareIDs: () => utilCompareIDs,
       } else if (options2 && options2.reverseOneway && key === "oneway") {
         return onewayReplacements[value] || value;
       } else if (includeAbsolute && directionKey.test(key)) {
-        if (compassReplacements[value])
-          return compassReplacements[value];
-        var degrees3 = parseFloat(value);
-        if (typeof degrees3 === "number" && !isNaN(degrees3)) {
-          if (degrees3 < 180) {
-            degrees3 += 180;
+        return value.split(";").map((value2) => {
+          if (compassReplacements[value2])
+            return compassReplacements[value2];
+          var degrees3 = Number(value2);
+          if (isFinite(degrees3)) {
+            if (degrees3 < 180) {
+              degrees3 += 180;
+            } else {
+              degrees3 -= 180;
+            }
+            return degrees3.toString();
           } else {
-            degrees3 -= 180;
+            return valueReplacements[value2] || value2;
           }
-          return degrees3.toString();
-        }
+        }).join(";");
       }
       return valueReplacements[value] || value;
     }
 
   // modules/osm/tags.js
   function osmIsInterestingTag(key) {
-    return key !== "attribution" && key !== "created_by" && key !== "source" && key !== "odbl" && key.indexOf("source:") !== 0 && key.indexOf("source_ref") !== 0 && key.indexOf("tiger:") !== 0;
+    return key !== "attribution" && key !== "created_by" && key !== "source" && key !== "odbl" && key.indexOf("source:") !== 0 && key.indexOf("source_ref") !== 0 && // purposely exclude colon
+    key.indexOf("tiger:") !== 0;
   }
   var osmLifecyclePrefixes = {
+    // nonexistent, might be built
     proposed: true,
     planned: true,
+    // under maintentance or between groundbreaking and opening
     construction: true,
+    // existent but not functional
     disused: true,
+    // dilapidated to nonexistent
     abandoned: true,
     was: true,
+    // nonexistent, still may appear in imagery
     dismantled: true,
     razed: true,
     demolished: true,
     destroyed: true,
     removed: true,
     obliterated: true,
+    // existent occasionally, e.g. stormwater drainage basin
     intermittent: true
   };
   function osmRemoveLifecyclePrefix(key) {
       turntable: true,
       wash: true
     },
+    traffic_calming: {
+      island: true
+    },
     waterway: {
       dam: true
     }
     var returnTags = {};
     for (var realKey in tags) {
       const key = osmRemoveLifecyclePrefix(realKey);
-      if (key in osmAreaKeys && !(tags[key] in osmAreaKeys[key])) {
+      if (key in osmAreaKeys && !(tags[realKey] in osmAreaKeys[key])) {
         returnTags[realKey] = tags[realKey];
         return returnTags;
       }
-      if (key in osmAreaKeysExceptions && tags[key] in osmAreaKeysExceptions[key]) {
+      if (key in osmAreaKeysExceptions && tags[realKey] in osmAreaKeysExceptions[key]) {
         returnTags[realKey] = tags[realKey];
         return returnTags;
       }
     }
     return null;
   }
+  var osmLineTags = {};
+  function osmSetLineTags(value) {
+    osmLineTags = value;
+  }
   var osmPointTags = {};
   function osmSetPointTags(value) {
     osmPointTags = value;
       "yes": true
     },
     "seamark:type": {
+      "two-way_route": true,
+      "recommended_traffic_lane": true,
       "separation_lane": true,
       "separation_roundabout": true
     },
       "ditch": true,
       "drain": true,
       "fish_pass": true,
+      "pressurised": true,
       "river": true,
+      "spillway": true,
       "stream": true,
       "tidal_channel": true
     }
       "city_wall": true
     },
     "man_made": {
-      "embankment": true
+      "embankment": true,
+      "quay": true
     },
     "waterway": {
       "weir": true
     stream: true,
     tidal_channel: true
   };
+  var allowUpperCaseTagValues = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery|cai_scale|traffic_sign/;
 
   // node_modules/d3-array/src/ascending.js
   function ascending(a, b) {
       streamGeometry(object.geometry, stream);
     },
     FeatureCollection: function(object, stream) {
-      var features2 = object.features, i2 = -1, n2 = features2.length;
+      var features = object.features, i2 = -1, n2 = features.length;
       while (++i2 < n2)
-        streamGeometry(features2[i2].geometry, stream);
+        streamGeometry(features[i2].geometry, stream);
     }
   };
   var streamGeometryType = {
       if (direction > 0 ? t0 < t1 : t0 > t1)
         t0 += direction * tau;
     }
-    for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
-      point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
-      stream.point(point[0], point[1]);
+    for (var point2, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
+      point2 = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
+      stream.point(point2[0], point2[1]);
     }
   }
-  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;
+  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;
   }
 
   // node_modules/d3-geo/src/clip/buffer.js
   }
 
   // node_modules/d3-geo/src/clip/rejoin.js
-  function Intersection(point, points, other, entry) {
-    this.x = point;
+  function Intersection(point2, points, other, entry) {
+    this.x = point2;
     this.z = points;
     this.o = other;
     this.e = entry;
     for (i2 = 0, n2 = clip.length; i2 < n2; ++i2) {
       clip[i2].e = startInside = !startInside;
     }
-    var start2 = subject[0], points, point;
+    var start2 = subject[0], points, point2;
     while (1) {
       var current = start2, isSubject = true;
       while (current.v)
         if (current.e) {
           if (isSubject) {
             for (i2 = 0, n2 = points.length; i2 < n2; ++i2)
-              stream.point((point = points[i2])[0], point[1]);
+              stream.point((point2 = points[i2])[0], point2[1]);
           } else {
             interpolate(current.x, current.n.x, 1, stream);
           }
           if (isSubject) {
             points = current.p.z;
             for (i2 = points.length - 1; i2 >= 0; --i2)
-              stream.point((point = points[i2])[0], point[1]);
+              stream.point((point2 = points[i2])[0], point2[1]);
           } else {
             interpolate(current.x, current.p.x, -1, stream);
           }
   }
 
   // node_modules/d3-geo/src/polygonContains.js
-  function longitude(point) {
-    return abs(point[0]) <= pi ? point[0] : sign(point[0]) * ((abs(point[0]) + pi) % tau - pi);
+  function longitude(point2) {
+    return abs(point2[0]) <= pi ? point2[0] : sign(point2[0]) * ((abs(point2[0]) + pi) % tau - pi);
   }
-  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;
+  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;
     var sum = new Adder();
     if (sinPhi === 1)
       phi = halfPi + epsilon;
     return function(sink) {
       var line = clipLine(sink), ringBuffer = buffer_default(), ringSink = clipLine(ringBuffer), polygonStarted = false, polygon2, segments, ring;
       var clip = {
-        point,
+        point: point2,
         lineStart,
         lineEnd,
         polygonStart: function() {
           polygon2 = [];
         },
         polygonEnd: function() {
-          clip.point = point;
+          clip.point = point2;
           clip.lineStart = lineStart;
           clip.lineEnd = lineEnd;
           segments = merge(segments);
           sink.polygonEnd();
         }
       };
-      function point(lambda, phi) {
+      function point2(lambda, phi) {
         if (pointVisible(lambda, phi))
           sink.point(lambda, phi);
       }
         line.lineStart();
       }
       function lineEnd() {
-        clip.point = point;
+        clip.point = point2;
         line.lineEnd();
       }
       function pointRing(lambda, phi) {
       function ringEnd() {
         pointRing(ring[0][0], ring[0][1]);
         ringSink.lineEnd();
-        var clean2 = ringSink.clean(), ringSegments = ringBuffer.result(), i2, n2 = ringSegments.length, m, segment, point2;
+        var clean2 = ringSink.clean(), ringSegments = ringBuffer.result(), i2, n2 = ringSegments.length, m, segment, point3;
         ring.pop();
         polygon2.push(ring);
         ring = null;
               sink.polygonStart(), polygonStarted = true;
             sink.lineStart();
             for (i2 = 0; i2 < m; ++i2)
-              sink.point((point2 = segment[i2])[0], point2[1]);
+              sink.point((point3 = segment[i2])[0], point3[1]);
             sink.lineEnd();
           }
           return;
             stream.lineEnd();
           point0 = null;
         },
+        // Rejoin first and last segments if there were intersections and the first
+        // and last points were visible.
         clean: function() {
           return clean2 | (v00 && v0) << 1;
         }
     return function(stream) {
       var activeStream = stream, bufferStream = buffer_default(), segments, polygon2, ring, x__, y__, v__, x_, y_, v_, first, clean2;
       var clipStream = {
-        point,
+        point: point2,
         lineStart,
         lineEnd,
         polygonStart,
         polygonEnd
       };
-      function point(x, y) {
+      function point2(x, y) {
         if (visible(x, y))
           activeStream.point(x, y);
       }
       function polygonInside() {
         var winding = 0;
         for (var i2 = 0, n2 = polygon2.length; i2 < n2; ++i2) {
-          for (var ring2 = polygon2[i2], j2 = 1, m = ring2.length, point2 = ring2[0], a0, a1, b0 = point2[0], b1 = point2[1]; j2 < m; ++j2) {
-            a0 = b0, a1 = b1, point2 = ring2[j2], b0 = point2[0], b1 = point2[1];
+          for (var ring2 = polygon2[i2], j2 = 1, m = ring2.length, point3 = ring2[0], a0, a1, b0 = point3[0], b1 = point3[1]; j2 < m; ++j2) {
+            a0 = b0, a1 = b1, point3 = ring2[j2], b0 = point3[0], b1 = point3[1];
             if (a1 <= y12) {
               if (b1 > y12 && (b0 - a0) * (y12 - a1) > (b1 - a1) * (x05 - a0))
                 ++winding;
             bufferStream.rejoin();
           segments.push(bufferStream.result());
         }
-        clipStream.point = point;
+        clipStream.point = point2;
         if (v_)
           activeStream.lineEnd();
       }
     return function(stream) {
       var lambda003, x004, y004, a00, b00, c00, lambda04, x05, y05, a0, b0, c0;
       var resampleStream = {
-        point,
+        point: point2,
         lineStart,
         lineEnd,
         polygonStart: function() {
           resampleStream.lineStart = lineStart;
         }
       };
-      function point(x, y) {
+      function point2(x, y) {
         x = project(x, y);
         stream.point(x[0], x[1]);
       }
         stream.point(x05, y05);
       }
       function lineEnd() {
-        resampleStream.point = point;
+        resampleStream.point = point2;
         stream.lineEnd();
       }
       function ringStart() {
   }
   function projectionMutator(projectAt) {
     var project, k = 150, x = 480, y = 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(point) {
-      return projectRotateTransform(point[0] * radians, point[1] * radians);
+    function projection2(point2) {
+      return projectRotateTransform(point2[0] * radians, point2[1] * radians);
     }
-    function invert(point) {
-      point = projectRotateTransform.invert(point[0], point[1]);
-      return point && [point[0] * degrees, point[1] * degrees];
+    function invert(point2) {
+      point2 = projectRotateTransform.invert(point2[0], point2[1]);
+      return point2 && [point2[0] * degrees, point2[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, z) / TAU;
   }
-  function geoSphericalClosestNode(nodes, point) {
+  function geoSphericalClosestNode(nodes, point2) {
     var minDistance = Infinity, distance;
     var indexOfMin;
     for (var i2 in nodes) {
-      distance = geoSphericalDistance(nodes[i2].loc, point);
+      distance = geoSphericalDistance(nodes[i2].loc, point2);
       if (distance < minDistance) {
         minDistance = distance;
         indexOfMin = i2;
     return a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0];
   }
   function geoRotate(points, angle2, around) {
-    return points.map(function(point) {
-      var radial = geoVecSubtract(point, around);
+    return points.map(function(point2) {
+      var radial = geoVecSubtract(point2, 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, point, projection2, activeID) {
+  function geoChooseEdge(nodes, point2, projection2, activeID) {
     var dist = geoVecLength;
     var points = nodes.map(function(n2) {
       return projection2(n2.loc);
         continue;
       var o = points[i2];
       var s = geoVecSubtract(points[i2 + 1], o);
-      var v = geoVecSubtract(point, o);
+      var v = geoVecSubtract(point2, o);
       var proj = geoVecDot(v, s) / geoVecDot(s, s);
       var p;
       if (proj < 0) {
       } else {
         p = [o[0] + proj * s[0], o[1] + proj * s[1]];
       }
-      var d = dist(p, point);
+      var d = dist(p, point2);
       if (d < min3) {
         min3 = d;
         idx = i2 + 1;
     }
     return false;
   }
-  function geoPointInPolygon(point, polygon2) {
-    var x = point[0];
-    var y = point[1];
+  function geoPointInPolygon(point2, polygon2) {
+    var x = point2[0];
+    var y = point2[1];
     var inside = false;
     for (var i2 = 0, j2 = polygon2.length - 1; i2 < polygon2.length; j2 = i2++) {
       var xi = polygon2[i2][0];
     return inside;
   }
   function geoPolygonContainsPolygon(outer, inner) {
-    return inner.every(function(point) {
-      return geoPointInPolygon(point, outer);
+    return inner.every(function(point2) {
+      return geoPointInPolygon(point2, outer);
     });
   }
   function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
     function testPoints(outer2, inner2) {
-      return inner2.some(function(point) {
-        return geoPointInPolygon(point, outer2);
+      return inner2.some(function(point2) {
+        return geoPointInPolygon(point2, outer2);
       });
     }
     return testPoints(outer, inner) || !!checkSegments && geoPathHasIntersections(outer, inner);
       var c2 = i2 === hull.length - 1 ? hull[0] : hull[i2 + 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, point) {
-        return extent2.extend(geoExtent(point));
+      var extent = poly.reduce(function(extent2, point2) {
+        return extent2.extend(geoExtent(point2));
       }, geoExtent());
       var area = extent.area();
       if (area < minArea) {
     }
     return length;
   }
-  function geoViewportEdge(point, dimensions) {
+  function geoViewportEdge(point2, dimensions) {
     var pad2 = [80, 20, 50, 20];
     var x = 0;
     var y = 0;
-    if (point[0] > dimensions[0] - pad2[1]) {
+    if (point2[0] > dimensions[0] - pad2[1]) {
       x = -10;
     }
-    if (point[0] < pad2[3]) {
+    if (point2[0] < pad2[3]) {
       x = 10;
     }
-    if (point[1] > dimensions[1] - pad2[2]) {
+    if (point2[1] > dimensions[1] - pad2[2]) {
       y = -10;
     }
-    if (point[1] < pad2[0]) {
+    if (point2[1] < pad2[0]) {
       y = 10;
     }
     if (x || y) {
         copy2[t] = _[t].slice();
       return new Dispatch(copy2);
     },
-    call: function(type3, that) {
+    call: function(type2, that) {
       if ((n2 = arguments.length - 2) > 0)
         for (var args = new Array(n2), i2 = 0, n2, t; i2 < n2; ++i2)
           args[i2] = arguments[i2 + 2];
-      if (!this._.hasOwnProperty(type3))
-        throw new Error("unknown type: " + type3);
-      for (t = this._[type3], i2 = 0, n2 = t.length; i2 < n2; ++i2)
+      if (!this._.hasOwnProperty(type2))
+        throw new Error("unknown type: " + type2);
+      for (t = this._[type2], i2 = 0, n2 = t.length; i2 < n2; ++i2)
         t[i2].value.apply(that, args);
     },
-    apply: function(type3, that, args) {
-      if (!this._.hasOwnProperty(type3))
-        throw new Error("unknown type: " + type3);
-      for (var t = this._[type3], i2 = 0, n2 = t.length; i2 < n2; ++i2)
+    apply: function(type2, that, args) {
+      if (!this._.hasOwnProperty(type2))
+        throw new Error("unknown type: " + type2);
+      for (var t = this._[type2], i2 = 0, n2 = t.length; i2 < n2; ++i2)
         t[i2].value.apply(that, args);
     }
   };
-  function get(type3, name) {
-    for (var i2 = 0, n2 = type3.length, c; i2 < n2; ++i2) {
-      if ((c = type3[i2]).name === name) {
+  function get(type2, name) {
+    for (var i2 = 0, n2 = type2.length, c; i2 < n2; ++i2) {
+      if ((c = type2[i2]).name === name) {
         return c.value;
       }
     }
   }
-  function set(type3, name, callback) {
-    for (var i2 = 0, n2 = type3.length; i2 < n2; ++i2) {
-      if (type3[i2].name === name) {
-        type3[i2] = noop2, type3 = type3.slice(0, i2).concat(type3.slice(i2 + 1));
+  function set(type2, name, callback) {
+    for (var i2 = 0, n2 = type2.length; i2 < n2; ++i2) {
+      if (type2[i2].name === name) {
+        type2[i2] = noop2, type2 = type2.slice(0, i2).concat(type2.slice(i2 + 1));
         break;
       }
     }
     if (callback != null)
-      type3.push({ name, value: callback });
-    return type3;
+      type2.push({ name, value: callback });
+    return type2;
   }
   var dispatch_default = dispatch;
 
   function merge_default(context) {
     var selection2 = context.selection ? context.selection() : context;
     for (var groups0 = this._groups, groups1 = selection2._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j2 = 0; j2 < m; ++j2) {
-      for (var group0 = groups0[j2], group1 = groups1[j2], n2 = group0.length, merge3 = merges[j2] = new Array(n2), node, i2 = 0; i2 < n2; ++i2) {
+      for (var group0 = groups0[j2], group1 = groups1[j2], n2 = group0.length, merge2 = merges[j2] = new Array(n2), node, i2 = 0; i2 < n2; ++i2) {
         if (node = group0[i2] || group1[i2]) {
-          merge3[i2] = node;
+          merge2[i2] = node;
         }
       }
     }
   }
 
   // node_modules/d3-selection/src/selection/dispatch.js
-  function dispatchEvent(node, type3, params) {
+  function dispatchEvent(node, type2, params) {
     var window2 = window_default(node), event = window2.CustomEvent;
     if (typeof event === "function") {
-      event = new event(type3, params);
+      event = new event(type2, params);
     } else {
       event = window2.document.createEvent("Event");
       if (params)
-        event.initEvent(type3, params.bubbles, params.cancelable), event.detail = params.detail;
+        event.initEvent(type2, params.bubbles, params.cancelable), event.detail = params.detail;
       else
-        event.initEvent(type3, false, false);
+        event.initEvent(type2, false, false);
     }
     node.dispatchEvent(event);
   }
-  function dispatchConstant(type3, params) {
+  function dispatchConstant(type2, params) {
     return function() {
-      return dispatchEvent(this, type3, params);
+      return dispatchEvent(this, type2, params);
     };
   }
-  function dispatchFunction(type3, params) {
+  function dispatchFunction(type2, params) {
     return function() {
-      return dispatchEvent(this, type3, params.apply(this, arguments));
+      return dispatchEvent(this, type2, params.apply(this, arguments));
     };
   }
-  function dispatch_default2(type3, params) {
-    return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type3, params));
+  function dispatch_default2(type2, params) {
+    return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type2, params));
   }
 
   // node_modules/d3-selection/src/selection/iterator.js
     if (node) {
       var svg2 = node.ownerSVGElement || node;
       if (svg2.createSVGPoint) {
-        var point = svg2.createSVGPoint();
-        point.x = event.clientX, point.y = event.clientY;
-        point = point.matrixTransform(node.getScreenCTM().inverse());
-        return [point.x, point.y];
+        var point2 = svg2.createSVGPoint();
+        point2.x = event.clientX, point2.y = event.clientY;
+        point2 = point2.matrixTransform(node.getScreenCTM().inverse());
+        return [point2.x, point2.y];
       }
       if (node.getBoundingClientRect) {
         var rect = node.getBoundingClientRect();
   var constant_default2 = (x) => () => x;
 
   // node_modules/d3-drag/src/event.js
-  function DragEvent(type3, {
+  function DragEvent(type2, {
     sourceEvent,
     subject,
     target,
     dispatch: dispatch10
   }) {
     Object.defineProperties(this, {
-      type: { value: type3, enumerable: true, configurable: true },
+      type: { value: type2, enumerable: true, configurable: true },
       sourceEvent: { value: sourceEvent, enumerable: true, configurable: true },
       subject: { value: subject, enumerable: true, configurable: true },
       target: { value: target, enumerable: true, configurable: true },
         return;
       dx = s.x - p[0] || 0;
       dy = s.y - p[1] || 0;
-      return function gesture(type3, event2, touch2) {
+      return function gesture(type2, event2, touch2) {
         var p02 = p, n2;
-        switch (type3) {
+        switch (type2) {
           case "start":
             gestures[identifier] = gesture, n2 = active++;
             break;
             break;
         }
         dispatch10.call(
-          type3,
+          type2,
           that,
-          new DragEvent(type3, {
+          new DragEvent(type2, {
             sourceEvent: event2,
             subject: s,
             target: drag,
       return this.rgb().displayable();
     },
     hex: color_formatHex,
+    // Deprecated! Use color.formatHex.
     formatHex: color_formatHex,
     formatHex8: color_formatHex8,
     formatHsl: color_formatHsl,
       return -0.5 <= this.r && this.r < 255.5 && (-0.5 <= this.g && this.g < 255.5) && (-0.5 <= this.b && this.b < 255.5) && (0 <= this.opacity && this.opacity <= 1);
     },
     hex: rgb_formatHex,
+    // Deprecated! Use color.formatHex.
     formatHex: rgb_formatHex,
     formatHex8: rgb_formatHex8,
     formatRgb: rgb_formatRgb,
 
   // node_modules/d3-interpolate/src/date.js
   function date_default(a, b) {
-    var d = new Date();
+    var d = /* @__PURE__ */ new Date();
     return a = +a, b = +b, function(t) {
       return d.setTime(a * (1 - t) + b * t), d;
     };
     create(node, id2, {
       name,
       index,
+      // For context during callback.
       group,
+      // For context during callback.
       on: emptyOn,
       tween: emptyTween,
       time: timing.time,
     if (transition2._id !== this._id)
       throw new Error();
     for (var groups0 = this._groups, groups1 = transition2._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j2 = 0; j2 < m; ++j2) {
-      for (var group0 = groups0[j2], group1 = groups1[j2], n2 = group0.length, merge3 = merges[j2] = new Array(n2), node, i2 = 0; i2 < n2; ++i2) {
+      for (var group0 = groups0[j2], group1 = groups1[j2], n2 = group0.length, merge2 = merges[j2] = new Array(n2), node, i2 = 0; i2 < n2; ++i2) {
         if (node = group0[i2] || group1[i2]) {
-          merge3[i2] = node;
+          merge2[i2] = node;
         }
       }
     }
   // node_modules/d3-transition/src/selection/transition.js
   var defaultTiming = {
     time: null,
+    // Set on use.
     delay: 0,
     duration: 250,
     ease: cubicInOut
   var constant_default4 = (x) => () => x;
 
   // node_modules/d3-zoom/src/event.js
-  function ZoomEvent(type3, {
+  function ZoomEvent(type2, {
     sourceEvent,
     target,
     transform: transform2,
     dispatch: dispatch10
   }) {
     Object.defineProperties(this, {
-      type: { value: type3, enumerable: true, configurable: true },
+      type: { value: type2, enumerable: true, configurable: true },
       sourceEvent: { value: sourceEvent, enumerable: true, configurable: true },
       target: { value: target, enumerable: true, configurable: true },
       transform: { value: transform2, enumerable: true, configurable: true },
     translate: function(x, y) {
       return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
     },
-    apply: function(point) {
-      return [point[0] * this.k + this.x, point[1] * this.k + this.y];
+    apply: function(point2) {
+      return [point2[0] * this.k + this.x, point2[1] * this.k + this.y];
     },
     applyX: function(x) {
       return x * this.k + this.x;
     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, point, event) {
+    zoom.transform = function(collection, transform2, point2, event) {
       var selection2 = collection.selection ? collection.selection() : collection;
       selection2.property("__zoom", defaultTransform);
       if (collection !== selection2) {
-        schedule(collection, transform2, point, event);
+        schedule(collection, transform2, point2, 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, point, event) {
+    function schedule(transition2, transform2, point2, 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, g = gesture(that, args).event(event), e = extent.apply(that, args), p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point, w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a = that.__zoom, b = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i2 = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
+        var that = this, args = arguments, g = gesture(that, args).event(event), e = extent.apply(that, args), p = point2 == null ? centroid(e) : typeof point2 === "function" ? point2.apply(that, args) : point2, w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a = that.__zoom, b = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i2 = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
         return function(t) {
           if (t === 1)
             t = b;
         }
         return this;
       },
-      emit: function(type3) {
+      emit: function(type2) {
         var d = select_default2(this.that).datum();
         listeners.call(
-          type3,
+          type2,
           this.that,
-          new ZoomEvent(type3, {
+          new ZoomEvent(type2, {
             sourceEvent: this.sourceEvent,
             target: zoom,
-            type: type3,
+            type: type2,
             transform: this.that.__zoom,
             dispatch: listeners
           }),
     var x = 0;
     var y = 0;
     var clipExtent = [[0, 0], [0, 0]];
-    function projection2(point) {
-      point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
-      return [point[0] * k + x, y - point[1] * k];
+    function projection2(point2) {
+      point2 = project(point2[0] * Math.PI / 180, point2[1] * Math.PI / 180);
+      return [point2[0] * k + x, y - point2[1] * k];
     }
-    projection2.invert = function(point) {
-      point = project.invert((point[0] - x) / k, (y - point[1]) / k);
-      return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
+    projection2.invert = function(point2) {
+      point2 = project.invert((point2[0] - x) / k, (y - point2[1]) / k);
+      return point2 && [point2[0] * 180 / Math.PI, point2[1] * 180 / Math.PI];
     };
     projection2.scale = function(_) {
       if (!arguments.length)
   // modules/core/file_fetcher.js
   var import_vparse = __toESM(require_vparse());
 
+  // config/id.js
+  var presetsCdnUrl = "https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@{presets_version}/";
+  var ociCdnUrl = "https://cdn.jsdelivr.net/npm/osm-community-index@{version}/";
+  var wmfSitematrixCdnUrl = "https://cdn.jsdelivr.net/npm/wmf-sitematrix@{version}/";
+  var nsiCdnUrl = "https://cdn.jsdelivr.net/npm/name-suggestion-index@{version}/";
+  var defaultOsmApiConnections = {
+    live: {
+      url: "https://www.openstreetmap.org",
+      client_id: "0tmNTmd0Jo1dQp4AUmMBLtGiD9YpMuXzHefitcuVStc",
+      client_secret: "BTlNrNxIPitHdL4sP2clHw5KLoee9aKkA7dQbc0Bj7Q"
+    },
+    dev: {
+      url: "https://api06.dev.openstreetmap.org",
+      client_id: "Ee1wWJ6UlpERbF6BfTNOpwn0R8k_06mvMXdDUkeHMgw",
+      client_secret: "OnfWFC-JkZNHyYdr_viNn_h_RTZXRslKcUxllOXqf5g"
+    }
+  };
+  var osmApiConnections = [];
+  if (false) {
+    osmApiConnections.push({
+      url: null,
+      client_id: null,
+      client_secret: null
+    });
+  } else if (false) {
+    osmApiConnections.push(defaultOsmApiConnections[null]);
+  } else {
+    osmApiConnections.push(defaultOsmApiConnections.live);
+    osmApiConnections.push(defaultOsmApiConnections.dev);
+  }
+  var taginfoApiUrl = "https://taginfo.openstreetmap.org/api/4/";
+  var nominatimApiUrl = "https://nominatim.openstreetmap.org/";
+
   // package.json
   var package_default = {
     name: "iD",
-    version: "2.22.0",
+    version: "2.26.1",
     description: "A friendly editor for OpenStreetMap",
     main: "dist/iD.min.js",
     repository: "github:openstreetmap/iD",
       build: "run-s build:css build:data build:js",
       "build:css": "node scripts/build_css.js",
       "build:data": "shx mkdir -p dist/data && node scripts/build_data.js",
-      "build:stats": "esbuild-visualizer --metadata dist/esbuild.json --exclude *.png --filename docs/statistics.html",
+      "build:stats": "node config/esbuild.config.mjs --stats && esbuild-visualizer --metadata dist/esbuild.json --exclude *.png --filename docs/statistics.html && shx rm dist/esbuild.json",
       "build:js": "node config/esbuild.config.mjs",
       "build:js:watch": "node config/esbuild.config.mjs --watch",
       clean: "shx rm -f dist/esbuild.json dist/*.js dist/*.map dist/*.css dist/img/*.svg",
       "dist:svg:maki": 'svg-sprite --symbol --symbol-dest . --shape-id-generator "maki-%s" --symbol-sprite dist/img/maki-sprite.svg node_modules/@mapbox/maki/icons/*.svg',
       "dist:svg:mapillary:signs": "svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/mapillary-sprite.svg node_modules/mapillary_sprite_source/package_signs/*.svg",
       "dist:svg:mapillary:objects": "svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/mapillary-object-sprite.svg node_modules/mapillary_sprite_source/package_objects/*.svg",
-      "dist:svg:temaki": 'svg-sprite --symbol --symbol-dest . --shape-id-generator "temaki-%s" --symbol-sprite dist/img/temaki-sprite.svg node_modules/@ideditor/temaki/icons/*.svg',
+      "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 scripts test/spec modules",
+      lint: "eslint config scripts test/spec modules --ext js,mjs",
       "lint:fix": "eslint scripts test/spec modules --fix",
-      start: "run-s build:js start:server",
+      start: "run-s start:watch",
+      "start:single-build": "run-p build:js start:server",
       "start:watch": "run-p build:js:watch start:server",
       "start:server": "node scripts/server.js",
       test: "npm-run-all -s lint build test:spec",
-      "test:spec": "karma start karma.conf.js",
+      "test:spec": "karma start config/karma.conf.js",
       translations: "node scripts/update_locales.js"
     },
     dependencies: {
-      "@ideditor/country-coder": "~5.0.3",
-      "@ideditor/location-conflation": "~1.0.2",
+      "@rapideditor/country-coder": "~5.2.0",
+      "@rapideditor/location-conflation": "~1.2.0",
       "@mapbox/geojson-area": "^0.2.2",
       "@mapbox/sexagesimal": "1.2.0",
       "@mapbox/vector-tile": "^1.3.1",
-      "@tmcw/togeojson": "^5.2.1",
+      "@tmcw/togeojson": "^5.6.2",
+      "@turf/bbox": "^6.0.0",
       "@turf/bbox-clip": "^6.0.0",
-      "abortcontroller-polyfill": "^1.4.0",
+      "abortcontroller-polyfill": "^1.7.5",
       "aes-js": "^3.1.2",
       "alif-toolkit": "^1.2.9",
-      "core-js-bundle": "^3.19.0",
+      "core-js-bundle": "^3.31.1",
       diacritics: "1.3.0",
       "fast-deep-equal": "~3.1.1",
       "fast-json-stable-stringify": "2.1.0",
       "lodash-es": "~4.17.15",
-      marked: "~4.1.0",
+      marked: "~5.1.1",
       "node-diff3": "~3.1.0",
-      "osm-auth": "~2.0.0",
+      "osm-auth": "~2.1.0",
       pannellum: "2.5.6",
       pbf: "^3.2.1",
       "polygon-clipping": "~0.15.1",
       rbush: "3.0.1",
       "whatwg-fetch": "^3.4.1",
-      "which-polygon": "2.2.0"
+      "which-polygon": "2.2.1"
     },
     devDependencies: {
-      "@fortawesome/fontawesome-svg-core": "~6.2.0",
-      "@fortawesome/free-brands-svg-icons": "~6.2.0",
-      "@fortawesome/free-regular-svg-icons": "~6.2.0",
-      "@fortawesome/free-solid-svg-icons": "~6.2.0",
-      "@ideditor/temaki": "~5.1.0",
-      "@mapbox/maki": "^8.0.0",
-      autoprefixer: "^10.0.1",
-      btoa: "^1.2.1",
-      chai: "^4.3.4",
+      "@fortawesome/fontawesome-svg-core": "~6.4.0",
+      "@fortawesome/free-brands-svg-icons": "~6.4.0",
+      "@fortawesome/free-regular-svg-icons": "~6.4.0",
+      "@fortawesome/free-solid-svg-icons": "~6.4.0",
+      "@rapideditor/temaki": "~5.4.0",
+      "@mapbox/maki": "^8.0.1",
+      "@openstreetmap/id-tagging-schema": "^6.3.0",
+      "@transifex/api": "^5.4.0",
+      autoprefixer: "^10.4.14",
+      chai: "^4.3.7",
       chalk: "^4.1.2",
-      "cldr-core": "^41.0.0",
-      "cldr-localenames-full": "^41.0.0",
+      "cldr-core": "^43.0.0",
+      "cldr-localenames-full": "^43.1.0",
       "concat-files": "^0.1.1",
-      d3: "~7.6.1",
+      d3: "~7.8.5",
+      dotenv: "^16.3.1",
       "editor-layer-index": "github:osmlab/editor-layer-index#gh-pages",
-      esbuild: "^0.15.7",
-      "esbuild-visualizer": "^0.3.1",
-      eslint: "^8.8.0",
+      esbuild: "^0.18.11",
+      "esbuild-visualizer": "^0.4.1",
+      eslint: "^8.44.0",
       "fetch-mock": "^9.11.0",
       gaze: "^1.1.3",
-      glob: "^8.0.3",
+      glob: "^10.3.3",
       happen: "^0.3.2",
       "js-yaml": "^4.0.0",
       "json-stringify-pretty-compact": "^3.0.0",
-      karma: "^6.3.5",
-      "karma-chrome-launcher": "^3.1.0",
+      karma: "^6.4.2",
+      "karma-chrome-launcher": "^3.2.0",
       "karma-coverage": "2.1.1",
       "karma-mocha": "^2.0.1",
       "karma-remap-istanbul": "^0.6.0",
       mapillary_sprite_source: "^1.8.0",
       "mapillary-js": "4.1.1",
-      minimist: "^1.2.3",
-      mocha: "^10.0.0",
+      minimist: "^1.2.8",
+      mocha: "^10.2.0",
       "name-suggestion-index": "~6.0",
-      "node-fetch": "^2.6.1",
+      "node-fetch": "^2.6.11",
       "npm-run-all": "^4.0.0",
-      "osm-community-index": "~5.2.0",
-      postcss: "^8.1.1",
+      "osm-community-index": "~5.5.3",
+      postcss: "^8.4.25",
       "postcss-selector-prepend": "^0.5.0",
       shelljs: "^0.8.0",
       shx: "^0.3.0",
       "sinon-chai": "^3.7.0",
       smash: "0.0",
       "static-server": "^2.2.1",
-      "svg-sprite": "1.5.4",
+      "svg-sprite": "2.0.2",
       vparse: "~1.1.0"
     },
     engines: {
   function coreFileFetcher() {
     const ociVersion = package_default.dependencies["osm-community-index"] || package_default.devDependencies["osm-community-index"];
     const v = (0, import_vparse.default)(ociVersion);
-    const vMinor = `${v.major}.${v.minor}`;
+    const ociVersionMinor = `${v.major}.${v.minor}`;
+    const presetsVersion = package_default.devDependencies["@openstreetmap/id-tagging-schema"];
     let _this = {};
     let _inflight4 = {};
     let _fileMap = {
       "address_formats": "data/address_formats.min.json",
-      "deprecated": "https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/deprecated.min.json",
-      "discarded": "https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/discarded.min.json",
       "imagery": "data/imagery.min.json",
       "intro_graph": "data/intro_graph.min.json",
       "keepRight": "data/keepRight.min.json",
       "languages": "data/languages.min.json",
       "locales": "locales/index.min.json",
-      "oci_defaults": `https://cdn.jsdelivr.net/npm/osm-community-index@${vMinor}/dist/defaults.min.json`,
-      "oci_features": `https://cdn.jsdelivr.net/npm/osm-community-index@${vMinor}/dist/featureCollection.min.json`,
-      "oci_resources": `https://cdn.jsdelivr.net/npm/osm-community-index@${vMinor}/dist/resources.min.json`,
-      "preset_categories": "https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/preset_categories.min.json",
-      "preset_defaults": "https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/preset_defaults.min.json",
-      "preset_fields": "https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/fields.min.json",
-      "preset_presets": "https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/presets.min.json",
       "phone_formats": "data/phone_formats.min.json",
       "qa_data": "data/qa_data.min.json",
       "shortcuts": "data/shortcuts.min.json",
       "territory_languages": "data/territory_languages.min.json",
-      "wmf_sitematrix": "https://cdn.jsdelivr.net/npm/wmf-sitematrix@0.1/wikipedia.min.json"
+      "oci_defaults": ociCdnUrl.replace("{version}", ociVersionMinor) + "dist/defaults.min.json",
+      "oci_features": ociCdnUrl.replace("{version}", ociVersionMinor) + "dist/featureCollection.min.json",
+      "oci_resources": ociCdnUrl.replace("{version}", ociVersionMinor) + "dist/resources.min.json",
+      "presets_package": presetsCdnUrl.replace("{presets_version}", presetsVersion) + "package.json",
+      "deprecated": presetsCdnUrl + "dist/deprecated.min.json",
+      "discarded": presetsCdnUrl + "dist/discarded.min.json",
+      "preset_categories": presetsCdnUrl + "dist/preset_categories.min.json",
+      "preset_defaults": presetsCdnUrl + "dist/preset_defaults.min.json",
+      "preset_fields": presetsCdnUrl + "dist/fields.min.json",
+      "preset_presets": presetsCdnUrl + "dist/presets.min.json",
+      "wmf_sitematrix": wmfSitematrixCdnUrl.replace("{version}", "0.1") + "wikipedia.min.json"
     };
     let _cachedData = {};
     _this.cache = () => _cachedData;
       if (!url) {
         return Promise.reject(`Unknown data file for "${which}"`);
       }
+      if (url.includes("{presets_version}")) {
+        return _this.get("presets_package").then((result) => {
+          const presetsVersion2 = result.version;
+          return getUrl(url.replace("{presets_version}", presetsVersion2), which);
+        });
+      } else {
+        return getUrl(url);
+      }
+    };
+    function getUrl(url, which) {
       let prom = _inflight4[url];
       if (!prom) {
         _inflight4[url] = prom = fetch(url).then((response) => {
         });
       }
       return prom;
-    };
+    }
     _this.fileMap = function(val) {
       if (!arguments.length)
         return _fileMap;
     return _this;
   }
 
-  // node_modules/@ideditor/country-coder/dist/country-coder.mjs
+  // node_modules/@rapideditor/country-coder/dist/country-coder.mjs
   var import_which_polygon = __toESM(require_which_polygon(), 1);
-  var type = "FeatureCollection";
-  var features = [
+  var borders_default = { type: "FeatureCollection", features: [
     { type: "Feature", properties: { wikidata: "Q21", nameEn: "England", aliases: ["GB-ENG"], country: "GB", groups: ["Q23666", "Q3336843", "154", "150", "UN"], driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["44"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-6.03913, 51.13217], [-7.74976, 48.64773], [1.17405, 50.74239], [2.18458, 51.52087], [2.56575, 51.85301], [0.792, 57.56437], [-2.30613, 55.62698], [-2.17058, 55.45916], [-2.6095, 55.28488], [-2.63532, 55.19452], [-3.02906, 55.04606], [-3.09361, 54.94924], [-3.38407, 54.94278], [-4.1819, 54.57861], [-3.5082, 53.54318], [-3.08228, 53.25526], [-3.03675, 53.25092], [-2.92329, 53.19383], [-2.92022, 53.17685], [-2.98598, 53.15589], [-2.90649, 53.10964], [-2.87469, 53.12337], [-2.89131, 53.09374], [-2.83133, 52.99184], [-2.7251, 52.98389], [-2.72221, 52.92969], [-2.80549, 52.89428], [-2.85897, 52.94487], [-2.92401, 52.93836], [-2.97243, 52.9651], [-3.13576, 52.895], [-3.15744, 52.84947], [-3.16105, 52.79599], [-3.08734, 52.77504], [-3.01001, 52.76636], [-2.95581, 52.71794], [-3.01724, 52.72083], [-3.04398, 52.65435], [-3.13648, 52.58208], [-3.12926, 52.5286], [-3.09746, 52.53077], [-3.08662, 52.54811], [-3.00929, 52.57774], [-2.99701, 52.551], [-3.03603, 52.49969], [-3.13359, 52.49174], [-3.22971, 52.45344], [-3.22754, 52.42526], [-3.04687, 52.34504], [-2.95364, 52.3501], [-2.99701, 52.323], [-3.00785, 52.2753], [-3.09289, 52.20546], [-3.12638, 52.08114], [-2.97111, 51.90456], [-2.8818, 51.93196], [-2.78742, 51.88833], [-2.74277, 51.84367], [-2.66234, 51.83555], [-2.66336, 51.59504], [-3.20563, 51.31615], [-6.03913, 51.13217]]]] } },
     { type: "Feature", properties: { wikidata: "Q22", nameEn: "Scotland", aliases: ["GB-SCT"], country: "GB", groups: ["Q23666", "Q3336843", "154", "150", "UN"], driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["44"] }, geometry: { type: "MultiPolygon", coordinates: [[[[0.792, 57.56437], [-0.3751, 61.32236], [-14.78497, 57.60709], [-6.82333, 55.83103], [-4.69044, 54.3629], [-3.38407, 54.94278], [-3.09361, 54.94924], [-3.02906, 55.04606], [-2.63532, 55.19452], [-2.6095, 55.28488], [-2.17058, 55.45916], [-2.30613, 55.62698], [0.792, 57.56437]]]] } },
     { type: "Feature", properties: { wikidata: "Q25", nameEn: "Wales", aliases: ["GB-WLS"], country: "GB", groups: ["Q23666", "Q3336843", "154", "150", "UN"], driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["44"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-3.5082, 53.54318], [-5.37267, 53.63269], [-6.03913, 51.13217], [-3.20563, 51.31615], [-2.66336, 51.59504], [-2.66234, 51.83555], [-2.74277, 51.84367], [-2.78742, 51.88833], [-2.8818, 51.93196], [-2.97111, 51.90456], [-3.12638, 52.08114], [-3.09289, 52.20546], [-3.00785, 52.2753], [-2.99701, 52.323], [-2.95364, 52.3501], [-3.04687, 52.34504], [-3.22754, 52.42526], [-3.22971, 52.45344], [-3.13359, 52.49174], [-3.03603, 52.49969], [-2.99701, 52.551], [-3.00929, 52.57774], [-3.08662, 52.54811], [-3.09746, 52.53077], [-3.12926, 52.5286], [-3.13648, 52.58208], [-3.04398, 52.65435], [-3.01724, 52.72083], [-2.95581, 52.71794], [-3.01001, 52.76636], [-3.08734, 52.77504], [-3.16105, 52.79599], [-3.15744, 52.84947], [-3.13576, 52.895], [-2.97243, 52.9651], [-2.92401, 52.93836], [-2.85897, 52.94487], [-2.80549, 52.89428], [-2.72221, 52.92969], [-2.7251, 52.98389], [-2.83133, 52.99184], [-2.89131, 53.09374], [-2.87469, 53.12337], [-2.90649, 53.10964], [-2.98598, 53.15589], [-2.92022, 53.17685], [-2.92329, 53.19383], [-3.03675, 53.25092], [-3.08228, 53.25526], [-3.5082, 53.54318]]]] } },
     { type: "Feature", properties: { iso1A2: "CD", iso1A3: "COD", iso1N3: "180", wikidata: "Q974", nameEn: "Democratic Republic of the Congo", aliases: ["ZR"], groups: ["017", "202", "002", "UN"], callingCodes: ["243"] }, geometry: { type: "MultiPolygon", coordinates: [[[[27.44012, 5.07349], [27.09575, 5.22305], [26.93064, 5.13535], [26.85579, 5.03887], [26.74572, 5.10685], [26.48595, 5.04984], [26.13371, 5.25594], [25.86073, 5.19455], [25.53271, 5.37431], [25.34558, 5.29101], [25.31256, 5.03668], [24.71816, 4.90509], [24.46719, 5.0915], [23.38847, 4.60013], [22.94817, 4.82392], [22.89094, 4.79321], [22.84691, 4.69887], [22.78526, 4.71423], [22.6928, 4.47285], [22.60915, 4.48821], [22.5431, 4.22041], [22.45504, 4.13039], [22.27682, 4.11347], [22.10721, 4.20723], [21.6405, 4.317], [21.55904, 4.25553], [21.25744, 4.33676], [21.21341, 4.29285], [21.11214, 4.33895], [21.08793, 4.39603], [20.90383, 4.44877], [20.60184, 4.42394], [18.62755, 3.47564], [18.63857, 3.19342], [18.10683, 2.26876], [18.08034, 1.58553], [17.85887, 1.04327], [17.86989, 0.58873], [17.95255, 0.48128], [17.93877, 0.32424], [17.81204, 0.23884], [17.66051, -0.26535], [17.72112, -0.52707], [17.32438, -0.99265], [16.97999, -1.12762], [16.70724, -1.45815], [16.50336, -1.8795], [16.16173, -2.16586], [16.22785, -2.59528], [16.1755, -3.25014], [16.21407, -3.2969], [15.89448, -3.9513], [15.53081, -4.042], [15.48121, -4.22062], [15.41785, -4.28381], [15.32693, -4.27282], [15.25411, -4.31121], [15.1978, -4.32388], [14.83101, -4.80838], [14.67948, -4.92093], [14.5059, -4.84956], [14.41499, -4.8825], [14.37366, -4.56125], [14.47284, -4.42941], [14.3957, -4.36623], [14.40672, -4.28381], [13.9108, -4.50906], [13.81162, -4.41842], [13.71794, -4.44864], [13.70417, -4.72601], [13.50305, -4.77818], [13.41764, -4.89897], [13.11182, -4.5942], [13.09648, -4.63739], [13.11195, -4.67745], [12.8733, -4.74346], [12.70868, -4.95505], [12.63465, -4.94632], [12.60251, -5.01715], [12.46297, -5.09408], [12.49815, -5.14058], [12.51589, -5.1332], [12.53586, -5.14658], [12.53599, -5.1618], [12.52301, -5.17481], [12.52318, -5.74353], [12.26557, -5.74031], [12.20376, -5.76338], [11.95767, -5.94705], [12.42245, -6.07585], [13.04371, -5.87078], [16.55507, -5.85631], [16.96282, -7.21787], [17.5828, -8.13784], [18.33635, -8.00126], [19.33698, -7.99743], [19.5469, -7.00195], [20.30218, -6.98955], [20.31846, -6.91953], [20.61689, -6.90876], [20.56263, -7.28566], [21.79824, -7.29628], [21.84856, -9.59871], [22.19039, -9.94628], [22.32604, -10.76291], [22.17954, -10.85884], [22.25951, -11.24911], [22.54205, -11.05784], [23.16602, -11.10577], [23.45631, -10.946], [23.86868, -11.02856], [24.00027, -10.89356], [24.34528, -11.06816], [24.42612, -11.44975], [25.34069, -11.19707], [25.33058, -11.65767], [26.01777, -11.91488], [26.88687, -12.01868], [27.04351, -11.61312], [27.22541, -11.60323], [27.21025, -11.76157], [27.59932, -12.22123], [28.33199, -12.41375], [29.01918, -13.41353], [29.60531, -13.21685], [29.65078, -13.41844], [29.81551, -13.44683], [29.8139, -12.14898], [29.48404, -12.23604], [29.4992, -12.43843], [29.18592, -12.37921], [28.48357, -11.87532], [28.37241, -11.57848], [28.65032, -10.65133], [28.62795, -9.92942], [28.68532, -9.78], [28.56208, -9.49122], [28.51627, -9.44726], [28.52636, -9.35379], [28.36562, -9.30091], [28.38526, -9.23393], [28.9711, -8.66935], [28.88917, -8.4831], [30.79243, -8.27382], [30.2567, -7.14121], [29.52552, -6.2731], [29.43673, -4.44845], [29.23708, -3.75856], [29.21463, -3.3514], [29.25633, -3.05471], [29.17258, -2.99385], [29.16037, -2.95457], [29.09797, -2.91935], [29.09119, -2.87871], [29.0505, -2.81774], [29.00404, -2.81978], [29.00167, -2.78523], [29.04081, -2.7416], [29.00357, -2.70596], [28.94346, -2.69124], [28.89793, -2.66111], [28.90226, -2.62385], [28.89288, -2.55848], [28.87943, -2.55165], [28.86193, -2.53185], [28.86209, -2.5231], [28.87497, -2.50887], [28.88846, -2.50493], [28.89342, -2.49017], [28.89132, -2.47557], [28.86846, -2.44866], [28.86826, -2.41888], [28.89601, -2.37321], [28.95642, -2.37321], [29.00051, -2.29001], [29.105, -2.27043], [29.17562, -2.12278], [29.11847, -1.90576], [29.24458, -1.69663], [29.24323, -1.66826], [29.36322, -1.50887], [29.45038, -1.5054], [29.53062, -1.40499], [29.59061, -1.39016], [29.58388, -0.89821], [29.63006, -0.8997], [29.62708, -0.71055], [29.67176, -0.55714], [29.67474, -0.47969], [29.65091, -0.46777], [29.72687, -0.08051], [29.7224, 0.07291], [29.77454, 0.16675], [29.81922, 0.16824], [29.87284, 0.39166], [29.97413, 0.52124], [29.95477, 0.64486], [29.98307, 0.84295], [30.1484, 0.89805], [30.22139, 0.99635], [30.24671, 1.14974], [30.48503, 1.21675], [31.30127, 2.11006], [31.28042, 2.17853], [31.20148, 2.2217], [31.1985, 2.29462], [31.12104, 2.27676], [31.07934, 2.30207], [31.06593, 2.35862], [30.96911, 2.41071], [30.91102, 2.33332], [30.83059, 2.42559], [30.74271, 2.43601], [30.75612, 2.5863], [30.8857, 2.83923], [30.8574, 2.9508], [30.77101, 3.04897], [30.84251, 3.26908], [30.93486, 3.40737], [30.94081, 3.50847], [30.85153, 3.48867], [30.85997, 3.5743], [30.80713, 3.60506], [30.78512, 3.67097], [30.56277, 3.62703], [30.57378, 3.74567], [30.55396, 3.84451], [30.47691, 3.83353], [30.27658, 3.95653], [30.22374, 3.93896], [30.1621, 4.10586], [30.06964, 4.13221], [29.79666, 4.37809], [29.82087, 4.56246], [29.49726, 4.7007], [29.43341, 4.50101], [29.22207, 4.34297], [29.03054, 4.48784], [28.8126, 4.48784], [28.6651, 4.42638], [28.20719, 4.35614], [27.79551, 4.59976], [27.76469, 4.79284], [27.65462, 4.89375], [27.56656, 4.89375], [27.44012, 5.07349]]]] } },
     { type: "Feature", properties: { iso1A2: "CF", iso1A3: "CAF", iso1N3: "140", wikidata: "Q929", nameEn: "Central African Republic", groups: ["017", "202", "002", "UN"], callingCodes: ["236"] }, geometry: { type: "MultiPolygon", coordinates: [[[[22.87758, 10.91915], [22.45889, 11.00246], [21.72139, 10.64136], [21.71479, 10.29932], [21.63553, 10.217], [21.52766, 10.2105], [21.34934, 9.95907], [21.26348, 9.97642], [20.82979, 9.44696], [20.36748, 9.11019], [19.06421, 9.00367], [18.86388, 8.87971], [19.11044, 8.68172], [18.79783, 8.25929], [18.67455, 8.22226], [18.62612, 8.14163], [18.64153, 8.08714], [18.6085, 8.05009], [18.02731, 8.01085], [17.93926, 7.95853], [17.67288, 7.98905], [16.8143, 7.53971], [16.6668, 7.67281], [16.658, 7.75353], [16.59415, 7.76444], [16.58315, 7.88657], [16.41583, 7.77971], [16.40703, 7.68809], [15.79942, 7.44149], [15.73118, 7.52006], [15.49743, 7.52179], [15.23397, 7.25135], [15.04717, 6.77085], [14.96311, 6.75693], [14.79966, 6.39043], [14.80122, 6.34866], [14.74206, 6.26356], [14.56149, 6.18928], [14.43073, 6.08867], [14.42917, 6.00508], [14.49455, 5.91683], [14.60974, 5.91838], [14.62375, 5.70466], [14.58951, 5.59777], [14.62531, 5.51411], [14.52724, 5.28319], [14.57083, 5.23979], [14.65489, 5.21343], [14.73383, 4.6135], [15.00825, 4.41458], [15.08609, 4.30282], [15.10644, 4.1362], [15.17482, 4.05131], [15.07686, 4.01805], [15.73522, 3.24348], [15.77725, 3.26835], [16.05449, 3.02306], [16.08252, 2.45708], [16.19357, 2.21537], [16.50126, 2.84739], [16.46701, 2.92512], [16.57598, 3.47999], [16.68283, 3.54257], [17.01746, 3.55136], [17.35649, 3.63045], [17.46876, 3.70515], [17.60966, 3.63705], [17.83421, 3.61068], [17.85842, 3.53378], [18.05656, 3.56893], [18.14902, 3.54476], [18.17323, 3.47665], [18.24148, 3.50302], [18.2723, 3.57992], [18.39558, 3.58212], [18.49245, 3.63924], [18.58711, 3.49423], [18.62755, 3.47564], [20.60184, 4.42394], [20.90383, 4.44877], [21.08793, 4.39603], [21.11214, 4.33895], [21.21341, 4.29285], [21.25744, 4.33676], [21.55904, 4.25553], [21.6405, 4.317], [22.10721, 4.20723], [22.27682, 4.11347], [22.45504, 4.13039], [22.5431, 4.22041], [22.60915, 4.48821], [22.6928, 4.47285], [22.78526, 4.71423], [22.84691, 4.69887], [22.89094, 4.79321], [22.94817, 4.82392], [23.38847, 4.60013], [24.46719, 5.0915], [24.71816, 4.90509], [25.31256, 5.03668], [25.34558, 5.29101], [25.53271, 5.37431], [25.86073, 5.19455], [26.13371, 5.25594], [26.48595, 5.04984], [26.74572, 5.10685], [26.85579, 5.03887], [26.93064, 5.13535], [27.09575, 5.22305], [27.44012, 5.07349], [27.26886, 5.25876], [27.23017, 5.37167], [27.28621, 5.56382], [27.22705, 5.62889], [27.22705, 5.71254], [26.51721, 6.09655], [26.58259, 6.1987], [26.32729, 6.36272], [26.38022, 6.63493], [25.90076, 7.09549], [25.37461, 7.33024], [25.35281, 7.42595], [25.20337, 7.50312], [25.20649, 7.61115], [25.29214, 7.66675], [25.25319, 7.8487], [24.98855, 7.96588], [24.85156, 8.16933], [24.35965, 8.26177], [24.13238, 8.36959], [24.25691, 8.69288], [23.51905, 8.71749], [23.59065, 8.99743], [23.44744, 8.99128], [23.4848, 9.16959], [23.56263, 9.19418], [23.64358, 9.28637], [23.64981, 9.44303], [23.62179, 9.53823], [23.69155, 9.67566], [23.67164, 9.86923], [23.3128, 10.45214], [23.02221, 10.69235], [22.87758, 10.91915]]]] } },
     { type: "Feature", properties: { iso1A2: "CG", iso1A3: "COG", iso1N3: "178", wikidata: "Q971", nameEn: "Republic of the Congo", groups: ["017", "202", "002", "UN"], callingCodes: ["242"] }, geometry: { type: "MultiPolygon", coordinates: [[[[18.62755, 3.47564], [18.58711, 3.49423], [18.49245, 3.63924], [18.39558, 3.58212], [18.2723, 3.57992], [18.24148, 3.50302], [18.17323, 3.47665], [18.14902, 3.54476], [18.05656, 3.56893], [17.85842, 3.53378], [17.83421, 3.61068], [17.60966, 3.63705], [17.46876, 3.70515], [17.35649, 3.63045], [17.01746, 3.55136], [16.68283, 3.54257], [16.57598, 3.47999], [16.46701, 2.92512], [16.50126, 2.84739], [16.19357, 2.21537], [16.15568, 2.18955], [16.08563, 2.19733], [16.05294, 1.9811], [16.14634, 1.70259], [16.02647, 1.65591], [16.02959, 1.76483], [15.48942, 1.98265], [15.34776, 1.91264], [15.22634, 2.03243], [15.00996, 1.98887], [14.61145, 2.17866], [13.29457, 2.16106], [13.13461, 1.57238], [13.25447, 1.32339], [13.15519, 1.23368], [13.89582, 1.4261], [14.25186, 1.39842], [14.48179, 0.9152], [14.26066, 0.57255], [14.10909, 0.58563], [13.88648, 0.26652], [13.90632, -0.2287], [14.06862, -0.20826], [14.2165, -0.38261], [14.41887, -0.44799], [14.52569, -0.57818], [14.41838, -1.89412], [14.25932, -1.97624], [14.23518, -2.15671], [14.16202, -2.23916], [14.23829, -2.33715], [14.10442, -2.49268], [13.85846, -2.46935], [13.92073, -2.35581], [13.75884, -2.09293], [13.47977, -2.43224], [13.02759, -2.33098], [12.82172, -1.91091], [12.61312, -1.8129], [12.44656, -1.92025], [12.47925, -2.32626], [12.04895, -2.41704], [11.96866, -2.33559], [11.74605, -2.39936], [11.57637, -2.33379], [11.64487, -2.61865], [11.5359, -2.85654], [11.64798, -2.81146], [11.80365, -3.00424], [11.70558, -3.0773], [11.70227, -3.17465], [11.96554, -3.30267], [11.8318, -3.5812], [11.92719, -3.62768], [11.87083, -3.71571], [11.68608, -3.68942], [11.57949, -3.52798], [11.48764, -3.51089], [11.22301, -3.69888], [11.12647, -3.94169], [10.75913, -4.39519], [11.50888, -5.33417], [12.00924, -5.02627], [12.16068, -4.90089], [12.20901, -4.75642], [12.25587, -4.79437], [12.32324, -4.78415], [12.40964, -4.60609], [12.64835, -4.55937], [12.76844, -4.38709], [12.87096, -4.40315], [12.91489, -4.47907], [13.09648, -4.63739], [13.11182, -4.5942], [13.41764, -4.89897], [13.50305, -4.77818], [13.70417, -4.72601], [13.71794, -4.44864], [13.81162, -4.41842], [13.9108, -4.50906], [14.40672, -4.28381], [14.3957, -4.36623], [14.47284, -4.42941], [14.37366, -4.56125], [14.41499, -4.8825], [14.5059, -4.84956], [14.67948, -4.92093], [14.83101, -4.80838], [15.1978, -4.32388], [15.25411, -4.31121], [15.32693, -4.27282], [15.41785, -4.28381], [15.48121, -4.22062], [15.53081, -4.042], [15.89448, -3.9513], [16.21407, -3.2969], [16.1755, -3.25014], [16.22785, -2.59528], [16.16173, -2.16586], [16.50336, -1.8795], [16.70724, -1.45815], [16.97999, -1.12762], [17.32438, -0.99265], [17.72112, -0.52707], [17.66051, -0.26535], [17.81204, 0.23884], [17.93877, 0.32424], [17.95255, 0.48128], [17.86989, 0.58873], [17.85887, 1.04327], [18.08034, 1.58553], [18.10683, 2.26876], [18.63857, 3.19342], [18.62755, 3.47564]]]] } },
-    { type: "Feature", properties: { iso1A2: "CH", iso1A3: "CHE", iso1N3: "756", wikidata: "Q39", nameEn: "Switzerland", groups: ["155", "150", "UN"], callingCodes: ["41"] }, geometry: { type: "MultiPolygon", coordinates: [[[[8.72809, 47.69282], [8.72617, 47.69651], [8.73671, 47.7169], [8.70543, 47.73121], [8.74251, 47.75168], [8.71778, 47.76571], [8.68985, 47.75686], [8.68022, 47.78599], [8.65292, 47.80066], [8.64425, 47.76398], [8.62408, 47.7626], [8.61657, 47.79998], [8.56415, 47.80633], [8.56814, 47.78001], [8.48868, 47.77215], [8.45771, 47.7493], [8.44807, 47.72426], [8.40569, 47.69855], [8.4211, 47.68407], [8.40473, 47.67499], [8.41346, 47.66676], [8.42264, 47.66667], [8.44711, 47.65379], [8.4667, 47.65747], [8.46605, 47.64103], [8.49656, 47.64709], [8.5322, 47.64687], [8.52801, 47.66059], [8.56141, 47.67088], [8.57683, 47.66158], [8.6052, 47.67258], [8.61113, 47.66332], [8.62884, 47.65098], [8.62049, 47.63757], [8.60412, 47.63735], [8.61471, 47.64514], [8.60701, 47.65271], [8.59545, 47.64298], [8.60348, 47.61204], [8.57586, 47.59537], [8.55756, 47.62394], [8.51686, 47.63476], [8.50747, 47.61897], [8.45578, 47.60121], [8.46637, 47.58389], [8.48949, 47.588], [8.49431, 47.58107], [8.43235, 47.56617], [8.39477, 47.57826], [8.38273, 47.56608], [8.32735, 47.57133], [8.30277, 47.58607], [8.29524, 47.5919], [8.29722, 47.60603], [8.2824, 47.61225], [8.26313, 47.6103], [8.25863, 47.61571], [8.23809, 47.61204], [8.22577, 47.60385], [8.22011, 47.6181], [8.20617, 47.62141], [8.19378, 47.61636], [8.1652, 47.5945], [8.14947, 47.59558], [8.13823, 47.59147], [8.13662, 47.58432], [8.11543, 47.5841], [8.10395, 47.57918], [8.10002, 47.56504], [8.08557, 47.55768], [8.06663, 47.56374], [8.04383, 47.55443], [8.02136, 47.55096], [8.00113, 47.55616], [7.97581, 47.55493], [7.95682, 47.55789], [7.94494, 47.54511], [7.91251, 47.55031], [7.90673, 47.57674], [7.88664, 47.58854], [7.84412, 47.5841], [7.81901, 47.58798], [7.79486, 47.55691], [7.75261, 47.54599], [7.71961, 47.54219], [7.69642, 47.53297], [7.68101, 47.53232], [7.6656, 47.53752], [7.66174, 47.54554], [7.65083, 47.54662], [7.63338, 47.56256], [7.67655, 47.56435], [7.68904, 47.57133], [7.67115, 47.5871], [7.68486, 47.59601], [7.69385, 47.60099], [7.68229, 47.59905], [7.67395, 47.59212], [7.64599, 47.59695], [7.64213, 47.5944], [7.64309, 47.59151], [7.61929, 47.57683], [7.60459, 47.57869], [7.60523, 47.58519], [7.58945, 47.59017], [7.58386, 47.57536], [7.56684, 47.57785], [7.56548, 47.57617], [7.55689, 47.57232], [7.55652, 47.56779], [7.53634, 47.55553], [7.52831, 47.55347], [7.51723, 47.54578], [7.50873, 47.54546], [7.49691, 47.53821], [7.50588, 47.52856], [7.51904, 47.53515], [7.53199, 47.5284], [7.5229, 47.51644], [7.49804, 47.51798], [7.51076, 47.49651], [7.47534, 47.47932], [7.43356, 47.49712], [7.42923, 47.48628], [7.4583, 47.47216], [7.4462, 47.46264], [7.43088, 47.45846], [7.40308, 47.43638], [7.35603, 47.43432], [7.33526, 47.44186], [7.24669, 47.4205], [7.17026, 47.44312], [7.19583, 47.49455], [7.16249, 47.49025], [7.12781, 47.50371], [7.07425, 47.48863], [7.0231, 47.50522], [6.98425, 47.49432], [7.0024, 47.45264], [6.93953, 47.43388], [6.93744, 47.40714], [6.88542, 47.37262], [6.87959, 47.35335], [7.03125, 47.36996], [7.0564, 47.35134], [7.05305, 47.33304], [6.94316, 47.28747], [6.95108, 47.26428], [6.9508, 47.24338], [6.8489, 47.15933], [6.76788, 47.1208], [6.68823, 47.06616], [6.71531, 47.0494], [6.43341, 46.92703], [6.46456, 46.88865], [6.43216, 46.80336], [6.45209, 46.77502], [6.38351, 46.73171], [6.27135, 46.68251], [6.11084, 46.57649], [6.1567, 46.54402], [6.07269, 46.46244], [6.08427, 46.44305], [6.06407, 46.41676], [6.09926, 46.40768], [6.15016, 46.3778], [6.15985, 46.37721], [6.16987, 46.36759], [6.15738, 46.3491], [6.13876, 46.33844], [6.1198, 46.31157], [6.11697, 46.29547], [6.1013, 46.28512], [6.11926, 46.2634], [6.12446, 46.25059], [6.10071, 46.23772], [6.08563, 46.24651], [6.07072, 46.24085], [6.0633, 46.24583], [6.05029, 46.23518], [6.04602, 46.23127], [6.03342, 46.2383], [6.02461, 46.23313], [5.97542, 46.21525], [5.96515, 46.19638], [5.99573, 46.18587], [5.98846, 46.17046], [5.98188, 46.17392], [5.97508, 46.15863], [5.9641, 46.14412], [5.95781, 46.12925], [5.97893, 46.13303], [5.9871, 46.14499], [6.01791, 46.14228], [6.03614, 46.13712], [6.04564, 46.14031], [6.05203, 46.15191], [6.07491, 46.14879], [6.09199, 46.15191], [6.09926, 46.14373], [6.13397, 46.1406], [6.15305, 46.15194], [6.18116, 46.16187], [6.18871, 46.16644], [6.18707, 46.17999], [6.19552, 46.18401], [6.19807, 46.18369], [6.20539, 46.19163], [6.21114, 46.1927], [6.21273, 46.19409], [6.21603, 46.19507], [6.21844, 46.19837], [6.22222, 46.19888], [6.22175, 46.20045], [6.23544, 46.20714], [6.23913, 46.20511], [6.24821, 46.20531], [6.26007, 46.21165], [6.27694, 46.21566], [6.29663, 46.22688], [6.31041, 46.24417], [6.29474, 46.26221], [6.26749, 46.24745], [6.24952, 46.26255], [6.23775, 46.27822], [6.25137, 46.29014], [6.24826, 46.30175], [6.21981, 46.31304], [6.25432, 46.3632], [6.53358, 46.45431], [6.82312, 46.42661], [6.8024, 46.39171], [6.77152, 46.34784], [6.86052, 46.28512], [6.78968, 46.14058], [6.89321, 46.12548], [6.87868, 46.03855], [6.93862, 46.06502], [7.00946, 45.9944], [7.04151, 45.92435], [7.10685, 45.85653], [7.56343, 45.97421], [7.85949, 45.91485], [7.9049, 45.99945], [7.98881, 45.99867], [8.02906, 46.10331], [8.11383, 46.11577], [8.16866, 46.17817], [8.08814, 46.26692], [8.31162, 46.38044], [8.30648, 46.41587], [8.42464, 46.46367], [8.46317, 46.43712], [8.45032, 46.26869], [8.62242, 46.12112], [8.75697, 46.10395], [8.80778, 46.10085], [8.85617, 46.0748], [8.79414, 46.00913], [8.78585, 45.98973], [8.79362, 45.99207], [8.8319, 45.9879], [8.85121, 45.97239], [8.86688, 45.96135], [8.88904, 45.95465], [8.93649, 45.86775], [8.94372, 45.86587], [8.93504, 45.86245], [8.91129, 45.8388], [8.94737, 45.84285], [8.9621, 45.83707], [8.99663, 45.83466], [9.00324, 45.82055], [9.0298, 45.82127], [9.03279, 45.82865], [9.03793, 45.83548], [9.03505, 45.83976], [9.04059, 45.8464], [9.04546, 45.84968], [9.06642, 45.8761], [9.09065, 45.89906], [8.99257, 45.9698], [9.01618, 46.04928], [9.24503, 46.23616], [9.29226, 46.32717], [9.25502, 46.43743], [9.28136, 46.49685], [9.36128, 46.5081], [9.40487, 46.46621], [9.45936, 46.50873], [9.46117, 46.37481], [9.57015, 46.2958], [9.71273, 46.29266], [9.73086, 46.35071], [9.95249, 46.38045], [10.07055, 46.21668], [10.14439, 46.22992], [10.17862, 46.25626], [10.10506, 46.3372], [10.165, 46.41051], [10.03715, 46.44479], [10.10307, 46.61003], [10.23674, 46.63484], [10.25309, 46.57432], [10.46136, 46.53164], [10.49375, 46.62049], [10.44686, 46.64162], [10.40475, 46.63671], [10.38659, 46.67847], [10.47197, 46.85698], [10.48376, 46.93891], [10.36933, 47.00212], [10.30031, 46.92093], [10.24128, 46.93147], [10.22675, 46.86942], [10.10715, 46.84296], [9.98058, 46.91434], [9.88266, 46.93343], [9.87935, 47.01337], [9.60717, 47.06091], [9.55721, 47.04762], [9.54041, 47.06495], [9.47548, 47.05257], [9.47139, 47.06402], [9.51362, 47.08505], [9.52089, 47.10019], [9.51044, 47.13727], [9.48774, 47.17402], [9.4891, 47.19346], [9.50318, 47.22153], [9.52406, 47.24959], [9.53116, 47.27029], [9.54773, 47.2809], [9.55857, 47.29919], [9.58513, 47.31334], [9.59978, 47.34671], [9.62476, 47.36639], [9.65427, 47.36824], [9.66243, 47.37136], [9.6711, 47.37824], [9.67445, 47.38429], [9.67334, 47.39191], [9.6629, 47.39591], [9.65136, 47.40504], [9.65043, 47.41937], [9.6446, 47.43233], [9.64483, 47.43842], [9.65863, 47.44847], [9.65728, 47.45383], [9.6423, 47.45599], [9.62475, 47.45685], [9.62158, 47.45858], [9.60841, 47.47178], [9.60484, 47.46358], [9.60205, 47.46165], [9.59482, 47.46305], [9.58208, 47.48344], [9.56312, 47.49495], [9.55125, 47.53629], [9.25619, 47.65939], [9.18203, 47.65598], [9.17593, 47.65399], [9.1755, 47.65584], [9.1705, 47.65513], [9.15181, 47.66904], [9.13845, 47.66389], [9.09891, 47.67801], [9.02093, 47.6868], [8.94093, 47.65596], [8.89946, 47.64769], [8.87625, 47.65441], [8.87383, 47.67045], [8.85065, 47.68209], [8.86989, 47.70504], [8.82002, 47.71458], [8.80663, 47.73821], [8.77309, 47.72059], [8.76965, 47.7075], [8.79966, 47.70222], [8.79511, 47.67462], [8.75856, 47.68969], [8.72809, 47.69282]], [[8.95861, 45.96485], [8.96668, 45.98436], [8.97741, 45.98317], [8.97604, 45.96151], [8.95861, 45.96485]], [[8.70847, 47.68904], [8.68985, 47.69552], [8.66837, 47.68437], [8.65769, 47.68928], [8.67508, 47.6979], [8.66416, 47.71367], [8.70237, 47.71453], [8.71773, 47.69088], [8.70847, 47.68904]]]] } },
+    { type: "Feature", geometry: { type: "MultiPolygon", coordinates: [[[[8.72809, 47.69282], [8.72617, 47.69651], [8.73671, 47.7169], [8.70543, 47.73121], [8.74251, 47.75168], [8.71778, 47.76571], [8.68985, 47.75686], [8.68022, 47.78599], [8.65292, 47.80066], [8.64425, 47.76398], [8.62408, 47.7626], [8.61657, 47.79998], [8.56415, 47.80633], [8.56814, 47.78001], [8.48868, 47.77215], [8.45771, 47.7493], [8.44807, 47.72426], [8.40569, 47.69855], [8.4211, 47.68407], [8.40473, 47.67499], [8.41346, 47.66676], [8.42264, 47.66667], [8.44711, 47.65379], [8.4667, 47.65747], [8.46605, 47.64103], [8.49656, 47.64709], [8.5322, 47.64687], [8.52801, 47.66059], [8.56141, 47.67088], [8.57683, 47.66158], [8.6052, 47.67258], [8.61113, 47.66332], [8.62884, 47.65098], [8.62049, 47.63757], [8.60412, 47.63735], [8.61471, 47.64514], [8.60701, 47.65271], [8.59545, 47.64298], [8.60348, 47.61204], [8.57586, 47.59537], [8.55756, 47.62394], [8.51686, 47.63476], [8.50747, 47.61897], [8.45578, 47.60121], [8.46637, 47.58389], [8.48949, 47.588], [8.49431, 47.58107], [8.43235, 47.56617], [8.39477, 47.57826], [8.38273, 47.56608], [8.35512, 47.57014], [8.32735, 47.57133], [8.30277, 47.58607], [8.29524, 47.5919], [8.29722, 47.60603], [8.2824, 47.61225], [8.26313, 47.6103], [8.25863, 47.61571], [8.23809, 47.61204], [8.22577, 47.60385], [8.22011, 47.6181], [8.20617, 47.62141], [8.19378, 47.61636], [8.1652, 47.5945], [8.14947, 47.59558], [8.13823, 47.59147], [8.13662, 47.58432], [8.11543, 47.5841], [8.10395, 47.57918], [8.10002, 47.56504], [8.08557, 47.55768], [8.06663, 47.56374], [8.04383, 47.55443], [8.02136, 47.55096], [8.00113, 47.55616], [7.97581, 47.55493], [7.95682, 47.55789], [7.94494, 47.54511], [7.91251, 47.55031], [7.90673, 47.57674], [7.88664, 47.58854], [7.84412, 47.5841], [7.81901, 47.58798], [7.79486, 47.55691], [7.75261, 47.54599], [7.71961, 47.54219], [7.69642, 47.53297], [7.68101, 47.53232], [7.6656, 47.53752], [7.66174, 47.54554], [7.65083, 47.54662], [7.63338, 47.56256], [7.67655, 47.56435], [7.68904, 47.57133], [7.67115, 47.5871], [7.68486, 47.59601], [7.69385, 47.60099], [7.68229, 47.59905], [7.67395, 47.59212], [7.64599, 47.59695], [7.64213, 47.5944], [7.64309, 47.59151], [7.61929, 47.57683], [7.60459, 47.57869], [7.60523, 47.58519], [7.58945, 47.59017], [7.58386, 47.57536], [7.56684, 47.57785], [7.56548, 47.57617], [7.55689, 47.57232], [7.55652, 47.56779], [7.53634, 47.55553], [7.52831, 47.55347], [7.51723, 47.54578], [7.50873, 47.54546], [7.49691, 47.53821], [7.50588, 47.52856], [7.51904, 47.53515], [7.53199, 47.5284], [7.5229, 47.51644], [7.49804, 47.51798], [7.51076, 47.49651], [7.47534, 47.47932], [7.43356, 47.49712], [7.42923, 47.48628], [7.4583, 47.47216], [7.4462, 47.46264], [7.43088, 47.45846], [7.40308, 47.43638], [7.35603, 47.43432], [7.33526, 47.44186], [7.24669, 47.4205], [7.17026, 47.44312], [7.19583, 47.49455], [7.16249, 47.49025], [7.12781, 47.50371], [7.07425, 47.48863], [7.0231, 47.50522], [6.98425, 47.49432], [7.0024, 47.45264], [6.93953, 47.43388], [6.93744, 47.40714], [6.88542, 47.37262], [6.87959, 47.35335], [7.03125, 47.36996], [7.0564, 47.35134], [7.05305, 47.33304], [6.94316, 47.28747], [6.95108, 47.26428], [6.9508, 47.24338], [6.8489, 47.15933], [6.76788, 47.1208], [6.68823, 47.06616], [6.71531, 47.0494], [6.43341, 46.92703], [6.46456, 46.88865], [6.43216, 46.80336], [6.45209, 46.77502], [6.38351, 46.73171], [6.27135, 46.68251], [6.11084, 46.57649], [6.1567, 46.54402], [6.07269, 46.46244], [6.08427, 46.44305], [6.06407, 46.41676], [6.09926, 46.40768], [6.15016, 46.3778], [6.15985, 46.37721], [6.16987, 46.36759], [6.15738, 46.3491], [6.13876, 46.33844], [6.1198, 46.31157], [6.11697, 46.29547], [6.1013, 46.28512], [6.11926, 46.2634], [6.12446, 46.25059], [6.10071, 46.23772], [6.08563, 46.24651], [6.07072, 46.24085], [6.0633, 46.24583], [6.05029, 46.23518], [6.04602, 46.23127], [6.03342, 46.2383], [6.02461, 46.23313], [5.97542, 46.21525], [5.96515, 46.19638], [5.99573, 46.18587], [5.98846, 46.17046], [5.98188, 46.17392], [5.97508, 46.15863], [5.9641, 46.14412], [5.95781, 46.12925], [5.97893, 46.13303], [5.9871, 46.14499], [6.01791, 46.14228], [6.03614, 46.13712], [6.04564, 46.14031], [6.05203, 46.15191], [6.07491, 46.14879], [6.09199, 46.15191], [6.09926, 46.14373], [6.13397, 46.1406], [6.15305, 46.15194], [6.18116, 46.16187], [6.18871, 46.16644], [6.18707, 46.17999], [6.19552, 46.18401], [6.19807, 46.18369], [6.20539, 46.19163], [6.21114, 46.1927], [6.21273, 46.19409], [6.21603, 46.19507], [6.21844, 46.19837], [6.22222, 46.19888], [6.22175, 46.20045], [6.23544, 46.20714], [6.23913, 46.20511], [6.24821, 46.20531], [6.26007, 46.21165], [6.27694, 46.21566], [6.29663, 46.22688], [6.31041, 46.24417], [6.29474, 46.26221], [6.26749, 46.24745], [6.24952, 46.26255], [6.23775, 46.27822], [6.25137, 46.29014], [6.24826, 46.30175], [6.21981, 46.31304], [6.25432, 46.3632], [6.53358, 46.45431], [6.82312, 46.42661], [6.8024, 46.39171], [6.77152, 46.34784], [6.86052, 46.28512], [6.78968, 46.14058], [6.89321, 46.12548], [6.87868, 46.03855], [6.93862, 46.06502], [7.00946, 45.9944], [7.04151, 45.92435], [7.10685, 45.85653], [7.56343, 45.97421], [7.85949, 45.91485], [7.9049, 45.99945], [7.98881, 45.99867], [8.02906, 46.10331], [8.11383, 46.11577], [8.16866, 46.17817], [8.08814, 46.26692], [8.31162, 46.38044], [8.30648, 46.41587], [8.42464, 46.46367], [8.46317, 46.43712], [8.45032, 46.26869], [8.62242, 46.12112], [8.75697, 46.10395], [8.80778, 46.10085], [8.85617, 46.0748], [8.79414, 46.00913], [8.78585, 45.98973], [8.79362, 45.99207], [8.8319, 45.9879], [8.85121, 45.97239], [8.86688, 45.96135], [8.88904, 45.95465], [8.93649, 45.86775], [8.94372, 45.86587], [8.93504, 45.86245], [8.91129, 45.8388], [8.94737, 45.84285], [8.9621, 45.83707], [8.99663, 45.83466], [9.00324, 45.82055], [9.0298, 45.82127], [9.03279, 45.82865], [9.03793, 45.83548], [9.03505, 45.83976], [9.04059, 45.8464], [9.04546, 45.84968], [9.06642, 45.8761], [9.09065, 45.89906], [8.99257, 45.9698], [9.01618, 46.04928], [9.24503, 46.23616], [9.29226, 46.32717], [9.25502, 46.43743], [9.28136, 46.49685], [9.36128, 46.5081], [9.40487, 46.46621], [9.45936, 46.50873], [9.46117, 46.37481], [9.57015, 46.2958], [9.71273, 46.29266], [9.73086, 46.35071], [9.95249, 46.38045], [10.07055, 46.21668], [10.14439, 46.22992], [10.17862, 46.25626], [10.10506, 46.3372], [10.165, 46.41051], [10.03715, 46.44479], [10.10307, 46.61003], [10.23674, 46.63484], [10.25309, 46.57432], [10.46136, 46.53164], [10.49375, 46.62049], [10.44686, 46.64162], [10.40475, 46.63671], [10.38659, 46.67847], [10.47197, 46.85698], [10.48376, 46.93891], [10.36933, 47.00212], [10.30031, 46.92093], [10.24128, 46.93147], [10.22675, 46.86942], [10.10715, 46.84296], [9.98058, 46.91434], [9.88266, 46.93343], [9.87935, 47.01337], [9.60717, 47.06091], [9.55721, 47.04762], [9.54041, 47.06495], [9.47548, 47.05257], [9.47139, 47.06402], [9.51362, 47.08505], [9.52089, 47.10019], [9.51044, 47.13727], [9.48774, 47.17402], [9.4891, 47.19346], [9.50318, 47.22153], [9.52406, 47.24959], [9.53116, 47.27029], [9.54773, 47.2809], [9.55857, 47.29919], [9.58513, 47.31334], [9.59978, 47.34671], [9.62476, 47.36639], [9.65427, 47.36824], [9.66243, 47.37136], [9.6711, 47.37824], [9.67445, 47.38429], [9.67334, 47.39191], [9.6629, 47.39591], [9.65136, 47.40504], [9.65043, 47.41937], [9.6446, 47.43233], [9.64483, 47.43842], [9.65863, 47.44847], [9.65728, 47.45383], [9.6423, 47.45599], [9.62475, 47.45685], [9.62158, 47.45858], [9.60841, 47.47178], [9.60484, 47.46358], [9.60205, 47.46165], [9.59482, 47.46305], [9.58208, 47.48344], [9.56312, 47.49495], [9.55125, 47.53629], [9.25619, 47.65939], [9.18203, 47.65598], [9.17593, 47.65399], [9.1755, 47.65584], [9.1705, 47.65513], [9.15181, 47.66904], [9.13845, 47.66389], [9.09891, 47.67801], [9.02093, 47.6868], [8.94093, 47.65596], [8.89946, 47.64769], [8.87625, 47.65441], [8.87383, 47.67045], [8.85065, 47.68209], [8.86989, 47.70504], [8.82002, 47.71458], [8.80663, 47.73821], [8.77309, 47.72059], [8.76965, 47.7075], [8.79966, 47.70222], [8.79511, 47.67462], [8.75856, 47.68969], [8.72809, 47.69282]], [[8.95861, 45.96485], [8.96668, 45.98436], [8.97741, 45.98317], [8.97604, 45.96151], [8.95861, 45.96485]], [[8.70847, 47.68904], [8.68985, 47.69552], [8.66837, 47.68437], [8.65769, 47.68928], [8.67508, 47.6979], [8.66416, 47.71367], [8.70237, 47.71453], [8.71773, 47.69088], [8.70847, 47.68904]]]] }, properties: { iso1A2: "CH", iso1A3: "CHE", iso1N3: "756", wikidata: "Q39", nameEn: "Switzerland", groups: ["155", "150", "UN"], callingCodes: ["41"] } },
     { type: "Feature", properties: { iso1A2: "CI", iso1A3: "CIV", iso1N3: "384", wikidata: "Q1008", nameEn: "C\xF4te d'Ivoire", groups: ["011", "202", "002", "UN"], callingCodes: ["225"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-7.52774, 3.7105], [-3.34019, 4.17519], [-3.10675, 5.08515], [-3.11073, 5.12675], [-3.063, 5.13665], [-2.96554, 5.10397], [-2.95261, 5.12477], [-2.75502, 5.10657], [-2.73074, 5.1364], [-2.77625, 5.34621], [-2.72737, 5.34789], [-2.76614, 5.60963], [-2.85378, 5.65156], [-2.93132, 5.62137], [-2.96671, 5.6415], [-2.95323, 5.71865], [-3.01896, 5.71697], [-3.25999, 6.62521], [-3.21954, 6.74407], [-3.23327, 6.81744], [-2.95438, 7.23737], [-2.97822, 7.27165], [-2.92339, 7.60847], [-2.79467, 7.86002], [-2.78395, 7.94974], [-2.74819, 7.92613], [-2.67787, 8.02055], [-2.61232, 8.02645], [-2.62901, 8.11495], [-2.49037, 8.20872], [-2.58243, 8.7789], [-2.66357, 9.01771], [-2.77799, 9.04949], [-2.69814, 9.22717], [-2.68802, 9.49343], [-2.76494, 9.40778], [-2.93012, 9.57403], [-3.00765, 9.74019], [-3.16609, 9.85147], [-3.19306, 9.93781], [-3.27228, 9.84981], [-3.31779, 9.91125], [-3.69703, 9.94279], [-4.25999, 9.76012], [-4.31392, 9.60062], [-4.6426, 9.70696], [-4.96621, 9.89132], [-4.96453, 9.99923], [-5.12465, 10.29788], [-5.39602, 10.2929], [-5.51058, 10.43177], [-5.65135, 10.46767], [-5.78124, 10.43952], [-5.99478, 10.19694], [-6.18851, 10.24244], [-6.1731, 10.46983], [-6.24795, 10.74248], [-6.325, 10.68624], [-6.40646, 10.69922], [-6.42847, 10.5694], [-6.52974, 10.59104], [-6.63541, 10.66893], [-6.68164, 10.35074], [-6.93921, 10.35291], [-7.01186, 10.25111], [-6.97444, 10.21644], [-7.00966, 10.15794], [-7.0603, 10.14711], [-7.13331, 10.24877], [-7.3707, 10.24677], [-7.44555, 10.44602], [-7.52261, 10.4655], [-7.54462, 10.40921], [-7.63048, 10.46334], [-7.92107, 10.15577], [-7.97971, 10.17117], [-8.01225, 10.1021], [-8.11921, 10.04577], [-8.15652, 9.94288], [-8.09434, 9.86936], [-8.14657, 9.55062], [-8.03463, 9.39604], [-7.85056, 9.41812], [-7.90777, 9.20456], [-7.73862, 9.08422], [-7.92518, 8.99332], [-7.95503, 8.81146], [-7.69882, 8.66148], [-7.65653, 8.36873], [-7.92518, 8.50652], [-8.22991, 8.48438], [-8.2411, 8.24196], [-8.062, 8.16071], [-7.98675, 8.20134], [-7.99919, 8.11023], [-7.94695, 8.00925], [-8.06449, 8.04989], [-8.13414, 7.87991], [-8.09931, 7.78626], [-8.21374, 7.54466], [-8.4003, 7.6285], [-8.47114, 7.55676], [-8.41935, 7.51203], [-8.37458, 7.25794], [-8.29249, 7.1691], [-8.31736, 6.82837], [-8.59456, 6.50612], [-8.48652, 6.43797], [-8.45666, 6.49977], [-8.38453, 6.35887], [-8.3298, 6.36381], [-8.17557, 6.28222], [-8.00642, 6.31684], [-7.90692, 6.27728], [-7.83478, 6.20309], [-7.8497, 6.08932], [-7.79747, 6.07696], [-7.78254, 5.99037], [-7.70294, 5.90625], [-7.67309, 5.94337], [-7.48155, 5.80974], [-7.46165, 5.84934], [-7.43677, 5.84687], [-7.43926, 5.74787], [-7.37209, 5.61173], [-7.43428, 5.42355], [-7.36463, 5.32944], [-7.46165, 5.26256], [-7.48901, 5.14118], [-7.55369, 5.08667], [-7.53876, 4.94294], [-7.59349, 4.8909], [-7.53259, 4.35145], [-7.52774, 3.7105]]]] } },
     { type: "Feature", properties: { iso1A2: "CK", iso1A3: "COK", iso1N3: "184", wikidata: "Q26988", nameEn: "Cook Islands", country: "NZ", groups: ["061", "009", "UN"], driveSide: "left", callingCodes: ["682"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-168.15106, -10.26955], [-156.45576, -31.75456], [-156.48634, -15.52824], [-156.50903, -7.4975], [-168.15106, -10.26955]]]] } },
     { type: "Feature", properties: { iso1A2: "CL", iso1A3: "CHL", iso1N3: "152", wikidata: "Q298", nameEn: "Chile", groups: ["005", "419", "019", "UN"], callingCodes: ["56"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-68.60702, -52.65781], [-68.41683, -52.33516], [-69.97824, -52.00845], [-71.99889, -51.98018], [-72.33873, -51.59954], [-72.31343, -50.58411], [-73.15765, -50.78337], [-73.55259, -49.92488], [-73.45156, -49.79461], [-73.09655, -49.14342], [-72.56894, -48.81116], [-72.54042, -48.52392], [-72.27662, -48.28727], [-72.50478, -47.80586], [-71.94152, -47.13595], [-71.68577, -46.55385], [-71.75614, -45.61611], [-71.35687, -45.22075], [-72.06985, -44.81756], [-71.26418, -44.75684], [-71.16436, -44.46244], [-71.81318, -44.38097], [-71.64206, -43.64774], [-72.14828, -42.85321], [-72.15541, -42.15941], [-71.74901, -42.11711], [-71.92726, -40.72714], [-71.37826, -38.91474], [-70.89532, -38.6923], [-71.24279, -37.20264], [-70.95047, -36.4321], [-70.38008, -36.02375], [-70.49416, -35.24145], [-69.87386, -34.13344], [-69.88099, -33.34489], [-70.55832, -31.51559], [-70.14479, -30.36595], [-69.8596, -30.26131], [-69.99507, -29.28351], [-69.80969, -29.07185], [-69.66709, -28.44055], [-69.22504, -27.95042], [-68.77586, -27.16029], [-68.43363, -27.08414], [-68.27677, -26.90626], [-68.59048, -26.49861], [-68.56909, -26.28146], [-68.38372, -26.15353], [-68.57622, -25.32505], [-68.38372, -25.08636], [-68.56909, -24.69831], [-68.24825, -24.42596], [-67.33563, -24.04237], [-66.99632, -22.99839], [-67.18382, -22.81525], [-67.54284, -22.89771], [-67.85114, -22.87076], [-68.18816, -21.28614], [-68.40403, -20.94562], [-68.53957, -20.91542], [-68.55383, -20.7355], [-68.44023, -20.62701], [-68.7276, -20.46178], [-68.74273, -20.08817], [-68.57132, -20.03134], [-68.54611, -19.84651], [-68.66761, -19.72118], [-68.41218, -19.40499], [-68.61989, -19.27584], [-68.80602, -19.08355], [-68.87082, -19.06003], [-68.94987, -18.93302], [-69.07432, -18.28259], [-69.14807, -18.16893], [-69.07496, -18.03715], [-69.28671, -17.94844], [-69.34126, -17.72753], [-69.46623, -17.60518], [-69.46897, -17.4988], [-69.66483, -17.65083], [-69.79087, -17.65563], [-69.82868, -17.72048], [-69.75305, -17.94605], [-69.81607, -18.12582], [-69.96732, -18.25992], [-70.16394, -18.31737], [-70.31267, -18.31258], [-70.378, -18.3495], [-70.59118, -18.35072], [-113.52687, -26.52828], [-68.11646, -58.14883], [-66.07313, -55.19618], [-67.11046, -54.94199], [-67.46182, -54.92205], [-68.01394, -54.8753], [-68.60733, -54.9125], [-68.60702, -52.65781]]]] } },
     { type: "Feature", properties: { iso1A2: "HU", iso1A3: "HUN", iso1N3: "348", wikidata: "Q28", nameEn: "Hungary", groups: ["EU", "151", "150", "UN"], callingCodes: ["36"] }, geometry: { type: "MultiPolygon", coordinates: [[[[21.72525, 48.34628], [21.67134, 48.3989], [21.6068, 48.50365], [21.44063, 48.58456], [21.11516, 48.49546], [20.83248, 48.5824], [20.5215, 48.53336], [20.29943, 48.26104], [20.24312, 48.2784], [19.92452, 48.1283], [19.63338, 48.25006], [19.52489, 48.19791], [19.47957, 48.09437], [19.28182, 48.08336], [19.23924, 48.0595], [19.01952, 48.07052], [18.82176, 48.04206], [18.76134, 47.97499], [18.76821, 47.87469], [18.8506, 47.82308], [18.74074, 47.8157], [18.66521, 47.76772], [18.56496, 47.76588], [18.29305, 47.73541], [18.02938, 47.75665], [17.71215, 47.7548], [17.23699, 48.02094], [17.16001, 48.00636], [17.09786, 47.97336], [17.11022, 47.92461], [17.08275, 47.87719], [17.00997, 47.86245], [17.07039, 47.81129], [17.05048, 47.79377], [17.08893, 47.70928], [16.87538, 47.68895], [16.86509, 47.72268], [16.82938, 47.68432], [16.7511, 47.67878], [16.72089, 47.73469], [16.65679, 47.74197], [16.61183, 47.76171], [16.54779, 47.75074], [16.53514, 47.73837], [16.55129, 47.72268], [16.4222, 47.66537], [16.58699, 47.61772], [16.64193, 47.63114], [16.71059, 47.52692], [16.64821, 47.50155], [16.6718, 47.46139], [16.57152, 47.40868], [16.52414, 47.41007], [16.49908, 47.39416], [16.45104, 47.41181], [16.47782, 47.25918], [16.44142, 47.25079], [16.43663, 47.21127], [16.41739, 47.20649], [16.42801, 47.18422], [16.4523, 47.18812], [16.46442, 47.16845], [16.44932, 47.14418], [16.52863, 47.13974], [16.46134, 47.09395], [16.52176, 47.05747], [16.43936, 47.03548], [16.51369, 47.00084], [16.28202, 47.00159], [16.27594, 46.9643], [16.22403, 46.939], [16.19904, 46.94134], [16.10983, 46.867], [16.14365, 46.8547], [16.15711, 46.85434], [16.21892, 46.86961], [16.2365, 46.87775], [16.2941, 46.87137], [16.34547, 46.83836], [16.3408, 46.80641], [16.31303, 46.79838], [16.30966, 46.7787], [16.37816, 46.69975], [16.42641, 46.69228], [16.41863, 46.66238], [16.38594, 46.6549], [16.39217, 46.63673], [16.50139, 46.56684], [16.52885, 46.53303], [16.52604, 46.5051], [16.59527, 46.47524], [16.6639, 46.45203], [16.7154, 46.39523], [16.8541, 46.36255], [16.8903, 46.28122], [17.14592, 46.16697], [17.35672, 45.95209], [17.56821, 45.93728], [17.66545, 45.84207], [17.87377, 45.78522], [17.99805, 45.79671], [18.08869, 45.76511], [18.12439, 45.78905], [18.44368, 45.73972], [18.57483, 45.80772], [18.6792, 45.92057], [18.80211, 45.87995], [18.81394, 45.91329], [18.99712, 45.93537], [19.01284, 45.96529], [19.0791, 45.96458], [19.10388, 46.04015], [19.14543, 45.9998], [19.28826, 45.99694], [19.52473, 46.1171], [19.56113, 46.16824], [19.66007, 46.19005], [19.81491, 46.1313], [19.93508, 46.17553], [20.01816, 46.17696], [20.03533, 46.14509], [20.09713, 46.17315], [20.26068, 46.12332], [20.28324, 46.1438], [20.35573, 46.16629], [20.45377, 46.14405], [20.49718, 46.18721], [20.63863, 46.12728], [20.76085, 46.21002], [20.74574, 46.25467], [20.86797, 46.28884], [21.06572, 46.24897], [21.16872, 46.30118], [21.28061, 46.44941], [21.26929, 46.4993], [21.33214, 46.63035], [21.43926, 46.65109], [21.5151, 46.72147], [21.48935, 46.7577], [21.52028, 46.84118], [21.59307, 46.86935], [21.59581, 46.91628], [21.68645, 46.99595], [21.648, 47.03902], [21.78395, 47.11104], [21.94463, 47.38046], [22.01055, 47.37767], [22.03389, 47.42508], [22.00917, 47.50492], [22.31816, 47.76126], [22.41979, 47.7391], [22.46559, 47.76583], [22.67247, 47.7871], [22.76617, 47.8417], [22.77991, 47.87211], [22.89849, 47.95851], [22.84276, 47.98602], [22.87847, 48.04665], [22.81804, 48.11363], [22.73427, 48.12005], [22.66835, 48.09162], [22.58733, 48.10813], [22.59007, 48.15121], [22.49806, 48.25189], [22.38133, 48.23726], [22.2083, 48.42534], [22.14689, 48.4005], [21.83339, 48.36242], [21.8279, 48.33321], [21.72525, 48.34628]]]] } },
     { type: "Feature", properties: { iso1A2: "IC", wikidata: "Q5813", nameEn: "Canary Islands", country: "ES", groups: ["Q3320166", "Q105472", "EU", "039", "150", "UN"], isoStatus: "excRes", callingCodes: ["34"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-12.00985, 30.24121], [-25.3475, 27.87574], [-14.43883, 27.02969], [-12.00985, 30.24121]]]] } },
     { type: "Feature", properties: { iso1A2: "ID", iso1A3: "IDN", iso1N3: "360", wikidata: "Q252", nameEn: "Indonesia", aliases: ["RI"] }, geometry: null },
-    { type: "Feature", properties: { iso1A2: "IE", iso1A3: "IRL", iso1N3: "372", wikidata: "Q27", nameEn: "Republic of Ireland", groups: ["EU", "Q22890", "154", "150", "UN"], driveSide: "left", callingCodes: ["353"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-6.26218, 54.09785], [-6.29003, 54.11278], [-6.32694, 54.09337], [-6.36279, 54.11248], [-6.36605, 54.07234], [-6.47849, 54.06947], [-6.62842, 54.03503], [-6.66264, 54.0666], [-6.6382, 54.17071], [-6.70175, 54.20218], [-6.74575, 54.18788], [-6.81583, 54.22791], [-6.85179, 54.29176], [-6.87775, 54.34682], [-7.02034, 54.4212], [-7.19145, 54.31296], [-7.14908, 54.22732], [-7.25012, 54.20063], [-7.26316, 54.13863], [-7.29493, 54.12013], [-7.29687, 54.1354], [-7.28017, 54.16714], [-7.29157, 54.17191], [-7.34005, 54.14698], [-7.30553, 54.11869], [-7.32834, 54.11475], [-7.44567, 54.1539], [-7.4799, 54.12239], [-7.55812, 54.12239], [-7.69501, 54.20731], [-7.81397, 54.20159], [-7.8596, 54.21779], [-7.87101, 54.29299], [-8.04555, 54.36292], [-8.179, 54.46763], [-8.04538, 54.48941], [-7.99812, 54.54427], [-7.8596, 54.53671], [-7.70315, 54.62077], [-7.93293, 54.66603], [-7.83352, 54.73854], [-7.75041, 54.7103], [-7.64449, 54.75265], [-7.54671, 54.74606], [-7.54508, 54.79401], [-7.47626, 54.83084], [-7.4473, 54.87003], [-7.44404, 54.9403], [-7.40004, 54.94498], [-7.4033, 55.00391], [-7.34464, 55.04688], [-7.2471, 55.06933], [-6.34755, 55.49206], [-7.75229, 55.93854], [-22.01468, 48.19557], [-6.03913, 51.13217], [-5.37267, 53.63269], [-6.26218, 54.09785]]]] } },
+    { type: "Feature", geometry: { type: "MultiPolygon", coordinates: [[[[-6.26218, 54.09785], [-6.29003, 54.11278], [-6.32694, 54.09337], [-6.36279, 54.11248], [-6.36605, 54.07234], [-6.47849, 54.06947], [-6.62842, 54.03503], [-6.66264, 54.0666], [-6.6382, 54.17071], [-6.70175, 54.20218], [-6.74575, 54.18788], [-6.81583, 54.22791], [-6.85179, 54.29176], [-6.87775, 54.34682], [-7.02034, 54.4212], [-7.19145, 54.31296], [-7.14908, 54.22732], [-7.25012, 54.20063], [-7.26316, 54.13863], [-7.29493, 54.12013], [-7.29687, 54.1354], [-7.28017, 54.16714], [-7.29157, 54.17191], [-7.34005, 54.14698], [-7.30553, 54.11869], [-7.32834, 54.11475], [-7.44567, 54.1539], [-7.4799, 54.12239], [-7.55812, 54.12239], [-7.69501, 54.20731], [-7.81397, 54.20159], [-7.8596, 54.21779], [-7.87101, 54.29299], [-8.04555, 54.36292], [-8.179, 54.46763], [-8.04538, 54.48941], [-7.99812, 54.54427], [-7.8596, 54.53671], [-7.70315, 54.62077], [-7.93293, 54.66603], [-7.83352, 54.73854], [-7.75041, 54.7103], [-7.64449, 54.75265], [-7.54671, 54.74606], [-7.54508, 54.79401], [-7.47626, 54.83084], [-7.4473, 54.87003], [-7.44404, 54.9403], [-7.40004, 54.94498], [-7.4033, 55.00391], [-7.34464, 55.04688], [-7.2471, 55.06933], [-6.34755, 55.49206], [-7.75229, 55.93854], [-11.75, 54], [-11, 51], [-6.03913, 51.13217], [-5.37267, 53.63269], [-6.26218, 54.09785]]]] }, properties: { iso1A2: "IE", iso1A3: "IRL", iso1N3: "372", wikidata: "Q27", nameEn: "Republic of Ireland", groups: ["EU", "Q22890", "154", "150", "UN"], driveSide: "left", callingCodes: ["353"] } },
     { type: "Feature", properties: { iso1A2: "IL", iso1A3: "ISR", iso1N3: "376", wikidata: "Q801", nameEn: "Israel", groups: ["145", "142", "UN"], callingCodes: ["972"] }, geometry: { type: "MultiPolygon", coordinates: [[[[34.052, 31.46619], [34.29262, 31.70393], [34.48681, 31.59711], [34.56797, 31.54197], [34.48892, 31.48365], [34.40077, 31.40926], [34.36505, 31.36404], [34.37381, 31.30598], [34.36523, 31.28963], [34.29417, 31.24194], [34.26742, 31.21998], [34.92298, 29.45305], [34.97718, 29.54294], [34.98207, 29.58147], [35.02147, 29.66343], [35.14108, 30.07374], [35.19183, 30.34636], [35.16218, 30.43535], [35.19595, 30.50297], [35.21379, 30.60401], [35.29311, 30.71365], [35.33456, 30.81224], [35.33984, 30.8802], [35.41371, 30.95565], [35.43658, 31.12444], [35.40316, 31.25535], [35.47672, 31.49578], [35.39675, 31.49572], [35.22921, 31.37445], [35.13033, 31.3551], [35.02459, 31.35979], [34.92571, 31.34337], [34.88932, 31.37093], [34.87833, 31.39321], [34.89756, 31.43891], [34.93258, 31.47816], [34.94356, 31.50743], [34.9415, 31.55601], [34.95249, 31.59813], [35.00879, 31.65426], [35.08226, 31.69107], [35.10782, 31.71594], [35.11895, 31.71454], [35.12933, 31.7325], [35.13931, 31.73012], [35.15119, 31.73634], [35.15474, 31.73352], [35.16478, 31.73242], [35.18023, 31.72067], [35.20538, 31.72388], [35.21937, 31.71578], [35.22392, 31.71899], [35.23972, 31.70896], [35.24315, 31.71244], [35.2438, 31.7201], [35.24981, 31.72543], [35.25182, 31.73945], [35.26319, 31.74846], [35.25225, 31.7678], [35.26058, 31.79064], [35.25573, 31.81362], [35.26404, 31.82567], [35.251, 31.83085], [35.25753, 31.8387], [35.24816, 31.8458], [35.2304, 31.84222], [35.2249, 31.85433], [35.22817, 31.8638], [35.22567, 31.86745], [35.22294, 31.87889], [35.22014, 31.88264], [35.2136, 31.88241], [35.21276, 31.88153], [35.21016, 31.88237], [35.20945, 31.8815], [35.20791, 31.8821], [35.20673, 31.88151], [35.20381, 31.86716], [35.21128, 31.863], [35.216, 31.83894], [35.21469, 31.81835], [35.19461, 31.82687], [35.18169, 31.82542], [35.18603, 31.80901], [35.14174, 31.81325], [35.07677, 31.85627], [35.05617, 31.85685], [35.01978, 31.82944], [34.9724, 31.83352], [34.99712, 31.85569], [35.03489, 31.85919], [35.03978, 31.89276], [35.03489, 31.92448], [35.00124, 31.93264], [34.98682, 31.96935], [35.00261, 32.027], [34.9863, 32.09551], [34.99437, 32.10962], [34.98507, 32.12606], [34.99039, 32.14626], [34.96009, 32.17503], [34.95703, 32.19522], [34.98885, 32.20758], [35.01841, 32.23981], [35.02939, 32.2671], [35.01119, 32.28684], [35.01772, 32.33863], [35.04243, 32.35008], [35.05142, 32.3667], [35.0421, 32.38242], [35.05311, 32.4024], [35.05423, 32.41754], [35.07059, 32.4585], [35.08564, 32.46948], [35.09236, 32.47614], [35.10024, 32.47856], [35.10882, 32.4757], [35.15937, 32.50466], [35.2244, 32.55289], [35.25049, 32.52453], [35.29306, 32.50947], [35.30685, 32.51024], [35.35212, 32.52047], [35.40224, 32.50136], [35.42034, 32.46009], [35.41598, 32.45593], [35.41048, 32.43706], [35.42078, 32.41562], [35.55807, 32.38674], [35.55494, 32.42687], [35.57485, 32.48669], [35.56614, 32.64393], [35.59813, 32.65159], [35.61669, 32.67999], [35.66527, 32.681], [35.68467, 32.70715], [35.75983, 32.74803], [35.78745, 32.77938], [35.83758, 32.82817], [35.84021, 32.8725], [35.87012, 32.91976], [35.89298, 32.9456], [35.87188, 32.98028], [35.84802, 33.1031], [35.81911, 33.11077], [35.81911, 33.1336], [35.84285, 33.16673], [35.83846, 33.19397], [35.81647, 33.2028], [35.81295, 33.24841], [35.77513, 33.27342], [35.813, 33.3172], [35.77477, 33.33609], [35.62019, 33.27278], [35.62283, 33.24226], [35.58502, 33.26653], [35.58326, 33.28381], [35.56523, 33.28969], [35.55555, 33.25844], [35.54544, 33.25513], [35.54808, 33.236], [35.5362, 33.23196], [35.54228, 33.19865], [35.52573, 33.11921], [35.50335, 33.114], [35.50272, 33.09056], [35.448, 33.09264], [35.43059, 33.06659], [35.35223, 33.05617], [35.31429, 33.10515], [35.1924, 33.08743], [35.10645, 33.09318], [34.78515, 33.20368], [33.62659, 31.82938], [34.052, 31.46619]]]] } },
     { type: "Feature", properties: { iso1A2: "IM", iso1A3: "IMN", iso1N3: "833", wikidata: "Q9676", nameEn: "Isle of Man", country: "GB", groups: ["Q185086", "154", "150", "UN"], driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["44 01624", "44 07624", "44 07524", "44 07924"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-3.98763, 54.07351], [-4.1819, 54.57861], [-5.6384, 53.81157], [-3.98763, 54.07351]]]] } },
     { type: "Feature", properties: { iso1A2: "IN", iso1A3: "IND", iso1N3: "356", wikidata: "Q668", nameEn: "India" }, geometry: null },
     { type: "Feature", properties: { iso1A2: "ZA", iso1A3: "ZAF", iso1N3: "710", wikidata: "Q258", nameEn: "South Africa", groups: ["018", "202", "002", "UN"], driveSide: "left", callingCodes: ["27"] }, geometry: { type: "MultiPolygon", coordinates: [[[[31.30611, -22.422], [31.16344, -22.32599], [31.08932, -22.34884], [30.86696, -22.28907], [30.6294, -22.32599], [30.48686, -22.31368], [30.38614, -22.34533], [30.28351, -22.35587], [30.2265, -22.2961], [30.13147, -22.30841], [29.92242, -22.19408], [29.76848, -22.14128], [29.64609, -22.12917], [29.37703, -22.19581], [29.21955, -22.17771], [29.18974, -22.18599], [29.15268, -22.21399], [29.10881, -22.21202], [29.0151, -22.22907], [28.91889, -22.44299], [28.63287, -22.55887], [28.34874, -22.5694], [28.04562, -22.8394], [28.04752, -22.90243], [27.93729, -22.96194], [27.93539, -23.04941], [27.74154, -23.2137], [27.6066, -23.21894], [27.52393, -23.37952], [27.33768, -23.40917], [26.99749, -23.65486], [26.84165, -24.24885], [26.51667, -24.47219], [26.46346, -24.60358], [26.39409, -24.63468], [25.8515, -24.75727], [25.84295, -24.78661], [25.88571, -24.87802], [25.72702, -25.25503], [25.69661, -25.29284], [25.6643, -25.4491], [25.58543, -25.6343], [25.33076, -25.76616], [25.12266, -25.75931], [25.01718, -25.72507], [24.8946, -25.80723], [24.67319, -25.81749], [24.44703, -25.73021], [24.36531, -25.773], [24.18287, -25.62916], [23.9244, -25.64286], [23.47588, -25.29971], [23.03497, -25.29971], [22.86012, -25.50572], [22.70808, -25.99186], [22.56365, -26.19668], [22.41921, -26.23078], [22.21206, -26.3773], [22.06192, -26.61882], [21.90703, -26.66808], [21.83291, -26.65959], [21.77114, -26.69015], [21.7854, -26.79199], [21.69322, -26.86152], [21.37869, -26.82083], [21.13353, -26.86661], [20.87031, -26.80047], [20.68596, -26.9039], [20.63275, -26.78181], [20.61754, -26.4692], [20.86081, -26.14892], [20.64795, -25.47827], [20.29826, -24.94869], [20.03678, -24.81004], [20.02809, -24.78725], [19.99817, -24.76768], [19.99882, -28.42622], [18.99885, -28.89165], [17.4579, -28.68718], [17.15405, -28.08573], [16.90446, -28.057], [16.59922, -28.53246], [16.46592, -28.57126], [16.45332, -28.63117], [12.51595, -32.27486], [38.88176, -48.03306], [34.51034, -26.91792], [32.35222, -26.86027], [32.29584, -26.852], [32.22302, -26.84136], [32.19409, -26.84032], [32.13315, -26.84345], [32.09664, -26.80721], [32.00893, -26.8096], [31.97463, -27.11057], [31.97592, -27.31675], [31.49834, -27.31549], [31.15027, -27.20151], [30.96088, -27.0245], [30.97757, -26.92706], [30.88826, -26.79622], [30.81101, -26.84722], [30.78927, -26.48271], [30.95819, -26.26303], [31.13073, -25.91558], [31.31237, -25.7431], [31.4175, -25.71886], [31.86881, -25.99973], [31.974, -25.95387], [31.92649, -25.84216], [32.00631, -25.65044], [31.97875, -25.46356], [32.01676, -25.38117], [32.03196, -25.10785], [31.9835, -24.29983], [31.90368, -24.18892], [31.87707, -23.95293], [31.77445, -23.90082], [31.70223, -23.72695], [31.67942, -23.60858], [31.56539, -23.47268], [31.55779, -23.176], [31.30611, -22.422]], [[29.33204, -29.45598], [29.28545, -29.58456], [29.12553, -29.76266], [29.16548, -29.91706], [28.9338, -30.05072], [28.80222, -30.10579], [28.68627, -30.12885], [28.399, -30.1592], [28.2319, -30.28476], [28.12073, -30.68072], [27.74814, -30.60635], [27.69467, -30.55862], [27.67819, -30.53437], [27.6521, -30.51707], [27.62137, -30.50509], [27.56781, -30.44562], [27.56901, -30.42504], [27.45452, -30.32239], [27.38108, -30.33456], [27.36649, -30.27246], [27.37293, -30.19401], [27.40778, -30.14577], [27.32555, -30.14785], [27.29603, -30.05473], [27.22719, -30.00718], [27.09489, -29.72796], [27.01016, -29.65439], [27.33464, -29.48161], [27.4358, -29.33465], [27.47254, -29.31968], [27.45125, -29.29708], [27.48679, -29.29349], [27.54258, -29.25575], [27.5158, -29.2261], [27.55974, -29.18954], [27.75458, -28.89839], [27.8907, -28.91612], [27.88933, -28.88156], [27.9392, -28.84864], [27.98675, -28.8787], [28.02503, -28.85991], [28.1317, -28.7293], [28.2348, -28.69471], [28.30518, -28.69531], [28.40612, -28.6215], [28.65091, -28.57025], [28.68043, -28.58744], [29.40524, -29.21246], [29.44883, -29.3772], [29.33204, -29.45598]]]] } },
     { type: "Feature", properties: { iso1A2: "ZM", iso1A3: "ZMB", iso1N3: "894", wikidata: "Q953", nameEn: "Zambia", groups: ["014", "202", "002", "UN"], driveSide: "left", callingCodes: ["260"] }, geometry: { type: "MultiPolygon", coordinates: [[[[32.95389, -9.40138], [32.76233, -9.31963], [32.75611, -9.28583], [32.53661, -9.24281], [32.49147, -9.14754], [32.43543, -9.11988], [32.25486, -9.13371], [32.16146, -9.05993], [32.08206, -9.04609], [31.98866, -9.07069], [31.94196, -9.02303], [31.94663, -8.93846], [31.81587, -8.88618], [31.71158, -8.91386], [31.57147, -8.81388], [31.57147, -8.70619], [31.37533, -8.60769], [31.00796, -8.58615], [30.79243, -8.27382], [28.88917, -8.4831], [28.9711, -8.66935], [28.38526, -9.23393], [28.36562, -9.30091], [28.52636, -9.35379], [28.51627, -9.44726], [28.56208, -9.49122], [28.68532, -9.78], [28.62795, -9.92942], [28.65032, -10.65133], [28.37241, -11.57848], [28.48357, -11.87532], [29.18592, -12.37921], [29.4992, -12.43843], [29.48404, -12.23604], [29.8139, -12.14898], [29.81551, -13.44683], [29.65078, -13.41844], [29.60531, -13.21685], [29.01918, -13.41353], [28.33199, -12.41375], [27.59932, -12.22123], [27.21025, -11.76157], [27.22541, -11.60323], [27.04351, -11.61312], [26.88687, -12.01868], [26.01777, -11.91488], [25.33058, -11.65767], [25.34069, -11.19707], [24.42612, -11.44975], [24.34528, -11.06816], [24.00027, -10.89356], [24.02603, -11.15368], [23.98804, -12.13149], [24.06672, -12.29058], [23.90937, -12.844], [24.03339, -12.99091], [21.97988, -13.00148], [22.00323, -16.18028], [22.17217, -16.50269], [23.20038, -17.47563], [23.47474, -17.62877], [24.23619, -17.47489], [24.32811, -17.49082], [24.38712, -17.46818], [24.5621, -17.52963], [24.70864, -17.49501], [25.00198, -17.58221], [25.26433, -17.79571], [25.51646, -17.86232], [25.6827, -17.81987], [25.85738, -17.91403], [25.85892, -17.97726], [26.08925, -17.98168], [26.0908, -17.93021], [26.21601, -17.88608], [26.55918, -17.99638], [26.68403, -18.07411], [26.74314, -18.0199], [26.89926, -17.98756], [27.14196, -17.81398], [27.30736, -17.60487], [27.61377, -17.34378], [27.62795, -17.24365], [27.83141, -16.96274], [28.73725, -16.5528], [28.76199, -16.51575], [28.81454, -16.48611], [28.8501, -16.04537], [28.9243, -15.93987], [29.01298, -15.93805], [29.21955, -15.76589], [29.4437, -15.68702], [29.8317, -15.6126], [30.35574, -15.6513], [30.41902, -15.62269], [30.22098, -14.99447], [33.24249, -14.00019], [33.16749, -13.93992], [33.07568, -13.98447], [33.02977, -14.05022], [32.99042, -13.95689], [32.88985, -13.82956], [32.79015, -13.80755], [32.76962, -13.77224], [32.84528, -13.71576], [32.7828, -13.64805], [32.68654, -13.64268], [32.66468, -13.60019], [32.68436, -13.55769], [32.73683, -13.57682], [32.84176, -13.52794], [32.86113, -13.47292], [33.0078, -13.19492], [32.98289, -13.12671], [33.02181, -12.88707], [32.96733, -12.88251], [32.94397, -12.76868], [33.05917, -12.59554], [33.18837, -12.61377], [33.28177, -12.54692], [33.37517, -12.54085], [33.54485, -12.35996], [33.47636, -12.32498], [33.3705, -12.34931], [33.25998, -12.14242], [33.33937, -11.91252], [33.32692, -11.59248], [33.24252, -11.59302], [33.23663, -11.40637], [33.29267, -11.43536], [33.29267, -11.3789], [33.39697, -11.15296], [33.25998, -10.88862], [33.28022, -10.84428], [33.47636, -10.78465], [33.70675, -10.56896], [33.54797, -10.36077], [33.53863, -10.20148], [33.31297, -10.05133], [33.37902, -9.9104], [33.36581, -9.81063], [33.31517, -9.82364], [33.2095, -9.61099], [33.12144, -9.58929], [33.10163, -9.66525], [33.05485, -9.61316], [33.00256, -9.63053], [33.00476, -9.5133], [32.95389, -9.40138]]]] } },
     { type: "Feature", properties: { iso1A2: "ZW", iso1A3: "ZWE", iso1N3: "716", wikidata: "Q954", nameEn: "Zimbabwe", groups: ["014", "202", "002", "UN"], driveSide: "left", callingCodes: ["263"] }, geometry: { type: "MultiPolygon", coordinates: [[[[30.41902, -15.62269], [30.35574, -15.6513], [29.8317, -15.6126], [29.4437, -15.68702], [29.21955, -15.76589], [29.01298, -15.93805], [28.9243, -15.93987], [28.8501, -16.04537], [28.81454, -16.48611], [28.76199, -16.51575], [28.73725, -16.5528], [27.83141, -16.96274], [27.62795, -17.24365], [27.61377, -17.34378], [27.30736, -17.60487], [27.14196, -17.81398], [26.89926, -17.98756], [26.74314, -18.0199], [26.68403, -18.07411], [26.55918, -17.99638], [26.21601, -17.88608], [26.0908, -17.93021], [26.08925, -17.98168], [25.85892, -17.97726], [25.85738, -17.91403], [25.6827, -17.81987], [25.51646, -17.86232], [25.26433, -17.79571], [25.23909, -17.90832], [25.31799, -18.07091], [25.39972, -18.12691], [25.53465, -18.39041], [25.68859, -18.56165], [25.79217, -18.6355], [25.82353, -18.82808], [25.94326, -18.90362], [25.99837, -19.02943], [25.96226, -19.08152], [26.17227, -19.53709], [26.72246, -19.92707], [27.21278, -20.08244], [27.29831, -20.28935], [27.28865, -20.49873], [27.69361, -20.48531], [27.72972, -20.51735], [27.69171, -21.08409], [27.91407, -21.31621], [28.01669, -21.57624], [28.29416, -21.59037], [28.49942, -21.66634], [28.58114, -21.63455], [29.07763, -21.81877], [29.04023, -21.85864], [29.02191, -21.90647], [29.02191, -21.95665], [29.04108, -22.00563], [29.08495, -22.04867], [29.14501, -22.07275], [29.1974, -22.07472], [29.24648, -22.05967], [29.3533, -22.18363], [29.37703, -22.19581], [29.64609, -22.12917], [29.76848, -22.14128], [29.92242, -22.19408], [30.13147, -22.30841], [30.2265, -22.2961], [30.28351, -22.35587], [30.38614, -22.34533], [30.48686, -22.31368], [30.6294, -22.32599], [30.86696, -22.28907], [31.08932, -22.34884], [31.16344, -22.32599], [31.30611, -22.422], [31.38336, -22.36919], [32.41234, -21.31246], [32.48236, -21.32873], [32.37115, -21.133], [32.51644, -20.91929], [32.48122, -20.63319], [32.55167, -20.56312], [32.66174, -20.56106], [32.85987, -20.27841], [32.85987, -20.16686], [32.93032, -20.03868], [33.01178, -20.02007], [33.06461, -19.77787], [32.95013, -19.67219], [32.84666, -19.68462], [32.84446, -19.48343], [32.78282, -19.47513], [32.77966, -19.36098], [32.85107, -19.29238], [32.87088, -19.09279], [32.84006, -19.0262], [32.72118, -19.02204], [32.69917, -18.94293], [32.73439, -18.92628], [32.70137, -18.84712], [32.82465, -18.77419], [32.9017, -18.7992], [32.95013, -18.69079], [32.88629, -18.58023], [32.88629, -18.51344], [33.02278, -18.4696], [33.03159, -18.35054], [32.94133, -17.99705], [33.0492, -17.60298], [32.98536, -17.55891], [32.96554, -17.48964], [33.0426, -17.3468], [33.00517, -17.30477], [32.96554, -17.11971], [32.84113, -16.92259], [32.91051, -16.89446], [32.97655, -16.70689], [32.78943, -16.70267], [32.69917, -16.66893], [32.71017, -16.59932], [32.42838, -16.4727], [32.28529, -16.43892], [32.02772, -16.43892], [31.91324, -16.41569], [31.90223, -16.34388], [31.67988, -16.19595], [31.42451, -16.15154], [31.30563, -16.01193], [31.13171, -15.98019], [30.97761, -16.05848], [30.91597, -15.99924], [30.42568, -15.9962], [30.41902, -15.62269]]]] } }
-  ];
-  var borders_default = { type, features };
+  ] };
   var borders = borders_default;
   var whichPolygonGetter = {};
   var featuresByCode = {};
           sharedGroups = sharedGroups.filter((groupID) => memberGroups.indexOf(groupID) !== -1);
         }
       });
-      props.groups = props.groups.concat(sharedGroups.filter((groupID) => props.groups.indexOf(groupID) === -1));
+      props.groups = props.groups.concat(
+        sharedGroups.filter((groupID) => props.groups.indexOf(groupID) === -1)
+      );
       sharedGroups.forEach((groupID) => {
         const groupFeature = featuresByCode[groupID];
         if (groupFeature.properties.members.indexOf(props.id) === -1) {
         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";
-        }).filter(Boolean)));
+        const vals = Array.from(
+          new Set(
+            props.members.map((id2) => {
+              const member = featuresByCode[id2];
+              if (member.geometry)
+                return member.properties.roadSpeedUnit || "km/h";
+            }).filter(Boolean)
+          )
+        );
         if (vals.length === 1)
           props.roadSpeedUnit = vals[0];
       }
         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";
-        }).filter(Boolean)));
+        const vals = Array.from(
+          new Set(
+            props.members.map((id2) => {
+              const member = featuresByCode[id2];
+              if (member.geometry)
+                return member.properties.roadHeightUnit || "m";
+            }).filter(Boolean)
+          )
+        );
         if (vals.length === 1)
           props.roadHeightUnit = vals[0];
       }
         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";
-        }).filter(Boolean)));
+        const vals = Array.from(
+          new Set(
+            props.members.map((id2) => {
+              const member = featuresByCode[id2];
+              if (member.geometry)
+                return member.properties.driveSide || "right";
+            }).filter(Boolean)
+          )
+        );
         if (vals.length === 1)
           props.driveSide = vals[0];
       }
     function loadCallingCodes(feature22) {
       const props = feature22.properties;
       if (!feature22.geometry && props.members) {
-        props.callingCodes = Array.from(new Set(props.members.reduce((array2, id2) => {
-          const member = featuresByCode[id2];
-          if (member.geometry && member.properties.callingCodes) {
-            return array2.concat(member.properties.callingCodes);
-          }
-          return array2;
-        }, [])));
+        props.callingCodes = Array.from(
+          new Set(
+            props.members.reduce((array2, id2) => {
+              const member = featuresByCode[id2];
+              if (member.geometry && member.properties.callingCodes) {
+                return array2.concat(member.properties.callingCodes);
+              }
+              return array2;
+            }, [])
+          )
+        );
       }
     }
     function loadFlag(feature22) {
         }
       }
     }
-    const features2 = featuresContaining(loc);
-    const match = features2.find((feature22) => {
+    const features = featuresContaining(loc);
+    const match = features.find((feature22) => {
       let levelIndex = levels.indexOf(feature22.properties.level);
-      if (feature22.properties.level === targetLevel || levelIndex > targetLevelIndex && levelIndex <= maxLevelIndex) {
+      if (feature22.properties.level === targetLevel || // if no feature exists at the target level, return the first feature at the next level up
+      levelIndex > targetLevelIndex && levelIndex <= maxLevelIndex) {
         if (!withProp || feature22.properties[withProp]) {
           return feature22;
         }
     }
     return featuresByCode[stringID] || null;
   }
-  function smallestFeaturesForBbox(bbox) {
-    return whichPolygonGetter.bbox(bbox).map((props) => featuresByCode[props.id]);
+  function smallestFeaturesForBbox(bbox2) {
+    return whichPolygonGetter.bbox(bbox2).map((props) => featuresByCode[props.id]);
   }
   function smallestOrMatchingFeature(query) {
     if (typeof query === "object") {
     const feature22 = featureForID(id2);
     if (!feature22)
       return [];
-    let features2 = [];
+    let features = [];
     if (!strict) {
-      features2.push(feature22);
+      features.push(feature22);
     }
     const properties = feature22.properties;
     (properties.members || []).forEach((memberID) => {
-      features2.push(featuresByCode[memberID]);
+      features.push(featuresByCode[memberID]);
     });
-    return features2;
+    return features;
   }
   function aggregateFeature(id2) {
-    const features2 = featuresIn(id2, false);
-    if (features2.length === 0)
+    const features = featuresIn(id2, false);
+    if (features.length === 0)
       return null;
     let aggregateCoordinates = [];
-    features2.forEach((feature22) => {
+    features.forEach((feature22) => {
       if (feature22.geometry && feature22.geometry.type === "MultiPolygon" && feature22.geometry.coordinates) {
         aggregateCoordinates = aggregateCoordinates.concat(feature22.geometry.coordinates);
       }
     });
     return {
       type: "Feature",
-      properties: features2[0].properties,
+      properties: features[0].properties,
       geometry: {
         type: "MultiPolygon",
         coordinates: aggregateCoordinates
     return feature22 && feature22.properties.roadHeightUnit || null;
   }
 
-  // node_modules/@ideditor/location-conflation/index.mjs
+  // node_modules/@rapideditor/location-conflation/index.mjs
   var import_geojson_area = __toESM(require_geojson_area(), 1);
   var import_circle_to_polygon = __toESM(require_circle_to_polygon(), 1);
   var import_polygon_clipping = __toESM(require_polygon_clipping_umd(), 1);
   var import_geojson_precision = __toESM(require_geojson_precision(), 1);
   var import_json_stringify_pretty_compact = __toESM(require_json_stringify_pretty_compact(), 1);
   var location_conflation_default = class {
+    // constructor
+    //
+    // `fc`  Optional FeatureCollection of known features
+    //
+    // Optionally pass a GeoJSON FeatureCollection of known features which we can refer to later.
+    // Each feature must have a filename-like `id`, for example: `something.geojson`
+    //
+    // {
+    //   "type": "FeatureCollection"
+    //   "features": [
+    //     {
+    //       "type": "Feature",
+    //       "id": "philly_metro.geojson",
+    //       "properties": { … },
+    //       "geometry": { … }
+    //     }
+    //   ]
+    // }
     constructor(fc) {
       this._cache = {};
       this._strict = true;
       world.properties.area = import_geojson_area.default.geometry(world.geometry) / 1e6;
       this._cache.Q2 = world;
     }
+    // validateLocation
+    // `location`  The location to validate
+    //
+    // Pass a `location` value to validate
+    //
+    // Returns a result like:
+    //   {
+    //     type:     'point', 'geojson', or 'countrycoder'
+    //     location:  the queried location
+    //     id:        the stable identifier for the feature
+    //   }
+    // or `null` if the location is invalid
+    //
     validateLocation(location) {
       if (Array.isArray(location) && (location.length === 2 || location.length === 3)) {
         const lon = location[0];
         return null;
       }
     }
+    // resolveLocation
+    // `location`  The location to resolve
+    //
+    // Pass a `location` value to resolve
+    //
+    // Returns a result like:
+    //   {
+    //     type:      'point', 'geojson', or 'countrycoder'
+    //     location:  the queried location
+    //     id:        a stable identifier for the feature
+    //     feature:   the resolved GeoJSON feature
+    //   }
+    //  or `null` if the location is invalid
+    //
     resolveLocation(location) {
       const valid = this.validateLocation(location);
       if (!valid)
           id: id2,
           properties: { id: id2, area: Number(area.toFixed(2)) },
           geometry: (0, import_circle_to_polygon.default)([lon, lat], radius * 1e3, EDGES)
+          // km to m
         }, PRECISION);
         return Object.assign(valid, { feature: feature3 });
       } else if (valid.type === "geojson") {
         return null;
       }
     }
+    // validateLocationSet
+    // `locationSet`  the locationSet to validate
+    //
+    // Pass a locationSet Object to validate like:
+    //   {
+    //     include: [ Array of locations ],
+    //     exclude: [ Array of locations ]
+    //   }
+    //
+    // Returns a result like:
+    //   {
+    //     type:         'locationset'
+    //     locationSet:  the queried locationSet
+    //     id:           the stable identifier for the feature
+    //   }
+    // or `null` if the locationSet is invalid
+    //
     validateLocationSet(locationSet) {
       locationSet = locationSet || {};
       const validator = this.validateLocation.bind(this);
       }
       return { type: "locationset", locationSet, id: id2 };
     }
+    // resolveLocationSet
+    // `locationSet`  the locationSet to resolve
+    //
+    // Pass a locationSet Object to validate like:
+    //   {
+    //     include: [ Array of locations ],
+    //     exclude: [ Array of locations ]
+    //   }
+    //
+    // Returns a result like:
+    //   {
+    //     type:         'locationset'
+    //     locationSet:  the queried locationSet
+    //     id:           the stable identifier for the feature
+    //     feature:      the resolved GeoJSON feature
+    //   }
+    // or `null` if the locationSet is invalid
+    //
     resolveLocationSet(locationSet) {
       locationSet = locationSet || {};
       const valid = this.validateLocationSet(locationSet);
       this._cache[id2] = resultGeoJSON;
       return Object.assign(valid, { feature: resultGeoJSON });
     }
+    // strict
+    //
     strict(val) {
       if (val === void 0) {
         return this._strict;
         return this;
       }
     }
+    // cache
+    // convenience method to access the internal cache
     cache() {
       return this._cache;
     }
+    // stringify
+    // convenience method to prettyStringify the given object
     stringify(obj, options2) {
       return (0, import_json_stringify_pretty_compact.default)(obj, options2);
     }
   };
-  function _clip(features2, which) {
-    if (!Array.isArray(features2) || !features2.length)
+  function _clip(features, which) {
+    if (!Array.isArray(features) || !features.length)
       return null;
     const fn = { UNION: import_polygon_clipping.default.union, DIFFERENCE: import_polygon_clipping.default.difference }[which];
-    const args = features2.map((feature3) => feature3.geometry.coordinates);
+    const args = features.map((feature3) => feature3.geometry.coordinates);
     const coords = fn.apply(null, args);
     return {
       type: "Feature",
     return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
   }
 
-  // modules/core/locations.js
+  // modules/core/LocationManager.js
   var import_which_polygon2 = __toESM(require_which_polygon());
   var import_geojson_area2 = __toESM(require_geojson_area());
-
-  // modules/util/aes.js
-  var import_aes_js = __toESM(require_aes_js());
-  var DEFAULT_128 = [250, 157, 60, 79, 142, 134, 229, 129, 138, 126, 210, 129, 29, 71, 160, 208];
-  function utilAesEncrypt(text2, key) {
-    key = key || DEFAULT_128;
-    const textBytes = import_aes_js.default.utils.utf8.toBytes(text2);
-    const aesCtr = new import_aes_js.default.ModeOfOperation.ctr(key);
-    const encryptedBytes = aesCtr.encrypt(textBytes);
-    const encryptedHex = import_aes_js.default.utils.hex.fromBytes(encryptedBytes);
-    return encryptedHex;
-  }
-  function utilAesDecrypt(encryptedHex, key) {
-    key = key || DEFAULT_128;
-    const encryptedBytes = import_aes_js.default.utils.hex.toBytes(encryptedHex);
-    const aesCtr = new import_aes_js.default.ModeOfOperation.ctr(key);
-    const decryptedBytes = aesCtr.decrypt(encryptedBytes);
-    const text2 = import_aes_js.default.utils.utf8.fromBytes(decryptedBytes);
-    return text2;
-  }
-
-  // modules/util/clean_tags.js
-  function utilCleanTags(tags) {
-    var out = {};
-    for (var k in tags) {
-      if (!k)
-        continue;
-      var v = tags[k];
-      if (v !== void 0) {
-        out[k] = cleanValue(k, v);
+  var _loco = new location_conflation_default();
+  var LocationManager = class {
+    /**
+     * @constructor
+     */
+    constructor() {
+      this._wp = null;
+      this._resolved = /* @__PURE__ */ new Map();
+      this._knownLocationSets = /* @__PURE__ */ new Map();
+      this._locationIncludedIn = /* @__PURE__ */ new Map();
+      this._locationExcludedIn = /* @__PURE__ */ new Map();
+      const world = { locationSet: { include: ["Q2"] } };
+      this._resolveLocationSet(world);
+      this._rebuildIndex();
+    }
+    /**
+     * _validateLocationSet
+     * Pass an Object with a `locationSet` property.
+     * Validates the `locationSet` and sets a `locationSetID` property on the object.
+     * To avoid so much computation we only resolve the include and exclude regions, but not the locationSet itself.
+     *
+     * Use `_resolveLocationSet()` instead if you need to resolve geojson of locationSet, for example to render it.
+     * Note: You need to call `_rebuildIndex()` after you're all finished validating the locationSets.
+     *
+     * @param  `obj`  Object to check, it should have `locationSet` property
+     */
+    _validateLocationSet(obj) {
+      if (obj.locationSetID)
+        return;
+      try {
+        let locationSet = obj.locationSet;
+        if (!locationSet) {
+          throw new Error("object missing locationSet property");
+        }
+        if (!locationSet.include) {
+          locationSet.include = ["Q2"];
+        }
+        const locationSetID = _loco.validateLocationSet(locationSet).id;
+        obj.locationSetID = locationSetID;
+        if (this._knownLocationSets.has(locationSetID))
+          return;
+        let area = 0;
+        (locationSet.include || []).forEach((location) => {
+          const locationID = _loco.validateLocation(location).id;
+          let geojson = this._resolved.get(locationID);
+          if (!geojson) {
+            geojson = _loco.resolveLocation(location).feature;
+            this._resolved.set(locationID, geojson);
+          }
+          area += geojson.properties.area;
+          let s = this._locationIncludedIn.get(locationID);
+          if (!s) {
+            s = /* @__PURE__ */ new Set();
+            this._locationIncludedIn.set(locationID, s);
+          }
+          s.add(locationSetID);
+        });
+        (locationSet.exclude || []).forEach((location) => {
+          const locationID = _loco.validateLocation(location).id;
+          let geojson = this._resolved.get(locationID);
+          if (!geojson) {
+            geojson = _loco.resolveLocation(location).feature;
+            this._resolved.set(locationID, geojson);
+          }
+          area -= geojson.properties.area;
+          let s = this._locationExcludedIn.get(locationID);
+          if (!s) {
+            s = /* @__PURE__ */ new Set();
+            this._locationExcludedIn.set(locationID, s);
+          }
+          s.add(locationSetID);
+        });
+        this._knownLocationSets.set(locationSetID, area);
+      } catch (err) {
+        obj.locationSet = { include: ["Q2"] };
+        obj.locationSetID = "+[Q2]";
       }
     }
-    return out;
-    function cleanValue(k2, v2) {
-      function keepSpaces(k3) {
-        return /_hours|_times|:conditional$/.test(k3);
+    /**
+     * _resolveLocationSet
+     * Does everything that `_validateLocationSet()` does, but then "resolves" the locationSet into GeoJSON.
+     * This step is a bit more computationally expensive, so really only needed if you intend to render the shape.
+     *
+     * Note: You need to call `_rebuildIndex()` after you're all finished validating the locationSets.
+     *
+     * @param  `obj`  Object to check, it should have `locationSet` property
+     */
+    _resolveLocationSet(obj) {
+      this._validateLocationSet(obj);
+      if (this._resolved.has(obj.locationSetID))
+        return;
+      try {
+        const result = _loco.resolveLocationSet(obj.locationSet);
+        const locationSetID = result.id;
+        obj.locationSetID = locationSetID;
+        if (!result.feature.geometry.coordinates.length || !result.feature.properties.area) {
+          throw new Error(`locationSet ${locationSetID} resolves to an empty feature.`);
+        }
+        let geojson = JSON.parse(JSON.stringify(result.feature));
+        geojson.id = locationSetID;
+        geojson.properties.id = locationSetID;
+        this._resolved.set(locationSetID, geojson);
+      } catch (err) {
+        obj.locationSet = { include: ["Q2"] };
+        obj.locationSetID = "+[Q2]";
       }
-      function skip(k3) {
-        return /^(description|note|fixme)$/.test(k3);
+    }
+    /**
+     * _rebuildIndex
+     * Rebuilds the whichPolygon index with whatever features have been resolved into GeoJSON.
+     */
+    _rebuildIndex() {
+      this._wp = (0, import_which_polygon2.default)({ features: [...this._resolved.values()] });
+    }
+    /**
+     * mergeCustomGeoJSON
+     * Accepts a FeatureCollection-like object containing custom locations
+     * Each feature must have a filename-like `id`, for example: `something.geojson`
+     * {
+     *   "type": "FeatureCollection"
+     *   "features": [
+     *     {
+     *       "type": "Feature",
+     *       "id": "philly_metro.geojson",
+     *       "properties": { … },
+     *       "geometry": { … }
+     *     }
+     *   ]
+     * }
+     *
+     * @param  `fc`  FeatureCollection-like Object containing custom locations
+     */
+    mergeCustomGeoJSON(fc) {
+      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;
+        id2 = id2.toLowerCase();
+        feature3.id = id2;
+        props.id = id2;
+        if (!props.area) {
+          const area = import_geojson_area2.default.geometry(feature3.geometry) / 1e6;
+          props.area = Number(area.toFixed(2));
+        }
+        _loco._cache[id2] = feature3;
+      });
+    }
+    /**
+     * mergeLocationSets
+     * Accepts an Array of Objects containing `locationSet` properties:
+     * [
+     *  { id: 'preset1', locationSet: {…} },
+     *  { id: 'preset2', locationSet: {…} },
+     *  …
+     * ]
+     * After validating, the Objects will be decorated with a `locationSetID` property:
+     * [
+     *  { id: 'preset1', locationSet: {…}, locationSetID: '+[Q2]' },
+     *  { id: 'preset2', locationSet: {…}, locationSetID: '+[Q30]' },
+     *  …
+     * ]
+     *
+     * @param  `objects`  Objects to check - they should have `locationSet` property
+     * @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");
+      objects.forEach((obj) => this._validateLocationSet(obj));
+      this._rebuildIndex();
+      return Promise.resolve(objects);
+    }
+    /**
+     * locationSetID
+     * Returns a locationSetID for a given locationSet (fallback to `+[Q2]`, world)
+     * (The locationSet doesn't necessarily need to be resolved to compute its `id`)
+     *
+     * @param  `locationSet`  A locationSet Object, e.g. `{ include: ['us'] }`
+     * @return  String locationSetID, e.g. `+[Q30]`
+     */
+    locationSetID(locationSet) {
+      let locationSetID;
+      try {
+        locationSetID = _loco.validateLocationSet(locationSet).id;
+      } catch (err) {
+        locationSetID = "+[Q2]";
       }
-      if (skip(k2))
-        return v2;
-      var cleaned = v2.split(";").map(function(s) {
-        return s.trim();
-      }).join(keepSpaces(k2) ? "; " : ";");
-      if (k2.indexOf("website") !== -1 || k2.indexOf("email") !== -1 || cleaned.indexOf("http") === 0) {
-        cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, "");
+      return locationSetID;
+    }
+    /**
+     * feature
+     * Returns the resolved GeoJSON feature for a given locationSetID (fallback to 'world')
+     * A GeoJSON feature:
+     * {
+     *   type: 'Feature',
+     *   id: '+[Q30]',
+     *   properties: { id: '+[Q30]', area: 21817019.17, … },
+     *   geometry: { … }
+     * }
+     *
+     * @param  `locationSetID`  String identifier, e.g. `+[Q30]`
+     * @return  GeoJSON object (fallback to world)
+     */
+    feature(locationSetID = "+[Q2]") {
+      const feature3 = this._resolved.get(locationSetID);
+      return feature3 || this._resolved.get("+[Q2]");
+    }
+    /**
+     * locationSetsAt
+     * Find all the locationSets valid at the given location.
+     * Results include the area (in km²) to facilitate sorting.
+     *
+     * Object of locationSetIDs to areas (in km²)
+     * {
+     *   "+[Q2]": 511207893.3958111,
+     *   "+[Q30]": 21817019.17,
+     *   "+[new_jersey.geojson]": 22390.77,
+     *   …
+     * }
+     *
+     * @param  `loc`  `[lon,lat]` location to query, e.g. `[-74.4813, 40.7967]`
+     * @return  Object of locationSetIDs valid at given location
+     */
+    locationSetsAt(loc) {
+      let result = {};
+      const hits = this._wp(loc, true) || [];
+      const thiz = this;
+      hits.forEach((prop) => {
+        if (prop.id[0] !== "+")
+          return;
+        const locationSetID = prop.id;
+        const area = thiz._knownLocationSets.get(locationSetID);
+        if (area) {
+          result[locationSetID] = area;
+        }
+      });
+      hits.forEach((prop) => {
+        if (prop.id[0] === "+")
+          return;
+        const locationID = prop.id;
+        const included = thiz._locationIncludedIn.get(locationID);
+        (included || []).forEach((locationSetID) => {
+          const area = thiz._knownLocationSets.get(locationSetID);
+          if (area) {
+            result[locationSetID] = area;
+          }
+        });
+      });
+      hits.forEach((prop) => {
+        if (prop.id[0] === "+")
+          return;
+        const locationID = prop.id;
+        const excluded = thiz._locationExcludedIn.get(locationID);
+        (excluded || []).forEach((locationSetID) => {
+          delete result[locationSetID];
+        });
+      });
+      return result;
+    }
+    // Direct access to the location-conflation resolver
+    loco() {
+      return _loco;
+    }
+  };
+  var _sharedLocationManager = new LocationManager();
+
+  // node_modules/lodash-es/_freeGlobal.js
+  var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
+  var freeGlobal_default = freeGlobal;
+
+  // node_modules/lodash-es/_root.js
+  var freeSelf = typeof self == "object" && self && self.Object === Object && self;
+  var root2 = freeGlobal_default || freeSelf || Function("return this")();
+  var root_default = root2;
+
+  // node_modules/lodash-es/_Symbol.js
+  var Symbol2 = root_default.Symbol;
+  var Symbol_default = Symbol2;
+
+  // node_modules/lodash-es/_getRawTag.js
+  var objectProto = Object.prototype;
+  var hasOwnProperty = objectProto.hasOwnProperty;
+  var nativeObjectToString = objectProto.toString;
+  var symToStringTag = Symbol_default ? Symbol_default.toStringTag : void 0;
+  function getRawTag(value) {
+    var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag];
+    try {
+      value[symToStringTag] = void 0;
+      var unmasked = true;
+    } catch (e) {
+    }
+    var result = nativeObjectToString.call(value);
+    if (unmasked) {
+      if (isOwn) {
+        value[symToStringTag] = tag;
+      } else {
+        delete value[symToStringTag];
       }
-      return cleaned;
     }
+    return result;
   }
+  var getRawTag_default = getRawTag;
 
-  // modules/util/detect.js
-  var _detected;
-  function utilDetect(refresh2) {
-    if (_detected && !refresh2)
-      return _detected;
-    _detected = {};
-    const ua = navigator.userAgent;
-    let m = null;
-    m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);
-    if (m !== null) {
-      _detected.browser = m[1];
-      _detected.version = m[2];
+  // node_modules/lodash-es/_objectToString.js
+  var objectProto2 = Object.prototype;
+  var nativeObjectToString2 = objectProto2.toString;
+  function objectToString(value) {
+    return nativeObjectToString2.call(value);
+  }
+  var objectToString_default = objectToString;
+
+  // node_modules/lodash-es/_baseGetTag.js
+  var nullTag = "[object Null]";
+  var undefinedTag = "[object Undefined]";
+  var symToStringTag2 = Symbol_default ? Symbol_default.toStringTag : void 0;
+  function baseGetTag(value) {
+    if (value == null) {
+      return value === void 0 ? undefinedTag : nullTag;
     }
-    if (!_detected.browser) {
-      m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);
-      if (m !== null) {
-        _detected.browser = "msie";
-        _detected.version = m[1];
-      }
+    return symToStringTag2 && symToStringTag2 in Object(value) ? getRawTag_default(value) : objectToString_default(value);
+  }
+  var baseGetTag_default = baseGetTag;
+
+  // node_modules/lodash-es/isObjectLike.js
+  function isObjectLike(value) {
+    return value != null && typeof value == "object";
+  }
+  var isObjectLike_default = isObjectLike;
+
+  // node_modules/lodash-es/isSymbol.js
+  var symbolTag = "[object Symbol]";
+  function isSymbol(value) {
+    return typeof value == "symbol" || isObjectLike_default(value) && baseGetTag_default(value) == symbolTag;
+  }
+  var isSymbol_default = isSymbol;
+
+  // node_modules/lodash-es/_arrayMap.js
+  function arrayMap(array2, iteratee) {
+    var index = -1, length = array2 == null ? 0 : array2.length, result = Array(length);
+    while (++index < length) {
+      result[index] = iteratee(array2[index], index, array2);
     }
-    if (!_detected.browser) {
-      m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);
-      if (m !== null) {
-        _detected.browser = "Opera";
-        _detected.version = m[2];
-      }
+    return result;
+  }
+  var arrayMap_default = arrayMap;
+
+  // node_modules/lodash-es/isArray.js
+  var isArray = Array.isArray;
+  var isArray_default = isArray;
+
+  // node_modules/lodash-es/_baseToString.js
+  var INFINITY = 1 / 0;
+  var symbolProto = Symbol_default ? Symbol_default.prototype : void 0;
+  var symbolToString = symbolProto ? symbolProto.toString : void 0;
+  function baseToString(value) {
+    if (typeof value == "string") {
+      return value;
     }
-    if (!_detected.browser) {
-      m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
-      if (m !== null) {
-        _detected.browser = m[1];
-        _detected.version = m[2];
-        m = ua.match(/version\/([\.\d]+)/i);
-        if (m !== null)
-          _detected.version = m[1];
-      }
+    if (isArray_default(value)) {
+      return arrayMap_default(value, baseToString) + "";
     }
-    if (!_detected.browser) {
-      _detected.browser = navigator.appName;
-      _detected.version = navigator.appVersion;
+    if (isSymbol_default(value)) {
+      return symbolToString ? symbolToString.call(value) : "";
     }
-    _detected.version = _detected.version.split(/\W/).slice(0, 2).join(".");
-    _detected.opera = _detected.browser.toLowerCase() === "opera" && parseFloat(_detected.version) < 15;
-    if (_detected.browser.toLowerCase() === "msie") {
-      _detected.ie = true;
-      _detected.browser = "Internet Explorer";
-      _detected.support = false;
-    } else {
-      _detected.ie = false;
-      _detected.support = true;
+    var result = value + "";
+    return result == "0" && 1 / value == -INFINITY ? "-0" : result;
+  }
+  var baseToString_default = baseToString;
+
+  // node_modules/lodash-es/_trimmedEndIndex.js
+  var reWhitespace = /\s/;
+  function trimmedEndIndex(string) {
+    var index = string.length;
+    while (index-- && reWhitespace.test(string.charAt(index))) {
     }
-    _detected.filedrop = window.FileReader && "ondrop" in window;
-    if (/Win/.test(ua)) {
-      _detected.os = "win";
-      _detected.platform = "Windows";
-    } else if (/Mac/.test(ua)) {
-      _detected.os = "mac";
-      _detected.platform = "Macintosh";
-    } else if (/X11/.test(ua) || /Linux/.test(ua)) {
-      _detected.os = "linux";
-      _detected.platform = "Linux";
-    } else {
-      _detected.os = "win";
-      _detected.platform = "Unknown";
+    return index;
+  }
+  var trimmedEndIndex_default = trimmedEndIndex;
+
+  // node_modules/lodash-es/_baseTrim.js
+  var reTrimStart = /^\s+/;
+  function baseTrim(string) {
+    return string ? string.slice(0, trimmedEndIndex_default(string) + 1).replace(reTrimStart, "") : string;
+  }
+  var baseTrim_default = baseTrim;
+
+  // node_modules/lodash-es/isObject.js
+  function isObject(value) {
+    var type2 = typeof value;
+    return value != null && (type2 == "object" || type2 == "function");
+  }
+  var isObject_default = isObject;
+
+  // node_modules/lodash-es/toNumber.js
+  var NAN = 0 / 0;
+  var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
+  var reIsBinary = /^0b[01]+$/i;
+  var reIsOctal = /^0o[0-7]+$/i;
+  var freeParseInt = parseInt;
+  function toNumber(value) {
+    if (typeof value == "number") {
+      return value;
     }
-    _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || navigator.platform === "MacIntel" && "maxTouchPoints" in navigator && navigator.maxTouchPoints > 1) && /WebKit/.test(ua) && !/Edge/.test(ua) && !window.MSStream;
-    _detected.browserLocales = Array.from(new Set(
-      [navigator.language].concat(navigator.languages || []).concat([
-        navigator.userLanguage
-      ]).filter(Boolean)
-    ));
-    const loc = window.top.location;
-    let origin = loc.origin;
-    if (!origin) {
-      origin = loc.protocol + "//" + loc.hostname + (loc.port ? ":" + loc.port : "");
+    if (isSymbol_default(value)) {
+      return NAN;
     }
-    _detected.host = origin + loc.pathname;
-    return _detected;
+    if (isObject_default(value)) {
+      var other = typeof value.valueOf == "function" ? value.valueOf() : value;
+      value = isObject_default(other) ? other + "" : other;
+    }
+    if (typeof value != "string") {
+      return value === 0 ? value : +value;
+    }
+    value = baseTrim_default(value);
+    var isBinary = reIsBinary.test(value);
+    return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
   }
+  var toNumber_default = toNumber;
 
-  // modules/util/get_set_value.js
-  function utilGetSetValue(selection2, value) {
-    function d3_selection_value(value2) {
-      function valueNull() {
-        delete this.value;
-      }
-      function valueConstant() {
-        if (this.value !== value2) {
-          this.value = value2;
-        }
+  // node_modules/lodash-es/isFunction.js
+  var asyncTag = "[object AsyncFunction]";
+  var funcTag = "[object Function]";
+  var genTag = "[object GeneratorFunction]";
+  var proxyTag = "[object Proxy]";
+  function isFunction(value) {
+    if (!isObject_default(value)) {
+      return false;
+    }
+    var tag = baseGetTag_default(value);
+    return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
+  }
+  var isFunction_default = isFunction;
+
+  // node_modules/lodash-es/_coreJsData.js
+  var coreJsData = root_default["__core-js_shared__"];
+  var coreJsData_default = coreJsData;
+
+  // node_modules/lodash-es/_isMasked.js
+  var maskSrcKey = function() {
+    var uid = /[^.]+$/.exec(coreJsData_default && coreJsData_default.keys && coreJsData_default.keys.IE_PROTO || "");
+    return uid ? "Symbol(src)_1." + uid : "";
+  }();
+  function isMasked(func) {
+    return !!maskSrcKey && maskSrcKey in func;
+  }
+  var isMasked_default = isMasked;
+
+  // node_modules/lodash-es/_toSource.js
+  var funcProto = Function.prototype;
+  var funcToString = funcProto.toString;
+  function toSource(func) {
+    if (func != null) {
+      try {
+        return funcToString.call(func);
+      } catch (e) {
       }
-      function valueFunction() {
-        var x = value2.apply(this, arguments);
-        if (x === null || x === void 0) {
-          delete this.value;
-        } else if (this.value !== x) {
-          this.value = x;
-        }
+      try {
+        return func + "";
+      } catch (e) {
       }
-      return value2 === null || value2 === void 0 ? valueNull : typeof value2 === "function" ? valueFunction : valueConstant;
     }
-    if (arguments.length === 1) {
-      return selection2.property("value");
+    return "";
+  }
+  var toSource_default = toSource;
+
+  // node_modules/lodash-es/_baseIsNative.js
+  var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
+  var reIsHostCtor = /^\[object .+?Constructor\]$/;
+  var funcProto2 = Function.prototype;
+  var objectProto3 = Object.prototype;
+  var funcToString2 = funcProto2.toString;
+  var hasOwnProperty2 = objectProto3.hasOwnProperty;
+  var reIsNative = RegExp(
+    "^" + funcToString2.call(hasOwnProperty2).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$"
+  );
+  function baseIsNative(value) {
+    if (!isObject_default(value) || isMasked_default(value)) {
+      return false;
     }
-    return selection2.each(d3_selection_value(value));
+    var pattern = isFunction_default(value) ? reIsNative : reIsHostCtor;
+    return pattern.test(toSource_default(value));
   }
+  var baseIsNative_default = baseIsNative;
 
-  // modules/util/keybinding.js
-  function utilKeybinding(namespace) {
-    var _keybindings = {};
-    function testBindings(d3_event, isCapturing) {
-      var didMatch = false;
-      var bindings = Object.keys(_keybindings).map(function(id2) {
-        return _keybindings[id2];
-      });
-      var i2, binding;
-      for (i2 = 0; i2 < bindings.length; i2++) {
-        binding = bindings[i2];
-        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;
-      for (i2 = 0; i2 < bindings.length; i2++) {
-        binding = bindings[i2];
-        if (binding.event.modifiers.shiftKey)
-          continue;
-        if (!!binding.capture !== isCapturing)
-          continue;
-        if (matches(d3_event, binding, false)) {
-          binding.callback(d3_event);
-          break;
-        }
+  // node_modules/lodash-es/_getValue.js
+  function getValue(object, key) {
+    return object == null ? void 0 : object[key];
+  }
+  var getValue_default = getValue;
+
+  // node_modules/lodash-es/_getNative.js
+  function getNative(object, key) {
+    var value = getValue_default(object, key);
+    return baseIsNative_default(value) ? value : void 0;
+  }
+  var getNative_default = getNative;
+
+  // node_modules/lodash-es/_WeakMap.js
+  var WeakMap = getNative_default(root_default, "WeakMap");
+  var WeakMap_default = WeakMap;
+
+  // node_modules/lodash-es/_isIndex.js
+  var MAX_SAFE_INTEGER = 9007199254740991;
+  var reIsUint = /^(?:0|[1-9]\d*)$/;
+  function isIndex(value, length) {
+    var type2 = typeof value;
+    length = length == null ? MAX_SAFE_INTEGER : length;
+    return !!length && (type2 == "number" || type2 != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length);
+  }
+  var isIndex_default = isIndex;
+
+  // node_modules/lodash-es/eq.js
+  function eq(value, other) {
+    return value === other || value !== value && other !== other;
+  }
+  var eq_default = eq;
+
+  // node_modules/lodash-es/isLength.js
+  var MAX_SAFE_INTEGER2 = 9007199254740991;
+  function isLength(value) {
+    return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER2;
+  }
+  var isLength_default = isLength;
+
+  // node_modules/lodash-es/isArrayLike.js
+  function isArrayLike(value) {
+    return value != null && isLength_default(value.length) && !isFunction_default(value);
+  }
+  var isArrayLike_default = isArrayLike;
+
+  // node_modules/lodash-es/_isPrototype.js
+  var objectProto4 = Object.prototype;
+  function isPrototype(value) {
+    var Ctor = value && value.constructor, proto = typeof Ctor == "function" && Ctor.prototype || objectProto4;
+    return value === proto;
+  }
+  var isPrototype_default = isPrototype;
+
+  // node_modules/lodash-es/_baseTimes.js
+  function baseTimes(n2, iteratee) {
+    var index = -1, result = Array(n2);
+    while (++index < n2) {
+      result[index] = iteratee(index);
+    }
+    return result;
+  }
+  var baseTimes_default = baseTimes;
+
+  // node_modules/lodash-es/_baseIsArguments.js
+  var argsTag = "[object Arguments]";
+  function baseIsArguments(value) {
+    return isObjectLike_default(value) && baseGetTag_default(value) == argsTag;
+  }
+  var baseIsArguments_default = baseIsArguments;
+
+  // node_modules/lodash-es/isArguments.js
+  var objectProto5 = Object.prototype;
+  var hasOwnProperty3 = objectProto5.hasOwnProperty;
+  var propertyIsEnumerable = objectProto5.propertyIsEnumerable;
+  var isArguments = baseIsArguments_default(function() {
+    return arguments;
+  }()) ? baseIsArguments_default : function(value) {
+    return isObjectLike_default(value) && hasOwnProperty3.call(value, "callee") && !propertyIsEnumerable.call(value, "callee");
+  };
+  var isArguments_default = isArguments;
+
+  // node_modules/lodash-es/stubFalse.js
+  function stubFalse() {
+    return false;
+  }
+  var stubFalse_default = stubFalse;
+
+  // node_modules/lodash-es/isBuffer.js
+  var freeExports = typeof exports == "object" && exports && !exports.nodeType && exports;
+  var freeModule = freeExports && typeof module == "object" && module && !module.nodeType && module;
+  var moduleExports = freeModule && freeModule.exports === freeExports;
+  var Buffer2 = moduleExports ? root_default.Buffer : void 0;
+  var nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : void 0;
+  var isBuffer = nativeIsBuffer || stubFalse_default;
+  var isBuffer_default = isBuffer;
+
+  // node_modules/lodash-es/_baseIsTypedArray.js
+  var argsTag2 = "[object Arguments]";
+  var arrayTag = "[object Array]";
+  var boolTag = "[object Boolean]";
+  var dateTag = "[object Date]";
+  var errorTag = "[object Error]";
+  var funcTag2 = "[object Function]";
+  var mapTag = "[object Map]";
+  var numberTag = "[object Number]";
+  var objectTag = "[object Object]";
+  var regexpTag = "[object RegExp]";
+  var setTag = "[object Set]";
+  var stringTag = "[object String]";
+  var weakMapTag = "[object WeakMap]";
+  var arrayBufferTag = "[object ArrayBuffer]";
+  var dataViewTag = "[object DataView]";
+  var float32Tag = "[object Float32Array]";
+  var float64Tag = "[object Float64Array]";
+  var int8Tag = "[object Int8Array]";
+  var int16Tag = "[object Int16Array]";
+  var int32Tag = "[object Int32Array]";
+  var uint8Tag = "[object Uint8Array]";
+  var uint8ClampedTag = "[object Uint8ClampedArray]";
+  var uint16Tag = "[object Uint16Array]";
+  var uint32Tag = "[object Uint32Array]";
+  var typedArrayTags = {};
+  typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true;
+  typedArrayTags[argsTag2] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag2] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+  function baseIsTypedArray(value) {
+    return isObjectLike_default(value) && isLength_default(value.length) && !!typedArrayTags[baseGetTag_default(value)];
+  }
+  var baseIsTypedArray_default = baseIsTypedArray;
+
+  // node_modules/lodash-es/_baseUnary.js
+  function baseUnary(func) {
+    return function(value) {
+      return func(value);
+    };
+  }
+  var baseUnary_default = baseUnary;
+
+  // node_modules/lodash-es/_nodeUtil.js
+  var freeExports2 = typeof exports == "object" && exports && !exports.nodeType && exports;
+  var freeModule2 = freeExports2 && typeof module == "object" && module && !module.nodeType && module;
+  var moduleExports2 = freeModule2 && freeModule2.exports === freeExports2;
+  var freeProcess = moduleExports2 && freeGlobal_default.process;
+  var nodeUtil = function() {
+    try {
+      var types = freeModule2 && freeModule2.require && freeModule2.require("util").types;
+      if (types) {
+        return types;
       }
-      function matches(d3_event2, binding2, testShift) {
-        var event = d3_event2;
-        var isMatch = false;
-        var tryKeyCode = true;
-        if (event.key !== void 0) {
-          tryKeyCode = event.key.charCodeAt(0) > 127;
-          isMatch = true;
-          if (binding2.event.key === void 0) {
-            isMatch = false;
-          } else if (Array.isArray(binding2.event.key)) {
-            if (binding2.event.key.map(function(s) {
-              return s.toLowerCase();
-            }).indexOf(event.key.toLowerCase()) === -1) {
-              isMatch = false;
-            }
-          } else {
-            if (event.key.toLowerCase() !== binding2.event.key.toLowerCase()) {
-              isMatch = false;
-            }
-          }
-        }
-        if (!isMatch && (tryKeyCode || binding2.event.modifiers.altKey)) {
-          isMatch = event.keyCode === binding2.event.keyCode;
-        }
-        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.metaKey !== binding2.event.modifiers.metaKey)
-          return false;
-        if (testShift && event.shiftKey !== binding2.event.modifiers.shiftKey)
-          return false;
-        return true;
+      return freeProcess && freeProcess.binding && freeProcess.binding("util");
+    } catch (e) {
+    }
+  }();
+  var nodeUtil_default = nodeUtil;
+
+  // node_modules/lodash-es/isTypedArray.js
+  var nodeIsTypedArray = nodeUtil_default && nodeUtil_default.isTypedArray;
+  var isTypedArray = nodeIsTypedArray ? baseUnary_default(nodeIsTypedArray) : baseIsTypedArray_default;
+  var isTypedArray_default = isTypedArray;
+
+  // node_modules/lodash-es/_arrayLikeKeys.js
+  var objectProto6 = Object.prototype;
+  var hasOwnProperty4 = objectProto6.hasOwnProperty;
+  function arrayLikeKeys(value, inherited) {
+    var isArr = isArray_default(value), isArg = !isArr && isArguments_default(value), isBuff = !isArr && !isArg && isBuffer_default(value), isType = !isArr && !isArg && !isBuff && isTypedArray_default(value), skipIndexes = isArr || isArg || isBuff || isType, result = skipIndexes ? baseTimes_default(value.length, String) : [], length = result.length;
+    for (var key in value) {
+      if ((inherited || hasOwnProperty4.call(value, key)) && !(skipIndexes && // Safari 9 has enumerable `arguments.length` in strict mode.
+      (key == "length" || // Node.js 0.10 has enumerable non-index properties on buffers.
+      isBuff && (key == "offset" || key == "parent") || // PhantomJS 2 has enumerable non-index properties on typed arrays.
+      isType && (key == "buffer" || key == "byteLength" || key == "byteOffset") || // Skip index properties.
+      isIndex_default(key, length)))) {
+        result.push(key);
       }
     }
-    function capture(d3_event) {
-      testBindings(d3_event, true);
+    return result;
+  }
+  var arrayLikeKeys_default = arrayLikeKeys;
+
+  // node_modules/lodash-es/_overArg.js
+  function overArg(func, transform2) {
+    return function(arg) {
+      return func(transform2(arg));
+    };
+  }
+  var overArg_default = overArg;
+
+  // node_modules/lodash-es/_nativeKeys.js
+  var nativeKeys = overArg_default(Object.keys, Object);
+  var nativeKeys_default = nativeKeys;
+
+  // node_modules/lodash-es/_baseKeys.js
+  var objectProto7 = Object.prototype;
+  var hasOwnProperty5 = objectProto7.hasOwnProperty;
+  function baseKeys(object) {
+    if (!isPrototype_default(object)) {
+      return nativeKeys_default(object);
     }
-    function bubble(d3_event) {
-      var tagName = select_default2(d3_event.target).node().tagName;
-      if (tagName === "INPUT" || tagName === "SELECT" || tagName === "TEXTAREA") {
-        return;
+    var result = [];
+    for (var key in Object(object)) {
+      if (hasOwnProperty5.call(object, key) && key != "constructor") {
+        result.push(key);
       }
-      testBindings(d3_event, false);
-    }
-    function keybinding(selection2) {
-      selection2 = selection2 || select_default2(document);
-      selection2.on("keydown.capture." + namespace, capture, true);
-      selection2.on("keydown.bubble." + namespace, bubble, false);
-      return keybinding;
     }
-    keybinding.unbind = function(selection2) {
-      _keybindings = [];
-      selection2 = selection2 || select_default2(document);
-      selection2.on("keydown.capture." + namespace, null);
-      selection2.on("keydown.bubble." + namespace, null);
-      return keybinding;
-    };
-    keybinding.clear = function() {
-      _keybindings = {};
-      return keybinding;
-    };
-    keybinding.off = function(codes, capture2) {
-      var arr = utilArrayUniq([].concat(codes));
-      for (var i2 = 0; i2 < arr.length; i2++) {
-        var id2 = arr[i2] + (capture2 ? "-capture" : "-bubble");
-        delete _keybindings[id2];
+    return result;
+  }
+  var baseKeys_default = baseKeys;
+
+  // node_modules/lodash-es/keys.js
+  function keys(object) {
+    return isArrayLike_default(object) ? arrayLikeKeys_default(object) : baseKeys_default(object);
+  }
+  var keys_default = keys;
+
+  // node_modules/lodash-es/_nativeCreate.js
+  var nativeCreate = getNative_default(Object, "create");
+  var nativeCreate_default = nativeCreate;
+
+  // node_modules/lodash-es/_hashClear.js
+  function hashClear() {
+    this.__data__ = nativeCreate_default ? nativeCreate_default(null) : {};
+    this.size = 0;
+  }
+  var hashClear_default = hashClear;
+
+  // node_modules/lodash-es/_hashDelete.js
+  function hashDelete(key) {
+    var result = this.has(key) && delete this.__data__[key];
+    this.size -= result ? 1 : 0;
+    return result;
+  }
+  var hashDelete_default = hashDelete;
+
+  // node_modules/lodash-es/_hashGet.js
+  var HASH_UNDEFINED = "__lodash_hash_undefined__";
+  var objectProto8 = Object.prototype;
+  var hasOwnProperty6 = objectProto8.hasOwnProperty;
+  function hashGet(key) {
+    var data = this.__data__;
+    if (nativeCreate_default) {
+      var result = data[key];
+      return result === HASH_UNDEFINED ? void 0 : result;
+    }
+    return hasOwnProperty6.call(data, key) ? data[key] : void 0;
+  }
+  var hashGet_default = hashGet;
+
+  // node_modules/lodash-es/_hashHas.js
+  var objectProto9 = Object.prototype;
+  var hasOwnProperty7 = objectProto9.hasOwnProperty;
+  function hashHas(key) {
+    var data = this.__data__;
+    return nativeCreate_default ? data[key] !== void 0 : hasOwnProperty7.call(data, key);
+  }
+  var hashHas_default = hashHas;
+
+  // node_modules/lodash-es/_hashSet.js
+  var HASH_UNDEFINED2 = "__lodash_hash_undefined__";
+  function hashSet(key, value) {
+    var data = this.__data__;
+    this.size += this.has(key) ? 0 : 1;
+    data[key] = nativeCreate_default && value === void 0 ? HASH_UNDEFINED2 : value;
+    return this;
+  }
+  var hashSet_default = hashSet;
+
+  // node_modules/lodash-es/_Hash.js
+  function Hash(entries) {
+    var index = -1, length = entries == null ? 0 : entries.length;
+    this.clear();
+    while (++index < length) {
+      var entry = entries[index];
+      this.set(entry[0], entry[1]);
+    }
+  }
+  Hash.prototype.clear = hashClear_default;
+  Hash.prototype["delete"] = hashDelete_default;
+  Hash.prototype.get = hashGet_default;
+  Hash.prototype.has = hashHas_default;
+  Hash.prototype.set = hashSet_default;
+  var Hash_default = Hash;
+
+  // node_modules/lodash-es/_listCacheClear.js
+  function listCacheClear() {
+    this.__data__ = [];
+    this.size = 0;
+  }
+  var listCacheClear_default = listCacheClear;
+
+  // node_modules/lodash-es/_assocIndexOf.js
+  function assocIndexOf(array2, key) {
+    var length = array2.length;
+    while (length--) {
+      if (eq_default(array2[length][0], key)) {
+        return length;
       }
-      return keybinding;
+    }
+    return -1;
+  }
+  var assocIndexOf_default = assocIndexOf;
+
+  // node_modules/lodash-es/_listCacheDelete.js
+  var arrayProto = Array.prototype;
+  var splice = arrayProto.splice;
+  function listCacheDelete(key) {
+    var data = this.__data__, index = assocIndexOf_default(data, key);
+    if (index < 0) {
+      return false;
+    }
+    var lastIndex = data.length - 1;
+    if (index == lastIndex) {
+      data.pop();
+    } else {
+      splice.call(data, index, 1);
+    }
+    --this.size;
+    return true;
+  }
+  var listCacheDelete_default = listCacheDelete;
+
+  // node_modules/lodash-es/_listCacheGet.js
+  function listCacheGet(key) {
+    var data = this.__data__, index = assocIndexOf_default(data, key);
+    return index < 0 ? void 0 : data[index][1];
+  }
+  var listCacheGet_default = listCacheGet;
+
+  // node_modules/lodash-es/_listCacheHas.js
+  function listCacheHas(key) {
+    return assocIndexOf_default(this.__data__, key) > -1;
+  }
+  var listCacheHas_default = listCacheHas;
+
+  // node_modules/lodash-es/_listCacheSet.js
+  function listCacheSet(key, value) {
+    var data = this.__data__, index = assocIndexOf_default(data, key);
+    if (index < 0) {
+      ++this.size;
+      data.push([key, value]);
+    } else {
+      data[index][1] = value;
+    }
+    return this;
+  }
+  var listCacheSet_default = listCacheSet;
+
+  // node_modules/lodash-es/_ListCache.js
+  function ListCache(entries) {
+    var index = -1, length = entries == null ? 0 : entries.length;
+    this.clear();
+    while (++index < length) {
+      var entry = entries[index];
+      this.set(entry[0], entry[1]);
+    }
+  }
+  ListCache.prototype.clear = listCacheClear_default;
+  ListCache.prototype["delete"] = listCacheDelete_default;
+  ListCache.prototype.get = listCacheGet_default;
+  ListCache.prototype.has = listCacheHas_default;
+  ListCache.prototype.set = listCacheSet_default;
+  var ListCache_default = ListCache;
+
+  // node_modules/lodash-es/_Map.js
+  var Map2 = getNative_default(root_default, "Map");
+  var Map_default = Map2;
+
+  // node_modules/lodash-es/_mapCacheClear.js
+  function mapCacheClear() {
+    this.size = 0;
+    this.__data__ = {
+      "hash": new Hash_default(),
+      "map": new (Map_default || ListCache_default)(),
+      "string": new Hash_default()
     };
-    keybinding.on = function(codes, callback, capture2) {
-      if (typeof callback !== "function") {
-        return keybinding.off(codes, capture2);
-      }
-      var arr = utilArrayUniq([].concat(codes));
-      for (var i2 = 0; i2 < arr.length; i2++) {
-        var id2 = arr[i2] + (capture2 ? "-capture" : "-bubble");
-        var binding = {
-          id: id2,
-          capture: capture2,
-          callback,
-          event: {
-            key: void 0,
-            keyCode: 0,
-            modifiers: {
-              shiftKey: false,
-              ctrlKey: false,
-              altKey: false,
-              metaKey: false
-            }
-          }
-        };
-        if (_keybindings[id2]) {
-          console.warn('warning: duplicate keybinding for "' + id2 + '"');
-        }
-        _keybindings[id2] = binding;
-        var matches = arr[i2].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
-        for (var j2 = 0; j2 < matches.length; 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;
-          } else {
-            binding.event.key = utilKeybinding.keys[matches[j2]] || matches[j2];
-            if (matches[j2] in utilKeybinding.keyCodes) {
-              binding.event.keyCode = utilKeybinding.keyCodes[matches[j2]];
-            }
-          }
-        }
-      }
-      return keybinding;
+  }
+  var mapCacheClear_default = mapCacheClear;
+
+  // node_modules/lodash-es/_isKeyable.js
+  function isKeyable(value) {
+    var type2 = typeof value;
+    return type2 == "string" || type2 == "number" || type2 == "symbol" || type2 == "boolean" ? value !== "__proto__" : value === null;
+  }
+  var isKeyable_default = isKeyable;
+
+  // node_modules/lodash-es/_getMapData.js
+  function getMapData(map2, key) {
+    var data = map2.__data__;
+    return isKeyable_default(key) ? data[typeof key == "string" ? "string" : "hash"] : data.map;
+  }
+  var getMapData_default = getMapData;
+
+  // node_modules/lodash-es/_mapCacheDelete.js
+  function mapCacheDelete(key) {
+    var result = getMapData_default(this, key)["delete"](key);
+    this.size -= result ? 1 : 0;
+    return result;
+  }
+  var mapCacheDelete_default = mapCacheDelete;
+
+  // node_modules/lodash-es/_mapCacheGet.js
+  function mapCacheGet(key) {
+    return getMapData_default(this, key).get(key);
+  }
+  var mapCacheGet_default = mapCacheGet;
+
+  // node_modules/lodash-es/_mapCacheHas.js
+  function mapCacheHas(key) {
+    return getMapData_default(this, key).has(key);
+  }
+  var mapCacheHas_default = mapCacheHas;
+
+  // node_modules/lodash-es/_mapCacheSet.js
+  function mapCacheSet(key, value) {
+    var data = getMapData_default(this, key), size = data.size;
+    data.set(key, value);
+    this.size += data.size == size ? 0 : 1;
+    return this;
+  }
+  var mapCacheSet_default = mapCacheSet;
+
+  // node_modules/lodash-es/_MapCache.js
+  function MapCache(entries) {
+    var index = -1, length = entries == null ? 0 : entries.length;
+    this.clear();
+    while (++index < length) {
+      var entry = entries[index];
+      this.set(entry[0], entry[1]);
+    }
+  }
+  MapCache.prototype.clear = mapCacheClear_default;
+  MapCache.prototype["delete"] = mapCacheDelete_default;
+  MapCache.prototype.get = mapCacheGet_default;
+  MapCache.prototype.has = mapCacheHas_default;
+  MapCache.prototype.set = mapCacheSet_default;
+  var MapCache_default = MapCache;
+
+  // node_modules/lodash-es/toString.js
+  function toString(value) {
+    return value == null ? "" : baseToString_default(value);
+  }
+  var toString_default = toString;
+
+  // node_modules/lodash-es/_arrayPush.js
+  function arrayPush(array2, values) {
+    var index = -1, length = values.length, offset = array2.length;
+    while (++index < length) {
+      array2[offset + index] = values[index];
+    }
+    return array2;
+  }
+  var arrayPush_default = arrayPush;
+
+  // node_modules/lodash-es/_basePropertyOf.js
+  function basePropertyOf(object) {
+    return function(key) {
+      return object == null ? void 0 : object[key];
     };
-    return keybinding;
   }
-  utilKeybinding.modifierCodes = {
-    "\u21E7": 16,
-    shift: 16,
-    "\u2303": 17,
-    ctrl: 17,
-    "\u2325": 18,
-    alt: 18,
-    option: 18,
-    "\u2318": 91,
-    meta: 91,
-    cmd: 91,
-    "super": 91,
-    win: 91
-  };
-  utilKeybinding.modifierProperties = {
-    16: "shiftKey",
-    17: "ctrlKey",
-    18: "altKey",
-    91: "metaKey"
-  };
-  utilKeybinding.plusKeys = ["plus", "ffplus", "=", "ffequals", "\u2260", "\xB1"];
-  utilKeybinding.minusKeys = ["_", "-", "ffminus", "dash", "\u2013", "\u2014"];
-  utilKeybinding.keys = {
-    "\u232B": "Backspace",
-    backspace: "Backspace",
-    "\u21E5": "Tab",
-    "\u21C6": "Tab",
-    tab: "Tab",
-    "\u21A9": "Enter",
-    "\u21B5": "Enter",
-    "\u23CE": "Enter",
-    "return": "Enter",
-    enter: "Enter",
-    "\u2305": "Enter",
-    "pause": "Pause",
-    "pause-break": "Pause",
-    "\u21EA": "CapsLock",
-    caps: "CapsLock",
-    "caps-lock": "CapsLock",
-    "\u238B": ["Escape", "Esc"],
-    escape: ["Escape", "Esc"],
-    esc: ["Escape", "Esc"],
-    space: [" ", "Spacebar"],
-    "\u2196": "PageUp",
-    pgup: "PageUp",
-    "page-up": "PageUp",
-    "\u2198": "PageDown",
-    pgdown: "PageDown",
-    "page-down": "PageDown",
-    "\u21DF": "End",
-    end: "End",
-    "\u21DE": "Home",
-    home: "Home",
-    ins: "Insert",
-    insert: "Insert",
-    "\u2326": ["Delete", "Del"],
-    del: ["Delete", "Del"],
-    "delete": ["Delete", "Del"],
-    "\u2190": ["ArrowLeft", "Left"],
-    left: ["ArrowLeft", "Left"],
-    "arrow-left": ["ArrowLeft", "Left"],
-    "\u2191": ["ArrowUp", "Up"],
-    up: ["ArrowUp", "Up"],
-    "arrow-up": ["ArrowUp", "Up"],
-    "\u2192": ["ArrowRight", "Right"],
-    right: ["ArrowRight", "Right"],
-    "arrow-right": ["ArrowRight", "Right"],
-    "\u2193": ["ArrowDown", "Down"],
-    down: ["ArrowDown", "Down"],
-    "arrow-down": ["ArrowDown", "Down"],
-    "*": ["*", "Multiply"],
-    star: ["*", "Multiply"],
-    asterisk: ["*", "Multiply"],
-    multiply: ["*", "Multiply"],
-    "+": ["+", "Add"],
-    "plus": ["+", "Add"],
-    "-": ["-", "Subtract"],
-    subtract: ["-", "Subtract"],
-    "dash": ["-", "Subtract"],
-    semicolon: ";",
-    equals: "=",
-    comma: ",",
-    period: ".",
-    "full-stop": ".",
-    slash: "/",
-    "forward-slash": "/",
-    tick: "`",
-    "back-quote": "`",
-    "open-bracket": "[",
-    "back-slash": "\\",
-    "close-bracket": "]",
-    quote: "'",
-    apostrophe: "'",
-    "num-0": "0",
-    "num-1": "1",
-    "num-2": "2",
-    "num-3": "3",
-    "num-4": "4",
-    "num-5": "5",
-    "num-6": "6",
-    "num-7": "7",
-    "num-8": "8",
-    "num-9": "9",
-    f1: "F1",
-    f2: "F2",
-    f3: "F3",
-    f4: "F4",
-    f5: "F5",
-    f6: "F6",
-    f7: "F7",
-    f8: "F8",
-    f9: "F9",
-    f10: "F10",
-    f11: "F11",
-    f12: "F12",
-    f13: "F13",
-    f14: "F14",
-    f15: "F15",
-    f16: "F16",
-    f17: "F17",
-    f18: "F18",
-    f19: "F19",
-    f20: "F20",
-    f21: "F21",
-    f22: "F22",
-    f23: "F23",
-    f24: "F24",
-    f25: "F25"
-  };
-  utilKeybinding.keyCodes = {
-    "\u232B": 8,
-    backspace: 8,
-    "\u21E5": 9,
-    "\u21C6": 9,
-    tab: 9,
-    "\u21A9": 13,
-    "\u21B5": 13,
-    "\u23CE": 13,
-    "return": 13,
-    enter: 13,
-    "\u2305": 13,
-    "pause": 19,
-    "pause-break": 19,
-    "\u21EA": 20,
-    caps: 20,
-    "caps-lock": 20,
-    "\u238B": 27,
-    escape: 27,
-    esc: 27,
-    space: 32,
-    "\u2196": 33,
-    pgup: 33,
-    "page-up": 33,
-    "\u2198": 34,
-    pgdown: 34,
-    "page-down": 34,
-    "\u21DF": 35,
-    end: 35,
-    "\u21DE": 36,
-    home: 36,
-    ins: 45,
-    insert: 45,
-    "\u2326": 46,
-    del: 46,
-    "delete": 46,
-    "\u2190": 37,
-    left: 37,
-    "arrow-left": 37,
-    "\u2191": 38,
-    up: 38,
-    "arrow-up": 38,
-    "\u2192": 39,
-    right: 39,
-    "arrow-right": 39,
-    "\u2193": 40,
-    down: 40,
-    "arrow-down": 40,
-    "ffequals": 61,
-    "*": 106,
-    star: 106,
-    asterisk: 106,
-    multiply: 106,
-    "+": 107,
-    "plus": 107,
-    "-": 109,
-    subtract: 109,
-    "|": 124,
-    "ffplus": 171,
-    "ffminus": 173,
-    ";": 186,
-    semicolon: 186,
-    "=": 187,
-    "equals": 187,
-    ",": 188,
-    comma: 188,
-    "dash": 189,
-    ".": 190,
-    period: 190,
-    "full-stop": 190,
-    "/": 191,
-    slash: 191,
-    "forward-slash": 191,
-    "`": 192,
-    tick: 192,
-    "back-quote": 192,
-    "[": 219,
-    "open-bracket": 219,
-    "\\": 220,
-    "back-slash": 220,
-    "]": 221,
-    "close-bracket": 221,
-    "'": 222,
-    quote: 222,
-    apostrophe: 222
-  };
-  var i = 95;
-  var n = 0;
-  while (++i < 106) {
-    utilKeybinding.keyCodes["num-" + n] = i;
-    ++n;
+  var basePropertyOf_default = basePropertyOf;
+
+  // node_modules/lodash-es/_stackClear.js
+  function stackClear() {
+    this.__data__ = new ListCache_default();
+    this.size = 0;
   }
-  i = 47;
-  n = 0;
-  while (++i < 58) {
-    utilKeybinding.keyCodes[n] = i;
-    ++n;
+  var stackClear_default = stackClear;
+
+  // node_modules/lodash-es/_stackDelete.js
+  function stackDelete(key) {
+    var data = this.__data__, result = data["delete"](key);
+    this.size = data.size;
+    return result;
   }
-  i = 111;
-  n = 1;
-  while (++i < 136) {
-    utilKeybinding.keyCodes["f" + n] = i;
-    ++n;
+  var stackDelete_default = stackDelete;
+
+  // node_modules/lodash-es/_stackGet.js
+  function stackGet(key) {
+    return this.__data__.get(key);
   }
-  i = 64;
-  while (++i < 91) {
-    utilKeybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
+  var stackGet_default = stackGet;
+
+  // node_modules/lodash-es/_stackHas.js
+  function stackHas(key) {
+    return this.__data__.has(key);
   }
+  var stackHas_default = stackHas;
 
-  // modules/util/object.js
-  function utilObjectOmit(obj, omitKeys) {
-    return Object.keys(obj).reduce(function(result, key) {
-      if (omitKeys.indexOf(key) === -1) {
-        result[key] = obj[key];
+  // node_modules/lodash-es/_stackSet.js
+  var LARGE_ARRAY_SIZE = 200;
+  function stackSet(key, value) {
+    var data = this.__data__;
+    if (data instanceof ListCache_default) {
+      var pairs = data.__data__;
+      if (!Map_default || pairs.length < LARGE_ARRAY_SIZE - 1) {
+        pairs.push([key, value]);
+        this.size = ++data.size;
+        return this;
       }
-      return result;
-    }, {});
+      data = this.__data__ = new MapCache_default(pairs);
+    }
+    data.set(key, value);
+    this.size = data.size;
+    return this;
   }
+  var stackSet_default = stackSet;
 
-  // modules/util/rebind.js
-  function utilRebind(target, source) {
-    var i2 = 1, n2 = arguments.length, method;
-    while (++i2 < n2) {
-      target[method = arguments[i2]] = d3_rebind(target, source, source[method]);
+  // node_modules/lodash-es/_Stack.js
+  function Stack(entries) {
+    var data = this.__data__ = new ListCache_default(entries);
+    this.size = data.size;
+  }
+  Stack.prototype.clear = stackClear_default;
+  Stack.prototype["delete"] = stackDelete_default;
+  Stack.prototype.get = stackGet_default;
+  Stack.prototype.has = stackHas_default;
+  Stack.prototype.set = stackSet_default;
+  var Stack_default = Stack;
+
+  // node_modules/lodash-es/_arrayFilter.js
+  function arrayFilter(array2, predicate) {
+    var index = -1, length = array2 == null ? 0 : array2.length, resIndex = 0, result = [];
+    while (++index < length) {
+      var value = array2[index];
+      if (predicate(value, index, array2)) {
+        result[resIndex++] = value;
+      }
     }
-    return target;
+    return result;
   }
-  function d3_rebind(target, source, method) {
-    return function() {
-      var value = method.apply(source, arguments);
-      return value === source ? target : value;
-    };
+  var arrayFilter_default = arrayFilter;
+
+  // node_modules/lodash-es/stubArray.js
+  function stubArray() {
+    return [];
   }
+  var stubArray_default = stubArray;
 
-  // modules/util/session_mutex.js
-  function utilSessionMutex(name) {
-    var mutex = {};
-    var intervalID;
-    function renew() {
-      var expires = new Date();
-      expires.setSeconds(expires.getSeconds() + 5);
-      document.cookie = name + "=1; expires=" + expires.toUTCString() + "; sameSite=strict";
+  // node_modules/lodash-es/_getSymbols.js
+  var objectProto10 = Object.prototype;
+  var propertyIsEnumerable2 = objectProto10.propertyIsEnumerable;
+  var nativeGetSymbols = Object.getOwnPropertySymbols;
+  var getSymbols = !nativeGetSymbols ? stubArray_default : function(object) {
+    if (object == null) {
+      return [];
     }
-    mutex.lock = function() {
-      if (intervalID)
-        return true;
-      var cookie = document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + name + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1");
-      if (cookie)
-        return false;
-      renew();
-      intervalID = window.setInterval(renew, 4e3);
-      return true;
-    };
-    mutex.unlock = function() {
-      if (!intervalID)
-        return;
-      document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict";
-      clearInterval(intervalID);
-      intervalID = null;
-    };
-    mutex.locked = function() {
-      return !!intervalID;
+    object = Object(object);
+    return arrayFilter_default(nativeGetSymbols(object), function(symbol) {
+      return propertyIsEnumerable2.call(object, symbol);
+    });
+  };
+  var getSymbols_default = getSymbols;
+
+  // node_modules/lodash-es/_baseGetAllKeys.js
+  function baseGetAllKeys(object, keysFunc, symbolsFunc) {
+    var result = keysFunc(object);
+    return isArray_default(object) ? result : arrayPush_default(result, symbolsFunc(object));
+  }
+  var baseGetAllKeys_default = baseGetAllKeys;
+
+  // node_modules/lodash-es/_getAllKeys.js
+  function getAllKeys(object) {
+    return baseGetAllKeys_default(object, keys_default, getSymbols_default);
+  }
+  var getAllKeys_default = getAllKeys;
+
+  // node_modules/lodash-es/_DataView.js
+  var DataView2 = getNative_default(root_default, "DataView");
+  var DataView_default = DataView2;
+
+  // node_modules/lodash-es/_Promise.js
+  var Promise2 = getNative_default(root_default, "Promise");
+  var Promise_default = Promise2;
+
+  // node_modules/lodash-es/_Set.js
+  var Set2 = getNative_default(root_default, "Set");
+  var Set_default = Set2;
+
+  // node_modules/lodash-es/_getTag.js
+  var mapTag2 = "[object Map]";
+  var objectTag2 = "[object Object]";
+  var promiseTag = "[object Promise]";
+  var setTag2 = "[object Set]";
+  var weakMapTag2 = "[object WeakMap]";
+  var dataViewTag2 = "[object DataView]";
+  var dataViewCtorString = toSource_default(DataView_default);
+  var mapCtorString = toSource_default(Map_default);
+  var promiseCtorString = toSource_default(Promise_default);
+  var setCtorString = toSource_default(Set_default);
+  var weakMapCtorString = toSource_default(WeakMap_default);
+  var getTag = baseGetTag_default;
+  if (DataView_default && getTag(new DataView_default(new ArrayBuffer(1))) != dataViewTag2 || Map_default && getTag(new Map_default()) != mapTag2 || Promise_default && getTag(Promise_default.resolve()) != promiseTag || Set_default && getTag(new Set_default()) != setTag2 || WeakMap_default && getTag(new WeakMap_default()) != weakMapTag2) {
+    getTag = function(value) {
+      var result = baseGetTag_default(value), Ctor = result == objectTag2 ? value.constructor : void 0, ctorString = Ctor ? toSource_default(Ctor) : "";
+      if (ctorString) {
+        switch (ctorString) {
+          case dataViewCtorString:
+            return dataViewTag2;
+          case mapCtorString:
+            return mapTag2;
+          case promiseCtorString:
+            return promiseTag;
+          case setCtorString:
+            return setTag2;
+          case weakMapCtorString:
+            return weakMapTag2;
+        }
+      }
+      return result;
     };
-    return mutex;
   }
+  var getTag_default = getTag;
 
-  // modules/util/tiler.js
-  function utilTiler() {
-    var _size = [256, 256];
-    var _scale = 256;
-    var _tileSize = 256;
-    var _zoomExtent = [0, 20];
-    var _translate = [_size[0] / 2, _size[1] / 2];
-    var _margin = 0;
-    var _skipNullIsland = false;
-    function clamp3(num, min3, max3) {
-      return Math.max(min3, Math.min(num, max3));
+  // node_modules/lodash-es/_Uint8Array.js
+  var Uint8Array2 = root_default.Uint8Array;
+  var Uint8Array_default = Uint8Array2;
+
+  // node_modules/lodash-es/_setCacheAdd.js
+  var HASH_UNDEFINED3 = "__lodash_hash_undefined__";
+  function setCacheAdd(value) {
+    this.__data__.set(value, HASH_UNDEFINED3);
+    return this;
+  }
+  var setCacheAdd_default = setCacheAdd;
+
+  // node_modules/lodash-es/_setCacheHas.js
+  function setCacheHas(value) {
+    return this.__data__.has(value);
+  }
+  var setCacheHas_default = setCacheHas;
+
+  // node_modules/lodash-es/_SetCache.js
+  function SetCache(values) {
+    var index = -1, length = values == null ? 0 : values.length;
+    this.__data__ = new MapCache_default();
+    while (++index < length) {
+      this.add(values[index]);
     }
-    function nearNullIsland(tile) {
-      var x = tile[0];
-      var y = tile[1];
-      var z = tile[2];
-      if (z >= 7) {
-        var center = Math.pow(2, z - 1);
-        var width = Math.pow(2, z - 6);
-        var min3 = center - width / 2;
-        var max3 = center + width / 2 - 1;
-        return x >= min3 && x <= max3 && y >= min3 && y <= max3;
+  }
+  SetCache.prototype.add = SetCache.prototype.push = setCacheAdd_default;
+  SetCache.prototype.has = setCacheHas_default;
+  var SetCache_default = SetCache;
+
+  // node_modules/lodash-es/_arraySome.js
+  function arraySome(array2, predicate) {
+    var index = -1, length = array2 == null ? 0 : array2.length;
+    while (++index < length) {
+      if (predicate(array2[index], index, array2)) {
+        return true;
       }
+    }
+    return false;
+  }
+  var arraySome_default = arraySome;
+
+  // node_modules/lodash-es/_cacheHas.js
+  function cacheHas(cache, key) {
+    return cache.has(key);
+  }
+  var cacheHas_default = cacheHas;
+
+  // node_modules/lodash-es/_equalArrays.js
+  var COMPARE_PARTIAL_FLAG = 1;
+  var COMPARE_UNORDERED_FLAG = 2;
+  function equalArrays(array2, other, bitmask, customizer, equalFunc, stack) {
+    var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array2.length, othLength = other.length;
+    if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
       return false;
     }
-    function tiler8() {
-      var z = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
-      var z0 = clamp3(Math.round(z), _zoomExtent[0], _zoomExtent[1]);
-      var tileMin = 0;
-      var tileMax = Math.pow(2, z0) - 1;
-      var log2ts = Math.log(_tileSize) * Math.LOG2E;
-      var k = Math.pow(2, z - z0 + log2ts);
-      var origin = [
-        (_translate[0] - _scale / 2) / k,
-        (_translate[1] - _scale / 2) / k
-      ];
-      var cols = range(
-        clamp3(Math.floor(-origin[0]) - _margin, tileMin, tileMax + 1),
-        clamp3(Math.ceil(_size[0] / k - origin[0]) + _margin, tileMin, tileMax + 1)
-      );
-      var rows = range(
-        clamp3(Math.floor(-origin[1]) - _margin, tileMin, tileMax + 1),
-        clamp3(Math.ceil(_size[1] / k - origin[1]) + _margin, tileMin, tileMax + 1)
-      );
-      var tiles = [];
-      for (var i2 = 0; i2 < rows.length; i2++) {
-        var y = rows[i2];
-        for (var j2 = 0; j2 < cols.length; j2++) {
-          var x = cols[j2];
-          if (i2 >= _margin && i2 <= rows.length - _margin && j2 >= _margin && j2 <= cols.length - _margin) {
-            tiles.unshift([x, y, z0]);
-          } else {
-            tiles.push([x, y, z0]);
+    var arrStacked = stack.get(array2);
+    var othStacked = stack.get(other);
+    if (arrStacked && othStacked) {
+      return arrStacked == other && othStacked == array2;
+    }
+    var index = -1, result = true, seen = bitmask & COMPARE_UNORDERED_FLAG ? new SetCache_default() : void 0;
+    stack.set(array2, other);
+    stack.set(other, array2);
+    while (++index < arrLength) {
+      var arrValue = array2[index], othValue = other[index];
+      if (customizer) {
+        var compared = isPartial ? customizer(othValue, arrValue, index, other, array2, stack) : customizer(arrValue, othValue, index, array2, other, stack);
+      }
+      if (compared !== void 0) {
+        if (compared) {
+          continue;
+        }
+        result = false;
+        break;
+      }
+      if (seen) {
+        if (!arraySome_default(other, function(othValue2, othIndex) {
+          if (!cacheHas_default(seen, othIndex) && (arrValue === othValue2 || equalFunc(arrValue, othValue2, bitmask, customizer, stack))) {
+            return seen.push(othIndex);
           }
+        })) {
+          result = false;
+          break;
         }
+      } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
+        result = false;
+        break;
       }
-      tiles.translate = origin;
-      tiles.scale = k;
-      return tiles;
     }
-    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 = tiler8();
-      var ts = tiles.scale;
-      return tiles.map(function(tile) {
-        if (_skipNullIsland && nearNullIsland(tile)) {
-          return false;
-        }
-        var x = tile[0] * ts - origin[0];
-        var y = tile[1] * ts - origin[1];
-        return {
-          id: tile.toString(),
-          xyz: tile,
-          extent: geoExtent(
-            projection2.invert([x, y + ts]),
-            projection2.invert([x + ts, y])
-          )
-        };
-      }).filter(Boolean);
-    };
-    tiler8.getGeoJSON = function(projection2) {
-      var features2 = tiler8.getTiles(projection2).map(function(tile) {
-        return {
-          type: "Feature",
-          properties: {
-            id: tile.id,
-            name: tile.id
-          },
-          geometry: {
-            type: "Polygon",
-            coordinates: [tile.extent.polygon()]
-          }
-        };
-      });
-      return {
-        type: "FeatureCollection",
-        features: features2
-      };
-    };
-    tiler8.tileSize = function(val) {
-      if (!arguments.length)
-        return _tileSize;
-      _tileSize = val;
-      return tiler8;
-    };
-    tiler8.zoomExtent = function(val) {
-      if (!arguments.length)
-        return _zoomExtent;
-      _zoomExtent = val;
-      return tiler8;
-    };
-    tiler8.size = function(val) {
-      if (!arguments.length)
-        return _size;
-      _size = val;
-      return tiler8;
-    };
-    tiler8.scale = function(val) {
-      if (!arguments.length)
-        return _scale;
-      _scale = val;
-      return tiler8;
-    };
-    tiler8.translate = function(val) {
-      if (!arguments.length)
-        return _translate;
-      _translate = val;
-      return tiler8;
-    };
-    tiler8.margin = function(val) {
-      if (!arguments.length)
-        return _margin;
-      _margin = +val;
-      return tiler8;
-    };
-    tiler8.skipNullIsland = function(val) {
-      if (!arguments.length)
-        return _skipNullIsland;
-      _skipNullIsland = val;
-      return tiler8;
-    };
-    return tiler8;
+    stack["delete"](array2);
+    stack["delete"](other);
+    return result;
   }
+  var equalArrays_default = equalArrays;
 
-  // modules/util/trigger_event.js
-  function utilTriggerEvent(target, type3) {
-    target.each(function() {
-      var evt = document.createEvent("HTMLEvents");
-      evt.initEvent(type3, true, true);
-      this.dispatchEvent(evt);
+  // node_modules/lodash-es/_mapToArray.js
+  function mapToArray(map2) {
+    var index = -1, result = Array(map2.size);
+    map2.forEach(function(value, key) {
+      result[++index] = [key, value];
     });
+    return result;
   }
+  var mapToArray_default = mapToArray;
 
-  // modules/core/locations.js
-  var _mainLocations = coreLocations();
-  function coreLocations() {
-    let _this = {};
-    let _resolvedFeatures = {};
-    let _loco = new location_conflation_default();
-    let _wp;
-    const world = { locationSet: { include: ["Q2"] } };
-    resolveLocationSet(world);
-    rebuildIndex();
-    let _queue = [];
-    let _deferred2 = /* @__PURE__ */ new Set();
-    let _inProcess;
-    function processQueue() {
-      if (!_queue.length)
-        return Promise.resolve();
-      const chunk = _queue.pop();
-      return new Promise((resolvePromise) => {
-        const handle = window.requestIdleCallback(() => {
-          _deferred2.delete(handle);
-          chunk.forEach(resolveLocationSet);
-          resolvePromise();
-        });
-        _deferred2.add(handle);
-      }).then(() => processQueue());
-    }
-    function resolveLocationSet(obj) {
-      if (obj.locationSetID)
-        return;
-      try {
-        let locationSet = obj.locationSet;
-        if (!locationSet) {
-          throw new Error("object missing locationSet property");
+  // node_modules/lodash-es/_setToArray.js
+  function setToArray(set3) {
+    var index = -1, result = Array(set3.size);
+    set3.forEach(function(value) {
+      result[++index] = value;
+    });
+    return result;
+  }
+  var setToArray_default = setToArray;
+
+  // node_modules/lodash-es/_equalByTag.js
+  var COMPARE_PARTIAL_FLAG2 = 1;
+  var COMPARE_UNORDERED_FLAG2 = 2;
+  var boolTag2 = "[object Boolean]";
+  var dateTag2 = "[object Date]";
+  var errorTag2 = "[object Error]";
+  var mapTag3 = "[object Map]";
+  var numberTag2 = "[object Number]";
+  var regexpTag2 = "[object RegExp]";
+  var setTag3 = "[object Set]";
+  var stringTag2 = "[object String]";
+  var symbolTag2 = "[object Symbol]";
+  var arrayBufferTag2 = "[object ArrayBuffer]";
+  var dataViewTag3 = "[object DataView]";
+  var symbolProto2 = Symbol_default ? Symbol_default.prototype : void 0;
+  var symbolValueOf = symbolProto2 ? symbolProto2.valueOf : void 0;
+  function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
+    switch (tag) {
+      case dataViewTag3:
+        if (object.byteLength != other.byteLength || object.byteOffset != other.byteOffset) {
+          return false;
         }
-        if (!locationSet.include) {
-          locationSet.include = ["Q2"];
+        object = object.buffer;
+        other = other.buffer;
+      case arrayBufferTag2:
+        if (object.byteLength != other.byteLength || !equalFunc(new Uint8Array_default(object), new Uint8Array_default(other))) {
+          return false;
         }
-        const resolved = _loco.resolveLocationSet(locationSet);
-        const locationSetID = resolved.id;
-        obj.locationSetID = locationSetID;
-        if (!resolved.feature.geometry.coordinates.length || !resolved.feature.properties.area) {
-          throw new Error(`locationSet ${locationSetID} resolves to an empty feature.`);
+        return true;
+      case boolTag2:
+      case dateTag2:
+      case numberTag2:
+        return eq_default(+object, +other);
+      case errorTag2:
+        return object.name == other.name && object.message == other.message;
+      case regexpTag2:
+      case stringTag2:
+        return object == other + "";
+      case mapTag3:
+        var convert = mapToArray_default;
+      case setTag3:
+        var isPartial = bitmask & COMPARE_PARTIAL_FLAG2;
+        convert || (convert = setToArray_default);
+        if (object.size != other.size && !isPartial) {
+          return false;
         }
-        if (!_resolvedFeatures[locationSetID]) {
-          let feature3 = JSON.parse(JSON.stringify(resolved.feature));
-          feature3.id = locationSetID;
-          feature3.properties.id = locationSetID;
-          _resolvedFeatures[locationSetID] = feature3;
+        var stacked = stack.get(object);
+        if (stacked) {
+          return stacked == other;
+        }
+        bitmask |= COMPARE_UNORDERED_FLAG2;
+        stack.set(object, other);
+        var result = equalArrays_default(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
+        stack["delete"](object);
+        return result;
+      case symbolTag2:
+        if (symbolValueOf) {
+          return symbolValueOf.call(object) == symbolValueOf.call(other);
         }
-      } catch (err) {
-        obj.locationSet = { include: ["Q2"] };
-        obj.locationSetID = "+[Q2]";
-      }
-    }
-    function rebuildIndex() {
-      _wp = (0, import_which_polygon2.default)({ features: Object.values(_resolvedFeatures) });
     }
-    _this.mergeCustomGeoJSON = (fc) => {
-      if (fc && fc.type === "FeatureCollection" && Array.isArray(fc.features)) {
-        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;
-          id2 = id2.toLowerCase();
-          feature3.id = id2;
-          props.id = id2;
-          if (!props.area) {
-            const area = import_geojson_area2.default.geometry(feature3.geometry) / 1e6;
-            props.area = Number(area.toFixed(2));
-          }
-          _loco._cache[id2] = feature3;
-        });
-      }
-    };
-    _this.mergeLocationSets = (objects) => {
-      if (!Array.isArray(objects))
-        return Promise.reject("nothing to do");
-      _queue = _queue.concat(utilArrayChunk(objects, 200));
-      if (!_inProcess) {
-        _inProcess = processQueue().then(() => {
-          rebuildIndex();
-          _inProcess = null;
-          return objects;
-        });
-      }
-      return _inProcess;
-    };
-    _this.locationSetID = (locationSet) => {
-      let locationSetID;
-      try {
-        locationSetID = _loco.validateLocationSet(locationSet).id;
-      } catch (err) {
-        locationSetID = "+[Q2]";
-      }
-      return locationSetID;
-    };
-    _this.feature = (locationSetID) => _resolvedFeatures[locationSetID] || _resolvedFeatures["+[Q2]"];
-    _this.locationsAt = (loc) => {
-      let result = {};
-      (_wp(loc, true) || []).forEach((prop) => result[prop.id] = prop.area);
-      return result;
-    };
-    _this.query = (loc, multi) => _wp(loc, multi);
-    _this.loco = () => _loco;
-    _this.wp = () => _wp;
-    return _this;
+    return false;
   }
+  var equalByTag_default = equalByTag;
 
-  // node_modules/lodash-es/_freeGlobal.js
-  var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
-  var freeGlobal_default = freeGlobal;
-
-  // node_modules/lodash-es/_root.js
-  var freeSelf = typeof self == "object" && self && self.Object === Object && self;
-  var root2 = freeGlobal_default || freeSelf || Function("return this")();
-  var root_default = root2;
-
-  // node_modules/lodash-es/_Symbol.js
-  var Symbol2 = root_default.Symbol;
-  var Symbol_default = Symbol2;
-
-  // node_modules/lodash-es/_getRawTag.js
-  var objectProto = Object.prototype;
-  var hasOwnProperty = objectProto.hasOwnProperty;
-  var nativeObjectToString = objectProto.toString;
-  var symToStringTag = Symbol_default ? Symbol_default.toStringTag : void 0;
-  function getRawTag(value) {
-    var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag];
-    try {
-      value[symToStringTag] = void 0;
-      var unmasked = true;
-    } catch (e) {
+  // node_modules/lodash-es/_equalObjects.js
+  var COMPARE_PARTIAL_FLAG3 = 1;
+  var objectProto11 = Object.prototype;
+  var hasOwnProperty8 = objectProto11.hasOwnProperty;
+  function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
+    var isPartial = bitmask & COMPARE_PARTIAL_FLAG3, objProps = getAllKeys_default(object), objLength = objProps.length, othProps = getAllKeys_default(other), othLength = othProps.length;
+    if (objLength != othLength && !isPartial) {
+      return false;
     }
-    var result = nativeObjectToString.call(value);
-    if (unmasked) {
-      if (isOwn) {
-        value[symToStringTag] = tag;
-      } else {
-        delete value[symToStringTag];
+    var index = objLength;
+    while (index--) {
+      var key = objProps[index];
+      if (!(isPartial ? key in other : hasOwnProperty8.call(other, key))) {
+        return false;
       }
     }
-    return result;
-  }
-  var getRawTag_default = getRawTag;
-
-  // node_modules/lodash-es/_objectToString.js
-  var objectProto2 = Object.prototype;
-  var nativeObjectToString2 = objectProto2.toString;
-  function objectToString(value) {
-    return nativeObjectToString2.call(value);
-  }
-  var objectToString_default = objectToString;
-
-  // node_modules/lodash-es/_baseGetTag.js
-  var nullTag = "[object Null]";
-  var undefinedTag = "[object Undefined]";
-  var symToStringTag2 = Symbol_default ? Symbol_default.toStringTag : void 0;
-  function baseGetTag(value) {
-    if (value == null) {
-      return value === void 0 ? undefinedTag : nullTag;
+    var objStacked = stack.get(object);
+    var othStacked = stack.get(other);
+    if (objStacked && othStacked) {
+      return objStacked == other && othStacked == object;
     }
-    return symToStringTag2 && symToStringTag2 in Object(value) ? getRawTag_default(value) : objectToString_default(value);
-  }
-  var baseGetTag_default = baseGetTag;
-
-  // node_modules/lodash-es/isObjectLike.js
-  function isObjectLike(value) {
-    return value != null && typeof value == "object";
-  }
-  var isObjectLike_default = isObjectLike;
-
-  // node_modules/lodash-es/isSymbol.js
-  var symbolTag = "[object Symbol]";
-  function isSymbol(value) {
-    return typeof value == "symbol" || isObjectLike_default(value) && baseGetTag_default(value) == symbolTag;
-  }
-  var isSymbol_default = isSymbol;
-
-  // node_modules/lodash-es/_arrayMap.js
-  function arrayMap(array2, iteratee) {
-    var index = -1, length = array2 == null ? 0 : array2.length, result = Array(length);
-    while (++index < length) {
-      result[index] = iteratee(array2[index], index, array2);
+    var result = true;
+    stack.set(object, other);
+    stack.set(other, object);
+    var skipCtor = isPartial;
+    while (++index < objLength) {
+      key = objProps[index];
+      var objValue = object[key], othValue = other[key];
+      if (customizer) {
+        var compared = isPartial ? customizer(othValue, objValue, key, other, object, stack) : customizer(objValue, othValue, key, object, other, stack);
+      }
+      if (!(compared === void 0 ? objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack) : compared)) {
+        result = false;
+        break;
+      }
+      skipCtor || (skipCtor = key == "constructor");
+    }
+    if (result && !skipCtor) {
+      var objCtor = object.constructor, othCtor = other.constructor;
+      if (objCtor != othCtor && ("constructor" in object && "constructor" in other) && !(typeof objCtor == "function" && objCtor instanceof objCtor && typeof othCtor == "function" && othCtor instanceof othCtor)) {
+        result = false;
+      }
     }
+    stack["delete"](object);
+    stack["delete"](other);
     return result;
   }
-  var arrayMap_default = arrayMap;
-
-  // node_modules/lodash-es/isArray.js
-  var isArray = Array.isArray;
-  var isArray_default = isArray;
-
-  // node_modules/lodash-es/_baseToString.js
-  var INFINITY = 1 / 0;
-  var symbolProto = Symbol_default ? Symbol_default.prototype : void 0;
-  var symbolToString = symbolProto ? symbolProto.toString : void 0;
-  function baseToString(value) {
-    if (typeof value == "string") {
-      return value;
+  var equalObjects_default = equalObjects;
+
+  // node_modules/lodash-es/_baseIsEqualDeep.js
+  var COMPARE_PARTIAL_FLAG4 = 1;
+  var argsTag3 = "[object Arguments]";
+  var arrayTag2 = "[object Array]";
+  var objectTag3 = "[object Object]";
+  var objectProto12 = Object.prototype;
+  var hasOwnProperty9 = objectProto12.hasOwnProperty;
+  function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
+    var objIsArr = isArray_default(object), othIsArr = isArray_default(other), objTag = objIsArr ? arrayTag2 : getTag_default(object), othTag = othIsArr ? arrayTag2 : getTag_default(other);
+    objTag = objTag == argsTag3 ? objectTag3 : objTag;
+    othTag = othTag == argsTag3 ? objectTag3 : othTag;
+    var objIsObj = objTag == objectTag3, othIsObj = othTag == objectTag3, isSameTag = objTag == othTag;
+    if (isSameTag && isBuffer_default(object)) {
+      if (!isBuffer_default(other)) {
+        return false;
+      }
+      objIsArr = true;
+      objIsObj = false;
     }
-    if (isArray_default(value)) {
-      return arrayMap_default(value, baseToString) + "";
+    if (isSameTag && !objIsObj) {
+      stack || (stack = new Stack_default());
+      return objIsArr || isTypedArray_default(object) ? equalArrays_default(object, other, bitmask, customizer, equalFunc, stack) : equalByTag_default(object, other, objTag, bitmask, customizer, equalFunc, stack);
     }
-    if (isSymbol_default(value)) {
-      return symbolToString ? symbolToString.call(value) : "";
+    if (!(bitmask & COMPARE_PARTIAL_FLAG4)) {
+      var objIsWrapped = objIsObj && hasOwnProperty9.call(object, "__wrapped__"), othIsWrapped = othIsObj && hasOwnProperty9.call(other, "__wrapped__");
+      if (objIsWrapped || othIsWrapped) {
+        var objUnwrapped = objIsWrapped ? object.value() : object, othUnwrapped = othIsWrapped ? other.value() : other;
+        stack || (stack = new Stack_default());
+        return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
+      }
     }
-    var result = value + "";
-    return result == "0" && 1 / value == -INFINITY ? "-0" : result;
-  }
-  var baseToString_default = baseToString;
-
-  // node_modules/lodash-es/_trimmedEndIndex.js
-  var reWhitespace = /\s/;
-  function trimmedEndIndex(string) {
-    var index = string.length;
-    while (index-- && reWhitespace.test(string.charAt(index))) {
+    if (!isSameTag) {
+      return false;
     }
-    return index;
-  }
-  var trimmedEndIndex_default = trimmedEndIndex;
-
-  // node_modules/lodash-es/_baseTrim.js
-  var reTrimStart = /^\s+/;
-  function baseTrim(string) {
-    return string ? string.slice(0, trimmedEndIndex_default(string) + 1).replace(reTrimStart, "") : string;
-  }
-  var baseTrim_default = baseTrim;
-
-  // node_modules/lodash-es/isObject.js
-  function isObject(value) {
-    var type3 = typeof value;
-    return value != null && (type3 == "object" || type3 == "function");
+    stack || (stack = new Stack_default());
+    return equalObjects_default(object, other, bitmask, customizer, equalFunc, stack);
   }
-  var isObject_default = isObject;
+  var baseIsEqualDeep_default = baseIsEqualDeep;
 
-  // node_modules/lodash-es/toNumber.js
-  var NAN = 0 / 0;
-  var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
-  var reIsBinary = /^0b[01]+$/i;
-  var reIsOctal = /^0o[0-7]+$/i;
-  var freeParseInt = parseInt;
-  function toNumber(value) {
-    if (typeof value == "number") {
-      return value;
-    }
-    if (isSymbol_default(value)) {
-      return NAN;
-    }
-    if (isObject_default(value)) {
-      var other = typeof value.valueOf == "function" ? value.valueOf() : value;
-      value = isObject_default(other) ? other + "" : other;
+  // node_modules/lodash-es/_baseIsEqual.js
+  function baseIsEqual(value, other, bitmask, customizer, stack) {
+    if (value === other) {
+      return true;
     }
-    if (typeof value != "string") {
-      return value === 0 ? value : +value;
+    if (value == null || other == null || !isObjectLike_default(value) && !isObjectLike_default(other)) {
+      return value !== value && other !== other;
     }
-    value = baseTrim_default(value);
-    var isBinary = reIsBinary.test(value);
-    return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
-  }
-  var toNumber_default = toNumber;
-
-  // node_modules/lodash-es/toString.js
-  function toString(value) {
-    return value == null ? "" : baseToString_default(value);
-  }
-  var toString_default = toString;
-
-  // node_modules/lodash-es/_basePropertyOf.js
-  function basePropertyOf(object) {
-    return function(key) {
-      return object == null ? void 0 : object[key];
-    };
+    return baseIsEqualDeep_default(value, other, bitmask, customizer, baseIsEqual, stack);
   }
-  var basePropertyOf_default = basePropertyOf;
+  var baseIsEqual_default = baseIsEqual;
 
   // node_modules/lodash-es/now.js
   var now2 = function() {
   }
   var escape_default = escape2;
 
+  // node_modules/lodash-es/isEqual.js
+  function isEqual(value, other) {
+    return baseIsEqual_default(value, other);
+  }
+  var isEqual_default = isEqual;
+
   // node_modules/lodash-es/throttle.js
   var FUNC_ERROR_TEXT2 = "Expected a function";
   function throttle(func, wait, options2) {
   }
   var unescape_default = unescape2;
 
-  // modules/core/localizer.js
-  var _mainLocalizer = coreLocalizer();
-  var _t = _mainLocalizer.t;
-  function coreLocalizer() {
-    let localizer = {};
-    let _dataLanguages = {};
-    let _dataLocales = {};
-    let _localeStrings = {};
-    let _localeCode = "en-US";
-    let _localeCodes = ["en-US", "en"];
-    let _languageCode = "en";
-    let _textDirection = "ltr";
-    let _usesMetric = false;
-    let _languageNames = {};
-    let _scriptNames = {};
-    localizer.localeCode = () => _localeCode;
-    localizer.localeCodes = () => _localeCodes;
-    localizer.languageCode = () => _languageCode;
-    localizer.textDirection = () => _textDirection;
-    localizer.usesMetric = () => _usesMetric;
-    localizer.languageNames = () => _languageNames;
-    localizer.scriptNames = () => _scriptNames;
-    let _preferredLocaleCodes = [];
-    localizer.preferredLocaleCodes = function(codes) {
-      if (!arguments.length)
-        return _preferredLocaleCodes;
-      if (typeof codes === "string") {
-        _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
-      } else {
-        _preferredLocaleCodes = codes;
-      }
-      return localizer;
-    };
-    var _loadPromise;
-    localizer.ensureLoaded = () => {
-      if (_loadPromise)
-        return _loadPromise;
-      let filesToFetch = [
-        "languages",
-        "locales"
-      ];
-      const localeDirs = {
-        general: "locales",
-        tagging: "https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/translations"
-      };
-      let fileMap = _mainFileFetcher.fileMap();
-      for (let scopeId in localeDirs) {
-        const key = `locales_index_${scopeId}`;
-        if (!fileMap[key]) {
-          fileMap[key] = localeDirs[scopeId] + "/index.min.json";
-        }
-        filesToFetch.push(key);
-      }
-      return _loadPromise = Promise.all(filesToFetch.map((key) => _mainFileFetcher.get(key))).then((results) => {
-        _dataLanguages = results[0];
-        _dataLocales = results[1];
-        let indexes = results.slice(2);
-        let requestedLocales = (_preferredLocaleCodes || []).concat(utilDetect().browserLocales).concat(["en"]);
-        _localeCodes = localesToUseFrom(requestedLocales);
-        _localeCode = _localeCodes[0];
-        let loadStringsPromises = [];
-        indexes.forEach((index, i2) => {
-          const fullCoverageIndex = _localeCodes.findIndex(function(locale2) {
-            return index[locale2] && index[locale2].pct === 1;
-          });
-          _localeCodes.slice(0, fullCoverageIndex + 1).forEach(function(code) {
-            let scopeId = Object.keys(localeDirs)[i2];
-            let directory = Object.values(localeDirs)[i2];
-            if (index[code])
-              loadStringsPromises.push(localizer.loadLocale(code, scopeId, directory));
-          });
-        });
-        return Promise.all(loadStringsPromises);
-      }).then(() => {
-        updateForCurrentLocale();
-      }).catch((err) => console.error(err));
-    };
-    function localesToUseFrom(requestedLocales) {
-      let supportedLocales = _dataLocales;
-      let toUse = [];
-      for (let i2 in requestedLocales) {
-        let locale2 = requestedLocales[i2];
-        if (supportedLocales[locale2])
-          toUse.push(locale2);
-        if (locale2.includes("-")) {
-          let langPart = locale2.split("-")[0];
-          if (supportedLocales[langPart])
-            toUse.push(langPart);
-        }
-      }
-      return utilArrayUniq(toUse);
+  // modules/util/detect.js
+  var _detected;
+  function utilDetect(refresh2) {
+    if (_detected && !refresh2)
+      return _detected;
+    _detected = {};
+    const ua = navigator.userAgent;
+    let m = null;
+    m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);
+    if (m !== null) {
+      _detected.browser = m[1];
+      _detected.version = m[2];
     }
-    function updateForCurrentLocale() {
-      if (!_localeCode)
-        return;
-      _languageCode = _localeCode.split("-")[0];
-      const currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
-      const hash = utilStringQs(window.location.hash);
-      if (hash.rtl === "true") {
-        _textDirection = "rtl";
-      } else if (hash.rtl === "false") {
-        _textDirection = "ltr";
-      } else {
-        _textDirection = currentData && currentData.rtl ? "rtl" : "ltr";
+    if (!_detected.browser) {
+      m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);
+      if (m !== null) {
+        _detected.browser = "msie";
+        _detected.version = m[1];
       }
-      let locale2 = _localeCode;
-      if (locale2.toLowerCase() === "en-us")
-        locale2 = "en";
-      _languageNames = _localeStrings.general[locale2].languageNames;
-      _scriptNames = _localeStrings.general[locale2].scriptNames;
-      _usesMetric = _localeCode.slice(-3).toLowerCase() !== "-us";
     }
-    localizer.loadLocale = (locale2, scopeId, directory) => {
-      if (locale2.toLowerCase() === "en-us")
-        locale2 = "en";
-      if (_localeStrings[scopeId] && _localeStrings[scopeId][locale2]) {
-        return Promise.resolve(locale2);
-      }
-      let fileMap = _mainFileFetcher.fileMap();
-      const key = `locale_${scopeId}_${locale2}`;
-      if (!fileMap[key]) {
-        fileMap[key] = `${directory}/${locale2}.min.json`;
-      }
-      return _mainFileFetcher.get(key).then((d) => {
-        if (!_localeStrings[scopeId])
-          _localeStrings[scopeId] = {};
-        _localeStrings[scopeId][locale2] = d[locale2];
-        return locale2;
-      });
-    };
-    localizer.pluralRule = function(number3) {
-      return pluralRule(number3, _localeCode);
-    };
-    function pluralRule(number3, localeCode) {
-      const rules = "Intl" in window && Intl.PluralRules && new Intl.PluralRules(localeCode);
-      if (rules) {
-        return rules.select(number3);
+    if (!_detected.browser) {
+      m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);
+      if (m !== null) {
+        _detected.browser = "Opera";
+        _detected.version = m[2];
       }
-      if (number3 === 1)
-        return "one";
-      return "other";
     }
-    localizer.tInfo = function(origStringId, replacements, locale2) {
-      let stringId = origStringId.trim();
-      let scopeId = "general";
-      if (stringId[0] === "_") {
-        let split = stringId.split(".");
-        scopeId = split[0].slice(1);
-        stringId = split.slice(1).join(".");
-      }
-      locale2 = locale2 || _localeCode;
-      let path = stringId.split(".").map((s) => s.replace(/<TX_DOT>/g, ".")).reverse();
-      let stringsKey = locale2;
-      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()];
+    if (!_detected.browser) {
+      m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
+      if (m !== null) {
+        _detected.browser = m[1];
+        _detected.version = m[2];
+        m = ua.match(/version\/([\.\d]+)/i);
+        if (m !== null)
+          _detected.version = m[1];
       }
-      if (result !== void 0) {
-        if (replacements) {
-          if (typeof result === "object" && Object.keys(result).length) {
-            const number3 = Object.values(replacements).find(function(value) {
-              return typeof value === "number";
-            });
-            if (number3 !== void 0) {
-              const rule = pluralRule(number3, locale2);
-              if (result[rule]) {
-                result = result[rule];
-              } else {
-                result = Object.values(result)[0];
-              }
-            }
-          }
-          if (typeof result === "string") {
-            for (let key in replacements) {
-              let value = replacements[key];
-              if (typeof value === "number") {
-                if (value.toLocaleString) {
-                  value = value.toLocaleString(locale2, {
-                    style: "decimal",
-                    useGrouping: true,
-                    minimumFractionDigits: 0
-                  });
-                } else {
-                  value = value.toString();
-                }
-              }
-              const token = `{${key}}`;
-              const regex = new RegExp(token, "g");
-              result = result.replace(regex, value);
-            }
-          }
-        }
-        if (typeof result === "string") {
-          return {
-            text: result,
-            locale: locale2
-          };
-        }
+    }
+    if (!_detected.browser) {
+      _detected.browser = navigator.appName;
+      _detected.version = navigator.appVersion;
+    }
+    _detected.version = _detected.version.split(/\W/).slice(0, 2).join(".");
+    _detected.opera = _detected.browser.toLowerCase() === "opera" && Number(_detected.version) < 15;
+    if (_detected.browser.toLowerCase() === "msie") {
+      _detected.ie = true;
+      _detected.browser = "Internet Explorer";
+      _detected.support = false;
+    } else {
+      _detected.ie = false;
+      _detected.support = true;
+    }
+    _detected.filedrop = window.FileReader && "ondrop" in window;
+    if (/Win/.test(ua)) {
+      _detected.os = "win";
+      _detected.platform = "Windows";
+    } else if (/Mac/.test(ua)) {
+      _detected.os = "mac";
+      _detected.platform = "Macintosh";
+    } else if (/X11/.test(ua) || /Linux/.test(ua)) {
+      _detected.os = "linux";
+      _detected.platform = "Linux";
+    } else {
+      _detected.os = "win";
+      _detected.platform = "Unknown";
+    }
+    _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent,
+    // so assume any "mac" with multitouch is actually iOS
+    navigator.platform === "MacIntel" && "maxTouchPoints" in navigator && navigator.maxTouchPoints > 1) && /WebKit/.test(ua) && !/Edge/.test(ua) && !window.MSStream;
+    _detected.browserLocales = Array.from(new Set(
+      // remove duplicates
+      [navigator.language].concat(navigator.languages || []).concat([
+        // old property for backwards compatibility
+        navigator.userLanguage
+      ]).filter(Boolean)
+    ));
+    const loc = window.top.location;
+    let origin = loc.origin;
+    if (!origin) {
+      origin = loc.protocol + "//" + loc.hostname + (loc.port ? ":" + loc.port : "");
+    }
+    _detected.host = origin + loc.pathname;
+    return _detected;
+  }
+
+  // modules/util/aes.js
+  var import_aes_js = __toESM(require_aes_js());
+  var DEFAULT_128 = [250, 157, 60, 79, 142, 134, 229, 129, 138, 126, 210, 129, 29, 71, 160, 208];
+  function utilAesEncrypt(text2, key) {
+    key = key || DEFAULT_128;
+    const textBytes = import_aes_js.default.utils.utf8.toBytes(text2);
+    const aesCtr = new import_aes_js.default.ModeOfOperation.ctr(key);
+    const encryptedBytes = aesCtr.encrypt(textBytes);
+    const encryptedHex = import_aes_js.default.utils.hex.fromBytes(encryptedBytes);
+    return encryptedHex;
+  }
+  function utilAesDecrypt(encryptedHex, key) {
+    key = key || DEFAULT_128;
+    const encryptedBytes = import_aes_js.default.utils.hex.toBytes(encryptedHex);
+    const aesCtr = new import_aes_js.default.ModeOfOperation.ctr(key);
+    const decryptedBytes = aesCtr.decrypt(encryptedBytes);
+    const text2 = import_aes_js.default.utils.utf8.fromBytes(decryptedBytes);
+    return text2;
+  }
+
+  // modules/util/clean_tags.js
+  function utilCleanTags(tags) {
+    var out = {};
+    for (var k in tags) {
+      if (!k)
+        continue;
+      var v = tags[k];
+      if (v !== void 0) {
+        out[k] = cleanValue(k, v);
       }
-      let index = _localeCodes.indexOf(locale2);
-      if (index >= 0 && index < _localeCodes.length - 1) {
-        let fallback = _localeCodes[index + 1];
-        return localizer.tInfo(origStringId, replacements, fallback);
+    }
+    return out;
+    function cleanValue(k2, v2) {
+      function keepSpaces(k3) {
+        return /_hours|_times|:conditional$/.test(k3);
       }
-      if (replacements && "default" in replacements) {
-        return {
-          text: replacements.default,
-          locale: null
-        };
+      function skip(k3) {
+        return /^(description|note|fixme)$/.test(k3);
       }
-      const missing = `Missing ${locale2} translation: ${origStringId}`;
-      if (typeof console !== "undefined")
-        console.error(missing);
-      return {
-        text: missing,
-        locale: "en"
-      };
-    };
-    localizer.hasTextForStringId = function(stringId) {
-      return !!localizer.tInfo(stringId, { default: "nothing found" }).locale;
-    };
-    localizer.t = function(stringId, replacements, locale2) {
-      return localizer.tInfo(stringId, replacements, locale2).text;
-    };
-    localizer.t.html = function(stringId, replacements, locale2) {
-      replacements = Object.assign({}, replacements);
-      for (var k in replacements) {
-        if (typeof replacements[k] === "string") {
-          replacements[k] = escape_default(replacements[k]);
-        }
-        if (typeof replacements[k] === "object" && typeof replacements[k].html === "string") {
-          replacements[k] = replacements[k].html;
-        }
+      if (skip(k2))
+        return v2;
+      var cleaned = v2.split(";").map(function(s) {
+        return s.trim();
+      }).join(keepSpaces(k2) ? "; " : ";");
+      if (k2.indexOf("website") !== -1 || k2.indexOf("email") !== -1 || cleaned.indexOf("http") === 0) {
+        cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, "");
       }
-      const info = localizer.tInfo(stringId, replacements, locale2);
-      if (info.text) {
-        return `<span class="localized-text" lang="${info.locale || "und"}">${info.text}</span>`;
-      } else {
-        return "";
+      return cleaned;
+    }
+  }
+
+  // modules/util/get_set_value.js
+  function utilGetSetValue(selection2, value, shouldUpdate) {
+    function setValue(value2, shouldUpdate2) {
+      function valueNull() {
+        delete this.value;
       }
-    };
-    localizer.t.append = function(stringId, replacements, locale2) {
-      const ret = function(selection2) {
-        const info = localizer.tInfo(stringId, replacements, locale2);
-        return selection2.append("span").attr("class", "localized-text").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[code]) {
-        return _languageNames[code];
+      function valueConstant() {
+        if (shouldUpdate2(this.value, value2)) {
+          this.value = value2;
+        }
       }
-      if (options2 && options2.localOnly)
-        return null;
-      const langInfo = _dataLanguages[code];
-      if (langInfo) {
-        if (langInfo.nativeName) {
-          return localizer.t("translate.language_and_code", { language: langInfo.nativeName, code });
-        } else if (langInfo.base && langInfo.script) {
-          const base = langInfo.base;
-          if (_languageNames[base]) {
-            const scriptCode = langInfo.script;
-            const script = _scriptNames[scriptCode] || scriptCode;
-            return localizer.t("translate.language_and_code", { language: _languageNames[base], code: script });
-          } else if (_dataLanguages[base] && _dataLanguages[base].nativeName) {
-            return localizer.t("translate.language_and_code", { language: _dataLanguages[base].nativeName, code });
-          }
+      function valueFunction() {
+        var x = value2.apply(this, arguments);
+        if (x === null || x === void 0) {
+          delete this.value;
+        } else if (shouldUpdate2(this.value, x)) {
+          this.value = x;
         }
       }
-      return code;
-    };
-    return localizer;
+      return value2 === null || value2 === void 0 ? valueNull : typeof value2 === "function" ? valueFunction : valueConstant;
+    }
+    function stickyCursor(func) {
+      const supportedTypes = ["text", "search", "url", "tel", "password"];
+      return function() {
+        if (!supportedTypes.includes(this.type)) {
+          return;
+        }
+        const cursor = { start: this.selectionStart, end: this.selectionEnd };
+        func.apply(this, arguments);
+        this.setSelectionRange(cursor.start, cursor.end);
+      };
+    }
+    if (arguments.length === 1) {
+      return selection2.property("value");
+    }
+    if (shouldUpdate === void 0) {
+      shouldUpdate = (a, b) => a !== b;
+    }
+    return selection2.each(stickyCursor(setValue(value, shouldUpdate)));
   }
 
-  // modules/presets/collection.js
-  function presetCollection(collection) {
-    const MAXRESULTS = 50;
-    let _this = {};
-    let _memo = {};
-    _this.collection = collection;
-    _this.item = (id2) => {
-      if (_memo[id2])
-        return _memo[id2];
-      const found = _this.collection.find((d) => d.id === id2);
-      if (found)
-        _memo[id2] = found;
-      return found;
-    };
-    _this.index = (id2) => _this.collection.findIndex((d) => d.id === id2);
-    _this.matchGeometry = (geometry) => {
-      return presetCollection(
-        _this.collection.filter((d) => d.matchGeometry(geometry))
-      );
-    };
-    _this.matchAllGeometry = (geometries) => {
-      return presetCollection(
-        _this.collection.filter((d) => d && d.matchAllGeometry(geometries))
-      );
-    };
-    _this.matchAnyGeometry = (geometries) => {
-      return presetCollection(
-        _this.collection.filter((d) => geometries.some((geom) => d.matchGeometry(geom)))
-      );
-    };
-    _this.fallback = (geometry) => {
-      let id2 = geometry;
-      if (id2 === "vertex")
-        id2 = "point";
-      return _this.item(id2);
-    };
-    _this.search = (value, geometry, loc) => {
-      if (!value)
-        return _this;
-      value = value.toLowerCase().trim();
-      function leading(a) {
-        const index = a.indexOf(value);
-        return index === 0 || a[index - 1] === " ";
-      }
-      function leadingStrict(a) {
-        const index = a.indexOf(value);
-        return index === 0;
-      }
-      function sortPresets(nameProp, aliasesProp) {
-        return function sortNames(a, b) {
-          let aCompare = a[nameProp]();
-          let bCompare = b[nameProp]();
-          if (aliasesProp) {
-            const findMatchingAlias = (strings) => {
-              if (strings.some((s) => s === value)) {
-                return strings.find((s) => s === value);
-              } else {
-                return strings.find((s) => s.includes(value));
-              }
-            };
-            aCompare = findMatchingAlias([aCompare].concat(a[aliasesProp]()));
-            bCompare = findMatchingAlias([bCompare].concat(b[aliasesProp]()));
-          }
-          if (value === aCompare)
-            return -1;
-          if (value === bCompare)
-            return 1;
-          let i2 = b.originalScore - a.originalScore;
-          if (i2 !== 0)
-            return i2;
-          i2 = aCompare.indexOf(value) - bCompare.indexOf(value);
-          if (i2 !== 0)
-            return i2;
-          return aCompare.length - bCompare.length;
-        };
-      }
-      let pool = _this.collection;
-      if (Array.isArray(loc)) {
-        const validLocations = _mainLocations.locationsAt(loc);
-        pool = pool.filter((a) => !a.locationSetID || validLocations[a.locationSetID]);
-      }
-      const searchable = pool.filter((a) => a.searchable !== false && a.suggestion !== true);
-      const suggestions = pool.filter((a) => a.suggestion === true);
-      const leadingNames = searchable.filter((a) => leading(a.searchName()) || a.searchAliases().some(leading)).sort(sortPresets("searchName", "searchAliases"));
-      const leadingSuggestions = suggestions.filter((a) => leadingStrict(a.searchName())).sort(sortPresets("searchName"));
-      const leadingNamesStripped = searchable.filter((a) => leading(a.searchNameStripped()) || a.searchAliasesStripped().some(leading)).sort(sortPresets("searchNameStripped", "searchAliasesStripped"));
-      const leadingSuggestionsStripped = suggestions.filter((a) => leadingStrict(a.searchNameStripped())).sort(sortPresets("searchNameStripped"));
-      const leadingTerms = searchable.filter((a) => (a.terms() || []).some(leading));
-      const leadingSuggestionTerms = suggestions.filter((a) => (a.terms() || []).some(leading));
-      const leadingTagValues = searchable.filter((a) => Object.values(a.tags || {}).filter((val) => val !== "*").some(leading));
-      const similarName = searchable.map((a) => ({ preset: a, dist: utilEditDistance(value, a.searchName()) })).filter((a) => a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 3).sort((a, b) => a.dist - b.dist).map((a) => a.preset);
-      const similarSuggestions = suggestions.map((a) => ({ preset: a, dist: utilEditDistance(value, a.searchName()) })).filter((a) => a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 1).sort((a, b) => a.dist - b.dist).map((a) => a.preset);
-      const similarTerms = searchable.filter((a) => {
-        return (a.terms() || []).some((b) => {
-          return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
-        });
+  // modules/util/keybinding.js
+  function utilKeybinding(namespace) {
+    var _keybindings = {};
+    function testBindings(d3_event, isCapturing) {
+      var didMatch = false;
+      var bindings = Object.keys(_keybindings).map(function(id2) {
+        return _keybindings[id2];
       });
-      let leadingTagKeyValues = [];
-      if (value.includes("=")) {
-        leadingTagKeyValues = searchable.filter((a) => a.tags && Object.keys(a.tags).some((key) => key + "=" + a.tags[key] === value)).concat(searchable.filter((a) => a.tags && Object.keys(a.tags).some((key) => leading(key + "=" + a.tags[key]))));
+      var i2, binding;
+      for (i2 = 0; i2 < bindings.length; i2++) {
+        binding = bindings[i2];
+        if (!binding.event.modifiers.shiftKey)
+          continue;
+        if (!!binding.capture !== isCapturing)
+          continue;
+        if (matches(d3_event, binding, true)) {
+          binding.callback(d3_event);
+          didMatch = true;
+          break;
+        }
       }
-      let results = leadingNames.concat(
-        leadingSuggestions,
-        leadingNamesStripped,
-        leadingSuggestionsStripped,
-        leadingTerms,
-        leadingSuggestionTerms,
-        leadingTagValues,
-        similarName,
-        similarSuggestions,
-        similarTerms,
-        leadingTagKeyValues
-      ).slice(0, MAXRESULTS - 1);
-      if (geometry) {
-        if (typeof geometry === "string") {
-          results.push(_this.fallback(geometry));
-        } else {
-          geometry.forEach((geom) => results.push(_this.fallback(geom)));
+      if (didMatch)
+        return;
+      for (i2 = 0; i2 < bindings.length; i2++) {
+        binding = bindings[i2];
+        if (binding.event.modifiers.shiftKey)
+          continue;
+        if (!!binding.capture !== isCapturing)
+          continue;
+        if (matches(d3_event, binding, false)) {
+          binding.callback(d3_event);
+          break;
         }
       }
-      return presetCollection(utilArrayUniq(results));
-    };
-    return _this;
-  }
-
-  // modules/presets/category.js
-  function presetCategory(categoryID, category, allPresets) {
-    let _this = Object.assign({}, category);
-    let _searchName;
-    let _searchNameStripped;
-    _this.id = categoryID;
-    _this.members = presetCollection(
-      (category.members || []).map((presetID) => allPresets[presetID]).filter(Boolean)
-    );
-    _this.geometry = _this.members.collection.reduce((acc, preset) => {
-      for (let i2 in preset.geometry) {
-        const geometry = preset.geometry[i2];
-        if (acc.indexOf(geometry) === -1) {
-          acc.push(geometry);
+      function matches(d3_event2, binding2, testShift) {
+        var event = d3_event2;
+        var isMatch = false;
+        var tryKeyCode = true;
+        if (event.key !== void 0) {
+          tryKeyCode = event.key.charCodeAt(0) > 127;
+          isMatch = true;
+          if (binding2.event.key === void 0) {
+            isMatch = false;
+          } else if (Array.isArray(binding2.event.key)) {
+            if (binding2.event.key.map(function(s) {
+              return s.toLowerCase();
+            }).indexOf(event.key.toLowerCase()) === -1) {
+              isMatch = false;
+            }
+          } else {
+            if (event.key.toLowerCase() !== binding2.event.key.toLowerCase()) {
+              isMatch = false;
+            }
+          }
+        }
+        if (!isMatch && (tryKeyCode || binding2.event.modifiers.altKey)) {
+          isMatch = event.keyCode === binding2.event.keyCode;
+        }
+        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.metaKey !== binding2.event.modifiers.metaKey)
+          return false;
+        if (testShift && event.shiftKey !== binding2.event.modifiers.shiftKey)
+          return false;
+        return true;
       }
-      return acc;
-    }, []);
-    _this.matchGeometry = (geom) => _this.geometry.indexOf(geom) >= 0;
-    _this.matchAllGeometry = (geometries) => _this.members.collection.some((preset) => preset.matchAllGeometry(geometries));
-    _this.matchScore = () => -1;
-    _this.name = () => _t(`_tagging.presets.categories.${categoryID}.name`, { "default": categoryID });
-    _this.nameLabel = () => _t.append(`_tagging.presets.categories.${categoryID}.name`, { "default": categoryID });
-    _this.terms = () => [];
-    _this.searchName = () => {
-      if (!_searchName) {
-        _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
+    }
+    function capture(d3_event) {
+      testBindings(d3_event, true);
+    }
+    function bubble(d3_event) {
+      var tagName = select_default2(d3_event.target).node().tagName;
+      if (tagName === "INPUT" || tagName === "SELECT" || tagName === "TEXTAREA") {
+        return;
       }
-      return _searchName;
+      testBindings(d3_event, false);
+    }
+    function keybinding(selection2) {
+      selection2 = selection2 || select_default2(document);
+      selection2.on("keydown.capture." + namespace, capture, true);
+      selection2.on("keydown.bubble." + namespace, bubble, false);
+      return keybinding;
+    }
+    keybinding.unbind = function(selection2) {
+      _keybindings = [];
+      selection2 = selection2 || select_default2(document);
+      selection2.on("keydown.capture." + namespace, null);
+      selection2.on("keydown.bubble." + namespace, null);
+      return keybinding;
     };
-    _this.searchNameStripped = () => {
-      if (!_searchNameStripped) {
-        _searchNameStripped = _this.searchName();
-        if (_searchNameStripped.normalize)
-          _searchNameStripped = _searchNameStripped.normalize("NFD");
-        _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, "");
+    keybinding.clear = function() {
+      _keybindings = {};
+      return keybinding;
+    };
+    keybinding.off = function(codes, capture2) {
+      var arr = utilArrayUniq([].concat(codes));
+      for (var i2 = 0; i2 < arr.length; i2++) {
+        var id2 = arr[i2] + (capture2 ? "-capture" : "-bubble");
+        delete _keybindings[id2];
       }
-      return _searchNameStripped;
+      return keybinding;
     };
-    _this.searchAliases = () => [];
-    _this.searchAliasesStripped = () => [];
-    return _this;
-  }
-
-  // modules/presets/field.js
-  function presetField(fieldID, field) {
-    let _this = Object.assign({}, field);
-    _this.id = fieldID;
-    _this.safeid = utilSafeClassName(fieldID);
-    _this.matchGeometry = (geom) => !_this.geometry || _this.geometry.indexOf(geom) !== -1;
-    _this.matchAllGeometry = (geometries) => {
-      return !_this.geometry || geometries.every((geom) => _this.geometry.indexOf(geom) !== -1);
+    keybinding.on = function(codes, callback, capture2) {
+      if (typeof callback !== "function") {
+        return keybinding.off(codes, capture2);
+      }
+      var arr = utilArrayUniq([].concat(codes));
+      for (var i2 = 0; i2 < arr.length; i2++) {
+        var id2 = arr[i2] + (capture2 ? "-capture" : "-bubble");
+        var binding = {
+          id: id2,
+          capture: capture2,
+          callback,
+          event: {
+            key: void 0,
+            // preferred
+            keyCode: 0,
+            // fallback
+            modifiers: {
+              shiftKey: false,
+              ctrlKey: false,
+              altKey: false,
+              metaKey: false
+            }
+          }
+        };
+        if (_keybindings[id2]) {
+          console.warn('warning: duplicate keybinding for "' + id2 + '"');
+        }
+        _keybindings[id2] = binding;
+        var matches = arr[i2].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
+        for (var j2 = 0; j2 < matches.length; 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;
+          } else {
+            binding.event.key = utilKeybinding.keys[matches[j2]] || matches[j2];
+            if (matches[j2] in utilKeybinding.keyCodes) {
+              binding.event.keyCode = utilKeybinding.keyCodes[matches[j2]];
+            }
+          }
+        }
+      }
+      return keybinding;
     };
-    _this.t = (scope, options2) => _t(`_tagging.presets.fields.${fieldID}.${scope}`, options2);
-    _this.t.html = (scope, options2) => _t.html(`_tagging.presets.fields.${fieldID}.${scope}`, options2);
-    _this.t.append = (scope, options2) => _t.append(`_tagging.presets.fields.${fieldID}.${scope}`, options2);
-    _this.hasTextForStringId = (scope) => _mainLocalizer.hasTextForStringId(`_tagging.presets.fields.${fieldID}.${scope}`);
-    _this.title = () => _this.overrideLabel || _this.t("label", { "default": fieldID });
-    _this.label = () => _this.overrideLabel ? (selection2) => selection2.text(_this.overrideLabel) : _this.t.append("label", { "default": fieldID });
-    const _placeholder = _this.placeholder;
-    _this.placeholder = () => _this.t("placeholder", { "default": _placeholder });
-    _this.originalTerms = (_this.terms || []).join();
-    _this.terms = () => _this.t("terms", { "default": _this.originalTerms }).toLowerCase().trim().split(/\s*,+\s*/);
-    _this.increment = _this.type === "number" ? _this.increment || 1 : void 0;
-    return _this;
+    return keybinding;
   }
-
-  // modules/presets/preset.js
-  function presetPreset(presetID, preset, addable, allFields, allPresets) {
-    allFields = allFields || {};
-    allPresets = allPresets || {};
-    let _this = Object.assign({}, preset);
-    let _addable = addable || false;
-    let _resolvedFields;
-    let _resolvedMoreFields;
-    let _searchName;
-    let _searchNameStripped;
-    let _searchAliases;
-    let _searchAliasesStripped;
-    _this.id = presetID;
-    _this.safeid = utilSafeClassName(presetID);
-    _this.originalTerms = (_this.terms || []).join();
-    _this.originalName = _this.name || "";
-    _this.originalAliases = (_this.aliases || []).join("\n");
-    _this.originalScore = _this.matchScore || 1;
-    _this.originalReference = _this.reference || {};
-    _this.originalFields = _this.fields || [];
-    _this.originalMoreFields = _this.moreFields || [];
-    _this.fields = () => _resolvedFields || (_resolvedFields = resolve("fields"));
-    _this.moreFields = () => _resolvedMoreFields || (_resolvedMoreFields = resolve("moreFields"));
-    _this.resetFields = () => _resolvedFields = _resolvedMoreFields = null;
-    _this.tags = _this.tags || {};
-    _this.addTags = _this.addTags || _this.tags;
-    _this.removeTags = _this.removeTags || _this.addTags;
-    _this.geometry = _this.geometry || [];
-    _this.matchGeometry = (geom) => _this.geometry.indexOf(geom) >= 0;
-    _this.matchAllGeometry = (geoms) => geoms.every(_this.matchGeometry);
-    _this.matchScore = (entityTags) => {
-      const tags = _this.tags;
-      let seen = {};
-      let score = 0;
-      for (let k in tags) {
-        seen[k] = true;
-        if (entityTags[k] === tags[k]) {
-          score += _this.originalScore;
-        } else if (tags[k] === "*" && k in entityTags) {
-          score += _this.originalScore / 2;
-        } else {
-          return -1;
-        }
-      }
-      const addTags = _this.addTags;
-      for (let k in addTags) {
-        if (!seen[k] && entityTags[k] === addTags[k]) {
-          score += _this.originalScore;
-        }
-      }
-      if (_this.searchable === false) {
-        score *= 0.999;
+  utilKeybinding.modifierCodes = {
+    // Shift key, ⇧
+    "\u21E7": 16,
+    shift: 16,
+    // CTRL key, on Mac: ⌃
+    "\u2303": 17,
+    ctrl: 17,
+    // ALT key, on Mac: ⌥ (Alt)
+    "\u2325": 18,
+    alt: 18,
+    option: 18,
+    // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
+    "\u2318": 91,
+    meta: 91,
+    cmd: 91,
+    "super": 91,
+    win: 91
+  };
+  utilKeybinding.modifierProperties = {
+    16: "shiftKey",
+    17: "ctrlKey",
+    18: "altKey",
+    91: "metaKey"
+  };
+  utilKeybinding.plusKeys = ["plus", "ffplus", "=", "ffequals", "\u2260", "\xB1"];
+  utilKeybinding.minusKeys = ["_", "-", "ffminus", "dash", "\u2013", "\u2014"];
+  utilKeybinding.keys = {
+    // Backspace key, on Mac: ⌫ (Backspace)
+    "\u232B": "Backspace",
+    backspace: "Backspace",
+    // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
+    "\u21E5": "Tab",
+    "\u21C6": "Tab",
+    tab: "Tab",
+    // Return key, ↩
+    "\u21A9": "Enter",
+    "\u21B5": "Enter",
+    "\u23CE": "Enter",
+    "return": "Enter",
+    enter: "Enter",
+    "\u2305": "Enter",
+    // Pause/Break key
+    "pause": "Pause",
+    "pause-break": "Pause",
+    // Caps Lock key, ⇪
+    "\u21EA": "CapsLock",
+    caps: "CapsLock",
+    "caps-lock": "CapsLock",
+    // Escape key, on Mac: ⎋, on Windows: Esc
+    "\u238B": ["Escape", "Esc"],
+    escape: ["Escape", "Esc"],
+    esc: ["Escape", "Esc"],
+    // Space key
+    space: [" ", "Spacebar"],
+    // Page-Up key, or pgup, on Mac: ↖
+    "\u2196": "PageUp",
+    pgup: "PageUp",
+    "page-up": "PageUp",
+    // Page-Down key, or pgdown, on Mac: ↘
+    "\u2198": "PageDown",
+    pgdown: "PageDown",
+    "page-down": "PageDown",
+    // END key, on Mac: ⇟
+    "\u21DF": "End",
+    end: "End",
+    // HOME key, on Mac: ⇞
+    "\u21DE": "Home",
+    home: "Home",
+    // Insert key, or ins
+    ins: "Insert",
+    insert: "Insert",
+    // Delete key, on Mac: ⌦ (Delete)
+    "\u2326": ["Delete", "Del"],
+    del: ["Delete", "Del"],
+    "delete": ["Delete", "Del"],
+    // Left Arrow Key, or ←
+    "\u2190": ["ArrowLeft", "Left"],
+    left: ["ArrowLeft", "Left"],
+    "arrow-left": ["ArrowLeft", "Left"],
+    // Up Arrow Key, or ↑
+    "\u2191": ["ArrowUp", "Up"],
+    up: ["ArrowUp", "Up"],
+    "arrow-up": ["ArrowUp", "Up"],
+    // Right Arrow Key, or →
+    "\u2192": ["ArrowRight", "Right"],
+    right: ["ArrowRight", "Right"],
+    "arrow-right": ["ArrowRight", "Right"],
+    // Up Arrow Key, or ↓
+    "\u2193": ["ArrowDown", "Down"],
+    down: ["ArrowDown", "Down"],
+    "arrow-down": ["ArrowDown", "Down"],
+    // odities, stuff for backward compatibility (browsers and code):
+    // Num-Multiply, or *
+    "*": ["*", "Multiply"],
+    star: ["*", "Multiply"],
+    asterisk: ["*", "Multiply"],
+    multiply: ["*", "Multiply"],
+    // Num-Plus or +
+    "+": ["+", "Add"],
+    "plus": ["+", "Add"],
+    // Num-Subtract, or -
+    "-": ["-", "Subtract"],
+    subtract: ["-", "Subtract"],
+    "dash": ["-", "Subtract"],
+    // Semicolon
+    semicolon: ";",
+    // = or equals
+    equals: "=",
+    // Comma, or ,
+    comma: ",",
+    // Period, or ., or full-stop
+    period: ".",
+    "full-stop": ".",
+    // Slash, or /, or forward-slash
+    slash: "/",
+    "forward-slash": "/",
+    // Tick, or `, or back-quote
+    tick: "`",
+    "back-quote": "`",
+    // Open bracket, or [
+    "open-bracket": "[",
+    // Back slash, or \
+    "back-slash": "\\",
+    // Close backet, or ]
+    "close-bracket": "]",
+    // Apostrophe, or Quote, or '
+    quote: "'",
+    apostrophe: "'",
+    // NUMPAD 0-9
+    "num-0": "0",
+    "num-1": "1",
+    "num-2": "2",
+    "num-3": "3",
+    "num-4": "4",
+    "num-5": "5",
+    "num-6": "6",
+    "num-7": "7",
+    "num-8": "8",
+    "num-9": "9",
+    // F1-F25
+    f1: "F1",
+    f2: "F2",
+    f3: "F3",
+    f4: "F4",
+    f5: "F5",
+    f6: "F6",
+    f7: "F7",
+    f8: "F8",
+    f9: "F9",
+    f10: "F10",
+    f11: "F11",
+    f12: "F12",
+    f13: "F13",
+    f14: "F14",
+    f15: "F15",
+    f16: "F16",
+    f17: "F17",
+    f18: "F18",
+    f19: "F19",
+    f20: "F20",
+    f21: "F21",
+    f22: "F22",
+    f23: "F23",
+    f24: "F24",
+    f25: "F25"
+  };
+  utilKeybinding.keyCodes = {
+    // Backspace key, on Mac: ⌫ (Backspace)
+    "\u232B": 8,
+    backspace: 8,
+    // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
+    "\u21E5": 9,
+    "\u21C6": 9,
+    tab: 9,
+    // Return key, ↩
+    "\u21A9": 13,
+    "\u21B5": 13,
+    "\u23CE": 13,
+    "return": 13,
+    enter: 13,
+    "\u2305": 13,
+    // Pause/Break key
+    "pause": 19,
+    "pause-break": 19,
+    // Caps Lock key, ⇪
+    "\u21EA": 20,
+    caps: 20,
+    "caps-lock": 20,
+    // Escape key, on Mac: ⎋, on Windows: Esc
+    "\u238B": 27,
+    escape: 27,
+    esc: 27,
+    // Space key
+    space: 32,
+    // Page-Up key, or pgup, on Mac: ↖
+    "\u2196": 33,
+    pgup: 33,
+    "page-up": 33,
+    // Page-Down key, or pgdown, on Mac: ↘
+    "\u2198": 34,
+    pgdown: 34,
+    "page-down": 34,
+    // END key, on Mac: ⇟
+    "\u21DF": 35,
+    end: 35,
+    // HOME key, on Mac: ⇞
+    "\u21DE": 36,
+    home: 36,
+    // Insert key, or ins
+    ins: 45,
+    insert: 45,
+    // Delete key, on Mac: ⌦ (Delete)
+    "\u2326": 46,
+    del: 46,
+    "delete": 46,
+    // Left Arrow Key, or ←
+    "\u2190": 37,
+    left: 37,
+    "arrow-left": 37,
+    // Up Arrow Key, or ↑
+    "\u2191": 38,
+    up: 38,
+    "arrow-up": 38,
+    // Right Arrow Key, or →
+    "\u2192": 39,
+    right: 39,
+    "arrow-right": 39,
+    // Up Arrow Key, or ↓
+    "\u2193": 40,
+    down: 40,
+    "arrow-down": 40,
+    // odities, printing characters that come out wrong:
+    // Firefox Equals
+    "ffequals": 61,
+    // Num-Multiply, or *
+    "*": 106,
+    star: 106,
+    asterisk: 106,
+    multiply: 106,
+    // Num-Plus or +
+    "+": 107,
+    "plus": 107,
+    // Num-Subtract, or -
+    "-": 109,
+    subtract: 109,
+    // Vertical Bar / Pipe
+    "|": 124,
+    // Firefox Plus
+    "ffplus": 171,
+    // Firefox Minus
+    "ffminus": 173,
+    // Semicolon
+    ";": 186,
+    semicolon: 186,
+    // = or equals
+    "=": 187,
+    "equals": 187,
+    // Comma, or ,
+    ",": 188,
+    comma: 188,
+    // Dash / Underscore key
+    "dash": 189,
+    // Period, or ., or full-stop
+    ".": 190,
+    period: 190,
+    "full-stop": 190,
+    // Slash, or /, or forward-slash
+    "/": 191,
+    slash: 191,
+    "forward-slash": 191,
+    // Tick, or `, or back-quote
+    "`": 192,
+    tick: 192,
+    "back-quote": 192,
+    // Open bracket, or [
+    "[": 219,
+    "open-bracket": 219,
+    // Back slash, or \
+    "\\": 220,
+    "back-slash": 220,
+    // Close backet, or ]
+    "]": 221,
+    "close-bracket": 221,
+    // Apostrophe, or Quote, or '
+    "'": 222,
+    quote: 222,
+    apostrophe: 222
+  };
+  var i = 95;
+  var n = 0;
+  while (++i < 106) {
+    utilKeybinding.keyCodes["num-" + n] = i;
+    ++n;
+  }
+  i = 47;
+  n = 0;
+  while (++i < 58) {
+    utilKeybinding.keyCodes[n] = i;
+    ++n;
+  }
+  i = 111;
+  n = 1;
+  while (++i < 136) {
+    utilKeybinding.keyCodes["f" + n] = i;
+    ++n;
+  }
+  i = 64;
+  while (++i < 91) {
+    utilKeybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
+  }
+
+  // modules/util/object.js
+  function utilObjectOmit(obj, omitKeys) {
+    return Object.keys(obj).reduce(function(result, key) {
+      if (omitKeys.indexOf(key) === -1) {
+        result[key] = obj[key];
       }
-      return score;
+      return result;
+    }, {});
+  }
+
+  // modules/util/rebind.js
+  function utilRebind(target, source) {
+    var i2 = 1, n2 = arguments.length, method;
+    while (++i2 < n2) {
+      target[method = arguments[i2]] = d3_rebind(target, source, source[method]);
+    }
+    return target;
+  }
+  function d3_rebind(target, source, method) {
+    return function() {
+      var value = method.apply(source, arguments);
+      return value === source ? target : value;
     };
-    _this.t = (scope, options2) => {
-      const textID = `_tagging.presets.presets.${presetID}.${scope}`;
-      return _t(textID, options2);
+  }
+
+  // modules/util/session_mutex.js
+  function utilSessionMutex(name) {
+    var mutex = {};
+    var intervalID;
+    function renew() {
+      var expires = /* @__PURE__ */ new Date();
+      expires.setSeconds(expires.getSeconds() + 5);
+      document.cookie = name + "=1; expires=" + expires.toUTCString() + "; sameSite=strict";
+    }
+    mutex.lock = function() {
+      if (intervalID)
+        return true;
+      var cookie = document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + name + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1");
+      if (cookie)
+        return false;
+      renew();
+      intervalID = window.setInterval(renew, 4e3);
+      return true;
     };
-    _this.t.append = (scope, options2) => {
-      const textID = `_tagging.presets.presets.${presetID}.${scope}`;
-      return _t.append(textID, options2);
+    mutex.unlock = function() {
+      if (!intervalID)
+        return;
+      document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict";
+      clearInterval(intervalID);
+      intervalID = null;
     };
-    _this.name = () => {
-      return _this.t("name", { "default": _this.originalName });
+    mutex.locked = function() {
+      return !!intervalID;
     };
-    _this.nameLabel = () => _this.t.append("name", { "default": _this.originalName });
-    _this.subtitle = () => {
-      if (_this.suggestion) {
-        let path = presetID.split("/");
-        path.pop();
-        return _t("_tagging.presets.presets." + path.join("/") + ".name");
+    return mutex;
+  }
+
+  // modules/util/tiler.js
+  function utilTiler() {
+    var _size = [256, 256];
+    var _scale = 256;
+    var _tileSize = 256;
+    var _zoomExtent = [0, 20];
+    var _translate = [_size[0] / 2, _size[1] / 2];
+    var _margin = 0;
+    var _skipNullIsland = false;
+    function clamp3(num, min3, max3) {
+      return Math.max(min3, Math.min(num, max3));
+    }
+    function nearNullIsland(tile) {
+      var x = tile[0];
+      var y = tile[1];
+      var z = tile[2];
+      if (z >= 7) {
+        var center = Math.pow(2, z - 1);
+        var width = Math.pow(2, z - 6);
+        var min3 = center - width / 2;
+        var max3 = center + width / 2 - 1;
+        return x >= min3 && x <= max3 && y >= min3 && y <= max3;
       }
-      return null;
-    };
-    _this.subtitleLabel = () => {
-      if (_this.suggestion) {
-        let path = presetID.split("/");
-        path.pop();
-        return _t.append("_tagging.presets.presets." + path.join("/") + ".name");
+      return false;
+    }
+    function tiler8() {
+      var z = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
+      var z0 = clamp3(Math.round(z), _zoomExtent[0], _zoomExtent[1]);
+      var tileMin = 0;
+      var tileMax = Math.pow(2, z0) - 1;
+      var log2ts = Math.log(_tileSize) * Math.LOG2E;
+      var k = Math.pow(2, z - z0 + log2ts);
+      var origin = [
+        (_translate[0] - _scale / 2) / k,
+        (_translate[1] - _scale / 2) / k
+      ];
+      var cols = range(
+        clamp3(Math.floor(-origin[0]) - _margin, tileMin, tileMax + 1),
+        clamp3(Math.ceil(_size[0] / k - origin[0]) + _margin, tileMin, tileMax + 1)
+      );
+      var rows = range(
+        clamp3(Math.floor(-origin[1]) - _margin, tileMin, tileMax + 1),
+        clamp3(Math.ceil(_size[1] / k - origin[1]) + _margin, tileMin, tileMax + 1)
+      );
+      var tiles = [];
+      for (var i2 = 0; i2 < rows.length; i2++) {
+        var y = rows[i2];
+        for (var j2 = 0; j2 < cols.length; j2++) {
+          var x = cols[j2];
+          if (i2 >= _margin && i2 <= rows.length - _margin && j2 >= _margin && j2 <= cols.length - _margin) {
+            tiles.unshift([x, y, z0]);
+          } else {
+            tiles.push([x, y, z0]);
+          }
+        }
       }
-      return null;
+      tiles.translate = origin;
+      tiles.scale = k;
+      return tiles;
+    }
+    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 = tiler8();
+      var ts = tiles.scale;
+      return tiles.map(function(tile) {
+        if (_skipNullIsland && nearNullIsland(tile)) {
+          return false;
+        }
+        var x = tile[0] * ts - origin[0];
+        var y = tile[1] * ts - origin[1];
+        return {
+          id: tile.toString(),
+          xyz: tile,
+          extent: geoExtent(
+            projection2.invert([x, y + ts]),
+            projection2.invert([x + ts, y])
+          )
+        };
+      }).filter(Boolean);
     };
-    _this.aliases = () => {
-      return _this.t("aliases", { "default": _this.originalAliases }).trim().split(/\s*[\r\n]+\s*/);
+    tiler8.getGeoJSON = function(projection2) {
+      var features = tiler8.getTiles(projection2).map(function(tile) {
+        return {
+          type: "Feature",
+          properties: {
+            id: tile.id,
+            name: tile.id
+          },
+          geometry: {
+            type: "Polygon",
+            coordinates: [tile.extent.polygon()]
+          }
+        };
+      });
+      return {
+        type: "FeatureCollection",
+        features
+      };
     };
-    _this.terms = () => _this.t("terms", { "default": _this.originalTerms }).toLowerCase().trim().split(/\s*,+\s*/);
-    _this.searchName = () => {
-      if (!_searchName) {
-        _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
-      }
-      return _searchName;
+    tiler8.tileSize = function(val) {
+      if (!arguments.length)
+        return _tileSize;
+      _tileSize = val;
+      return tiler8;
     };
-    _this.searchNameStripped = () => {
-      if (!_searchNameStripped) {
-        _searchNameStripped = stripDiacritics(_this.searchName());
-      }
-      return _searchNameStripped;
+    tiler8.zoomExtent = function(val) {
+      if (!arguments.length)
+        return _zoomExtent;
+      _zoomExtent = val;
+      return tiler8;
     };
-    _this.searchAliases = () => {
-      if (!_searchAliases) {
-        _searchAliases = _this.aliases().map((alias) => alias.toLowerCase());
-      }
-      return _searchAliases;
+    tiler8.size = function(val) {
+      if (!arguments.length)
+        return _size;
+      _size = val;
+      return tiler8;
     };
-    _this.searchAliasesStripped = () => {
-      if (!_searchAliasesStripped) {
-        _searchAliasesStripped = _this.searchAliases();
-        _searchAliasesStripped = _searchAliasesStripped.map(stripDiacritics);
-      }
-      return _searchAliasesStripped;
+    tiler8.scale = function(val) {
+      if (!arguments.length)
+        return _scale;
+      _scale = val;
+      return tiler8;
     };
-    _this.isFallback = () => {
-      const tagCount = Object.keys(_this.tags).length;
-      return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty("area");
+    tiler8.translate = function(val) {
+      if (!arguments.length)
+        return _translate;
+      _translate = val;
+      return tiler8;
     };
-    _this.addable = function(val) {
+    tiler8.margin = function(val) {
       if (!arguments.length)
-        return _addable;
-      _addable = val;
-      return _this;
+        return _margin;
+      _margin = +val;
+      return tiler8;
     };
-    _this.reference = () => {
-      const qid = _this.tags.wikidata || _this.tags["flag:wikidata"] || _this.tags["brand:wikidata"] || _this.tags["network:wikidata"] || _this.tags["operator:wikidata"];
-      if (qid) {
-        return { qid };
-      }
-      let key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, "name"))[0];
-      let value = _this.originalReference.value || _this.tags[key];
-      if (value === "*") {
-        return { key };
-      } else {
-        return { key, value };
-      }
+    tiler8.skipNullIsland = function(val) {
+      if (!arguments.length)
+        return _skipNullIsland;
+      _skipNullIsland = val;
+      return tiler8;
     };
-    _this.unsetTags = (tags, geometry, ignoringKeys, skipFieldDefaults) => {
-      let removeTags = ignoringKeys ? utilObjectOmit(_this.removeTags, ignoringKeys) : _this.removeTags;
-      tags = utilObjectOmit(tags, Object.keys(removeTags));
-      if (geometry && !skipFieldDefaults) {
-        _this.fields().forEach((field) => {
-          if (field.matchGeometry(geometry) && field.key && field.default === tags[field.key]) {
-            delete tags[field.key];
-          }
-        });
+    return tiler8;
+  }
+
+  // modules/util/trigger_event.js
+  function utilTriggerEvent(target, type2) {
+    target.each(function() {
+      var evt = document.createEvent("HTMLEvents");
+      evt.initEvent(type2, true, true);
+      this.dispatchEvent(evt);
+    });
+  }
+
+  // modules/core/localizer.js
+  var _mainLocalizer = coreLocalizer();
+  var _t = _mainLocalizer.t;
+  function coreLocalizer() {
+    let localizer = {};
+    let _dataLanguages = {};
+    let _dataLocales = {};
+    let _localeStrings = {};
+    let _localeCode = "en-US";
+    let _localeCodes = ["en-US", "en"];
+    let _languageCode = "en";
+    let _textDirection = "ltr";
+    let _usesMetric = false;
+    let _languageNames = {};
+    let _scriptNames = {};
+    localizer.localeCode = () => _localeCode;
+    localizer.localeCodes = () => _localeCodes;
+    localizer.languageCode = () => _languageCode;
+    localizer.textDirection = () => _textDirection;
+    localizer.usesMetric = () => _usesMetric;
+    localizer.languageNames = () => _languageNames;
+    localizer.scriptNames = () => _scriptNames;
+    let _preferredLocaleCodes = [];
+    localizer.preferredLocaleCodes = function(codes) {
+      if (!arguments.length)
+        return _preferredLocaleCodes;
+      if (typeof codes === "string") {
+        _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
+      } else {
+        _preferredLocaleCodes = codes;
       }
-      delete tags.area;
-      return tags;
+      return localizer;
     };
-    _this.setTags = (tags, geometry, skipFieldDefaults) => {
-      const addTags = _this.addTags;
-      tags = Object.assign({}, tags);
-      for (let k in addTags) {
-        if (addTags[k] === "*") {
-          if (_this.tags[k] || !tags[k]) {
-            tags[k] = "yes";
-          }
-        } else {
-          tags[k] = addTags[k];
-        }
-      }
-      if (!addTags.hasOwnProperty("area")) {
-        delete tags.area;
-        if (geometry === "area") {
-          let needsAreaTag = true;
-          for (let k in addTags) {
-            if (_this.geometry.indexOf("line") === -1 && k in osmAreaKeys || k in osmAreaKeysExceptions && addTags[k] in osmAreaKeysExceptions[k]) {
-              needsAreaTag = false;
-              break;
-            }
-          }
-          if (needsAreaTag) {
-            tags.area = "yes";
-          }
+    var _loadPromise;
+    localizer.ensureLoaded = () => {
+      if (_loadPromise)
+        return _loadPromise;
+      let filesToFetch = [
+        "languages",
+        // load the list of languages
+        "locales"
+        // load the list of supported locales
+      ];
+      const localeDirs = {
+        general: "locales",
+        tagging: presetsCdnUrl + "dist/translations"
+      };
+      let fileMap = _mainFileFetcher.fileMap();
+      for (let scopeId in localeDirs) {
+        const key = `locales_index_${scopeId}`;
+        if (!fileMap[key]) {
+          fileMap[key] = localeDirs[scopeId] + "/index.min.json";
         }
+        filesToFetch.push(key);
       }
-      if (geometry && !skipFieldDefaults) {
-        _this.fields().forEach((field) => {
-          if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
-            tags[field.key] = field.default;
-          }
+      return _loadPromise = Promise.all(filesToFetch.map((key) => _mainFileFetcher.get(key))).then((results) => {
+        _dataLanguages = results[0];
+        _dataLocales = results[1];
+        let indexes = results.slice(2);
+        let requestedLocales = (_preferredLocaleCodes || []).concat(utilDetect().browserLocales).concat(["en"]);
+        _localeCodes = localesToUseFrom(requestedLocales);
+        _localeCode = _localeCodes[0];
+        let loadStringsPromises = [];
+        indexes.forEach((index, i2) => {
+          const fullCoverageIndex = _localeCodes.findIndex(function(locale2) {
+            return index[locale2] && index[locale2].pct === 1;
+          });
+          _localeCodes.slice(0, fullCoverageIndex + 1).forEach(function(code) {
+            let scopeId = Object.keys(localeDirs)[i2];
+            let directory = Object.values(localeDirs)[i2];
+            if (index[code])
+              loadStringsPromises.push(localizer.loadLocale(code, scopeId, directory));
+          });
         });
-      }
-      return tags;
+        return Promise.all(loadStringsPromises);
+      }).then(() => {
+        updateForCurrentLocale();
+      }).catch((err) => console.error(err));
     };
-    function resolve(which) {
-      const fieldIDs = which === "fields" ? _this.originalFields : _this.originalMoreFields;
-      let resolved = [];
-      fieldIDs.forEach((fieldID) => {
-        const match = fieldID.match(/\{(.*)\}/);
-        if (match !== null) {
-          resolved = resolved.concat(inheritFields(match[1], which));
-        } else if (allFields[fieldID]) {
-          resolved.push(allFields[fieldID]);
-        } else {
-          console.log(`Cannot resolve "${fieldID}" found in ${_this.id}.${which}`);
-        }
-      });
-      if (!resolved.length) {
-        const endIndex = _this.id.lastIndexOf("/");
-        const parentID = endIndex && _this.id.substring(0, endIndex);
-        if (parentID) {
-          resolved = inheritFields(parentID, which);
-        }
-      }
-      return utilArrayUniq(resolved);
-      function inheritFields(presetID2, which2) {
-        const parent = allPresets[presetID2];
-        if (!parent)
-          return [];
-        if (which2 === "fields") {
-          return parent.fields().filter(shouldInherit);
-        } else if (which2 === "moreFields") {
-          return parent.moreFields();
-        } else {
-          return [];
+    function localesToUseFrom(requestedLocales) {
+      let supportedLocales = _dataLocales;
+      let toUse = [];
+      for (let i2 in requestedLocales) {
+        let locale2 = requestedLocales[i2];
+        if (supportedLocales[locale2])
+          toUse.push(locale2);
+        if (locale2.includes("-")) {
+          let langPart = locale2.split("-")[0];
+          if (supportedLocales[langPart])
+            toUse.push(langPart);
         }
       }
-      function shouldInherit(f2) {
-        if (f2.key && _this.tags[f2.key] !== void 0 && f2.type !== "multiCombo" && f2.type !== "semiCombo" && f2.type !== "manyCombo" && f2.type !== "check")
-          return false;
-        return true;
-      }
+      return utilArrayUniq(toUse);
     }
-    function stripDiacritics(s) {
-      if (s.normalize)
-        s = s.normalize("NFD");
-      s = s.replace(/[\u0300-\u036f]/g, "");
-      return s;
+    function updateForCurrentLocale() {
+      if (!_localeCode)
+        return;
+      _languageCode = _localeCode.split("-")[0];
+      const currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
+      const hash = utilStringQs(window.location.hash);
+      if (hash.rtl === "true") {
+        _textDirection = "rtl";
+      } else if (hash.rtl === "false") {
+        _textDirection = "ltr";
+      } else {
+        _textDirection = currentData && currentData.rtl ? "rtl" : "ltr";
+      }
+      let locale2 = _localeCode;
+      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";
     }
-    return _this;
-  }
-
-  // modules/presets/index.js
-  var _mainPresetIndex = presetIndex();
-  function presetIndex() {
-    const dispatch10 = dispatch_default("favoritePreset", "recentsChange");
-    const MAXRECENTS = 30;
-    const POINT = presetPreset("point", { name: "Point", tags: {}, geometry: ["point", "vertex"], matchScore: 0.1 });
-    const LINE = presetPreset("line", { name: "Line", tags: {}, geometry: ["line"], matchScore: 0.1 });
-    const AREA = presetPreset("area", { name: "Area", tags: { area: "yes" }, geometry: ["area"], matchScore: 0.1 });
-    const RELATION = presetPreset("relation", { name: "Relation", tags: {}, geometry: ["relation"], matchScore: 0.1 });
-    let _this = presetCollection([POINT, LINE, AREA, RELATION]);
-    let _presets = { point: POINT, line: LINE, area: AREA, relation: RELATION };
-    let _defaults = {
-      point: presetCollection([POINT]),
-      vertex: presetCollection([POINT]),
-      line: presetCollection([LINE]),
-      area: presetCollection([AREA]),
-      relation: presetCollection([RELATION])
-    };
-    let _fields = {};
-    let _categories = {};
-    let _universal = [];
-    let _addablePresetIDs = null;
-    let _recents;
-    let _favorites;
-    let _geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
-    let _loadPromise;
-    _this.ensureLoaded = () => {
-      if (_loadPromise)
-        return _loadPromise;
-      return _loadPromise = Promise.all([
-        _mainFileFetcher.get("preset_categories"),
-        _mainFileFetcher.get("preset_defaults"),
-        _mainFileFetcher.get("preset_presets"),
-        _mainFileFetcher.get("preset_fields")
-      ]).then((vals) => {
-        _this.merge({
-          categories: vals[0],
-          defaults: vals[1],
-          presets: vals[2],
-          fields: vals[3]
-        });
-        osmSetAreaKeys(_this.areaKeys());
-        osmSetPointTags(_this.pointTags());
-        osmSetVertexTags(_this.vertexTags());
+    localizer.loadLocale = (locale2, scopeId, directory) => {
+      if (locale2.toLowerCase() === "en-us")
+        locale2 = "en";
+      if (_localeStrings[scopeId] && _localeStrings[scopeId][locale2]) {
+        return Promise.resolve(locale2);
+      }
+      let fileMap = _mainFileFetcher.fileMap();
+      const key = `locale_${scopeId}_${locale2}`;
+      if (!fileMap[key]) {
+        fileMap[key] = `${directory}/${locale2}.min.json`;
+      }
+      return _mainFileFetcher.get(key).then((d) => {
+        if (!_localeStrings[scopeId])
+          _localeStrings[scopeId] = {};
+        _localeStrings[scopeId][locale2] = d[locale2];
+        return locale2;
       });
     };
-    _this.merge = (d) => {
-      let newLocationSets = [];
-      if (d.fields) {
-        Object.keys(d.fields).forEach((fieldID) => {
-          let f2 = d.fields[fieldID];
-          if (f2) {
-            f2 = presetField(fieldID, f2);
-            if (f2.locationSet)
-              newLocationSets.push(f2);
-            _fields[fieldID] = f2;
-          } else {
-            delete _fields[fieldID];
-          }
-        });
+    localizer.pluralRule = function(number3) {
+      return pluralRule(number3, _localeCode);
+    };
+    function pluralRule(number3, localeCode) {
+      const rules = "Intl" in window && Intl.PluralRules && new Intl.PluralRules(localeCode);
+      if (rules) {
+        return rules.select(number3);
       }
-      if (d.presets) {
-        Object.keys(d.presets).forEach((presetID) => {
-          let p = d.presets[presetID];
-          if (p) {
-            const isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
-            p = presetPreset(presetID, p, isAddable, _fields, _presets);
-            if (p.locationSet)
-              newLocationSets.push(p);
-            _presets[presetID] = p;
-          } else {
-            const existing = _presets[presetID];
-            if (existing && !existing.isFallback()) {
-              delete _presets[presetID];
-            }
-          }
-        });
+      if (number3 === 1)
+        return "one";
+      return "other";
+    }
+    localizer.tInfo = function(origStringId, replacements, locale2) {
+      let stringId = origStringId.trim();
+      let scopeId = "general";
+      if (stringId[0] === "_") {
+        let split = stringId.split(".");
+        scopeId = split[0].slice(1);
+        stringId = split.slice(1).join(".");
       }
-      if (d.categories) {
-        Object.keys(d.categories).forEach((categoryID) => {
-          let c = d.categories[categoryID];
-          if (c) {
-            c = presetCategory(categoryID, c, _presets);
-            if (c.locationSet)
-              newLocationSets.push(c);
-            _categories[categoryID] = c;
-          } else {
-            delete _categories[categoryID];
-          }
-        });
+      locale2 = locale2 || _localeCode;
+      let path = stringId.split(".").map((s) => s.replace(/<TX_DOT>/g, ".")).reverse();
+      let stringsKey = locale2;
+      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()];
       }
-      _this.collection = Object.values(_presets).concat(Object.values(_categories));
-      if (d.defaults) {
-        Object.keys(d.defaults).forEach((geometry) => {
-          const def = d.defaults[geometry];
-          if (Array.isArray(def)) {
-            _defaults[geometry] = presetCollection(
-              def.map((id2) => _presets[id2] || _categories[id2]).filter(Boolean)
-            );
-          } else {
-            delete _defaults[geometry];
+      if (result !== void 0) {
+        if (replacements) {
+          if (typeof result === "object" && Object.keys(result).length) {
+            const number3 = Object.values(replacements).find(function(value) {
+              return typeof value === "number";
+            });
+            if (number3 !== void 0) {
+              const rule = pluralRule(number3, locale2);
+              if (result[rule]) {
+                result = result[rule];
+              } else {
+                result = Object.values(result)[0];
+              }
+            }
           }
-        });
-      }
-      _universal = Object.values(_fields).filter((field) => field.universal);
-      Object.values(_presets).forEach((preset) => preset.resetFields());
-      _geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
-      _this.collection.forEach((preset) => {
-        (preset.geometry || []).forEach((geometry) => {
-          let g = _geometryIndex[geometry];
-          for (let key in preset.tags) {
-            g[key] = g[key] || {};
-            let value = preset.tags[key];
-            (g[key][value] = g[key][value] || []).push(preset);
+          if (typeof result === "string") {
+            for (let key in replacements) {
+              let value = replacements[key];
+              if (typeof value === "number") {
+                if (value.toLocaleString) {
+                  value = value.toLocaleString(locale2, {
+                    style: "decimal",
+                    useGrouping: true,
+                    minimumFractionDigits: 0
+                  });
+                } else {
+                  value = value.toString();
+                }
+              }
+              const token = `{${key}}`;
+              const regex = new RegExp(token, "g");
+              result = result.replace(regex, value);
+            }
           }
-        });
-      });
-      if (d.featureCollection && Array.isArray(d.featureCollection.features)) {
-        _mainLocations.mergeCustomGeoJSON(d.featureCollection);
+        }
+        if (typeof result === "string") {
+          return {
+            text: result,
+            locale: locale2
+          };
+        }
       }
-      if (newLocationSets.length) {
-        _mainLocations.mergeLocationSets(newLocationSets);
+      let index = _localeCodes.indexOf(locale2);
+      if (index >= 0 && index < _localeCodes.length - 1) {
+        let fallback = _localeCodes[index + 1];
+        return localizer.tInfo(origStringId, replacements, fallback);
       }
-      return _this;
+      if (replacements && "default" in replacements) {
+        return {
+          text: replacements.default,
+          locale: null
+        };
+      }
+      const missing = `Missing ${locale2} translation: ${origStringId}`;
+      if (typeof console !== "undefined")
+        console.error(missing);
+      return {
+        text: missing,
+        locale: "en"
+      };
     };
-    _this.match = (entity, resolver) => {
-      return resolver.transient(entity, "presetMatch", () => {
-        let geometry = entity.geometry(resolver);
-        if (geometry === "vertex" && entity.isOnAddressLine(resolver)) {
-          geometry = "point";
-        }
-        const entityExtent = entity.extent(resolver);
-        return _this.matchTags(entity.tags, geometry, entityExtent.center());
-      });
+    localizer.hasTextForStringId = function(stringId) {
+      return !!localizer.tInfo(stringId, { default: "nothing found" }).locale;
     };
-    _this.matchTags = (tags, geometry, loc) => {
-      const keyIndex = _geometryIndex[geometry];
-      let bestScore = -1;
-      let bestMatch;
-      let matchCandidates = [];
-      for (let k in tags) {
-        let indexMatches = [];
-        let valueIndex = keyIndex[k];
-        if (!valueIndex)
-          continue;
-        let keyValueMatches = valueIndex[tags[k]];
-        if (keyValueMatches)
-          indexMatches.push(...keyValueMatches);
-        let keyStarMatches = valueIndex["*"];
-        if (keyStarMatches)
-          indexMatches.push(...keyStarMatches);
-        if (indexMatches.length === 0)
-          continue;
-        for (let i2 = 0; i2 < indexMatches.length; i2++) {
-          const candidate = indexMatches[i2];
-          const score = candidate.matchScore(tags);
-          if (score === -1) {
-            continue;
-          }
-          matchCandidates.push({ score, candidate });
-          if (score > bestScore) {
-            bestScore = score;
-            bestMatch = candidate;
-          }
+    localizer.t = function(stringId, replacements, locale2) {
+      return localizer.tInfo(stringId, replacements, locale2).text;
+    };
+    localizer.t.html = function(stringId, replacements, locale2) {
+      replacements = Object.assign({}, replacements);
+      for (var k in replacements) {
+        if (typeof replacements[k] === "string") {
+          replacements[k] = escape_default(replacements[k]);
         }
-      }
-      if (bestMatch && bestMatch.locationSetID && bestMatch.locationSetID !== "+[Q2]" && Array.isArray(loc)) {
-        let validLocations = _mainLocations.locationsAt(loc);
-        if (!validLocations[bestMatch.locationSetID]) {
-          matchCandidates.sort((a, b) => a.score < b.score ? 1 : -1);
-          for (let i2 = 0; i2 < matchCandidates.length; i2++) {
-            const candidateScore = matchCandidates[i2];
-            if (!candidateScore.candidate.locationSetID || validLocations[candidateScore.candidate.locationSetID]) {
-              bestMatch = candidateScore.candidate;
-              bestScore = candidateScore.score;
-              break;
-            }
-          }
+        if (typeof replacements[k] === "object" && typeof replacements[k].html === "string") {
+          replacements[k] = replacements[k].html;
         }
       }
-      if (!bestMatch || bestMatch.isFallback()) {
-        for (let k in tags) {
-          if (/^addr:/.test(k) && keyIndex["addr:*"] && keyIndex["addr:*"]["*"]) {
-            bestMatch = keyIndex["addr:*"]["*"][0];
-            break;
+      const info = localizer.tInfo(stringId, replacements, locale2);
+      if (info.text) {
+        return `<span class="localized-text" lang="${info.locale || "und"}">${info.text}</span>`;
+      } else {
+        return "";
+      }
+    };
+    localizer.t.append = function(stringId, replacements, locale2) {
+      const ret = function(selection2) {
+        const info = localizer.tInfo(stringId, replacements, locale2);
+        return selection2.append("span").attr("class", "localized-text").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;
+      const langInfo = _dataLanguages[code];
+      if (langInfo) {
+        if (langInfo.nativeName) {
+          return localizer.t("translate.language_and_code", { language: langInfo.nativeName, code });
+        } else if (langInfo.base && langInfo.script) {
+          const base = langInfo.base;
+          if (_languageNames && _languageNames[base]) {
+            const scriptCode = langInfo.script;
+            const script = _scriptNames && _scriptNames[scriptCode] || scriptCode;
+            return localizer.t("translate.language_and_code", { language: _languageNames[base], code: script });
+          } else if (_dataLanguages[base] && _dataLanguages[base].nativeName) {
+            return localizer.t("translate.language_and_code", { language: _dataLanguages[base].nativeName, code });
           }
         }
       }
-      return bestMatch || _this.fallback(geometry);
+      return code;
     };
-    _this.allowsVertex = (entity, resolver) => {
-      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;
-        const geometries = osmNodeGeometriesForTags(entity.tags);
-        if (geometries.vertex)
-          return true;
-        if (geometries.point)
-          return false;
-        return true;
-      });
+    localizer.floatFormatter = (locale2) => {
+      if (!("Intl" in window && "NumberFormat" in Intl && "formatToParts" in Intl.NumberFormat.prototype)) {
+        return (number3, fractionDigits) => {
+          return fractionDigits === void 0 ? number3.toString() : number3.toFixed(fractionDigits);
+        };
+      } else {
+        return (number3, fractionDigits) => number3.toLocaleString(locale2, {
+          minimumFractionDigits: fractionDigits,
+          maximumFractionDigits: fractionDigits === void 0 ? 20 : fractionDigits
+        });
+      }
     };
-    _this.areaKeys = () => {
-      const ignore = {
-        barrier: true,
-        highway: true,
-        footway: true,
-        railway: true,
-        junction: true,
-        type: true
+    localizer.floatParser = (locale2) => {
+      const polyfill = (string) => +string.trim();
+      if (!("Intl" in window && "NumberFormat" in Intl))
+        return polyfill;
+      const format2 = new Intl.NumberFormat(locale2, { maximumFractionDigits: 20 });
+      if (!("formatToParts" in format2))
+        return polyfill;
+      const parts = format2.formatToParts(-12345.6);
+      const numerals = Array.from({ length: 10 }).map((_, i2) => format2.format(i2));
+      const index = new Map(numerals.map((d, i2) => [d, i2]));
+      const literalPart = parts.find((d) => d.type === "literal");
+      const literal = literalPart && new RegExp(`[${literalPart.value}]`, "g");
+      const groupPart = parts.find((d) => d.type === "group");
+      const group = groupPart && new RegExp(`[${groupPart.value}]`, "g");
+      const decimalPart = parts.find((d) => d.type === "decimal");
+      const decimal = decimalPart && new RegExp(`[${decimalPart.value}]`);
+      const numeral = new RegExp(`[${numerals.join("")}]`, "g");
+      const getIndex = (d) => index.get(d);
+      return (string) => {
+        string = string.trim();
+        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;
       };
-      let areaKeys = {};
-      const presets = _this.collection.filter((p) => !p.suggestion && !p.replacement);
-      presets.forEach((p) => {
-        const keys = p.tags && Object.keys(p.tags);
-        const key = keys && keys.length && keys[0];
-        if (!key)
-          return;
-        if (ignore[key])
-          return;
-        if (p.geometry.indexOf("area") !== -1) {
-          areaKeys[key] = areaKeys[key] || {};
-        }
-      });
-      presets.forEach((p) => {
-        let key;
-        for (key in p.addTags) {
-          const value = p.addTags[key];
-          if (key in areaKeys && p.geometry.indexOf("line") !== -1 && value !== "*") {
-            areaKeys[key][value] = true;
-          }
-        }
-      });
-      return areaKeys;
     };
-    _this.pointTags = () => {
-      return _this.collection.reduce((pointTags, d) => {
-        if (d.suggestion || d.replacement || d.searchable === false)
-          return pointTags;
-        const keys = d.tags && Object.keys(d.tags);
-        const key = keys && keys.length && keys[0];
-        if (!key)
-          return pointTags;
-        if (d.geometry.indexOf("point") !== -1) {
-          pointTags[key] = pointTags[key] || {};
-          pointTags[key][d.tags[key]] = true;
-        }
-        return pointTags;
-      }, {});
+    localizer.decimalPlaceCounter = (locale2) => {
+      var literal, group, decimal;
+      if ("Intl" in window && "NumberFormat" in Intl) {
+        const format2 = new Intl.NumberFormat(locale2, { maximumFractionDigits: 20 });
+        if ("formatToParts" in format2) {
+          const parts = format2.formatToParts(-12345.6);
+          const literalPart = parts.find((d) => d.type === "literal");
+          literal = literalPart && new RegExp(`[${literalPart.value}]`, "g");
+          const groupPart = parts.find((d) => d.type === "group");
+          group = groupPart && new RegExp(`[${groupPart.value}]`, "g");
+          const decimalPart = parts.find((d) => d.type === "decimal");
+          decimal = decimalPart && new RegExp(`[${decimalPart.value}]`);
+        }
+      }
+      return (string) => {
+        string = string.trim();
+        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;
+      };
     };
-    _this.vertexTags = () => {
-      return _this.collection.reduce((vertexTags, d) => {
-        if (d.suggestion || d.replacement || d.searchable === false)
-          return vertexTags;
-        const keys = d.tags && Object.keys(d.tags);
-        const key = keys && keys.length && keys[0];
-        if (!key)
-          return vertexTags;
-        if (d.geometry.indexOf("vertex") !== -1) {
-          vertexTags[key] = vertexTags[key] || {};
-          vertexTags[key][d.tags[key]] = true;
-        }
-        return vertexTags;
-      }, {});
+    return localizer;
+  }
+
+  // modules/presets/collection.js
+  function presetCollection(collection) {
+    const MAXRESULTS = 50;
+    let _this = {};
+    let _memo = {};
+    _this.collection = collection;
+    _this.item = (id2) => {
+      if (_memo[id2])
+        return _memo[id2];
+      const found = _this.collection.find((d) => d.id === id2);
+      if (found)
+        _memo[id2] = found;
+      return found;
     };
-    _this.field = (id2) => _fields[id2];
-    _this.universal = () => _universal;
-    _this.defaults = (geometry, n2, startWithRecents, loc, extraPresets) => {
-      let recents = [];
-      if (startWithRecents) {
-        recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
-      }
-      let defaults2;
-      if (_addablePresetIDs) {
-        defaults2 = Array.from(_addablePresetIDs).map(function(id2) {
-          var preset = _this.item(id2);
-          if (preset && preset.matchGeometry(geometry))
-            return preset;
-          return null;
-        }).filter(Boolean);
-      } else {
-        defaults2 = _defaults[geometry].collection.concat(_this.fallback(geometry));
-      }
-      let result = presetCollection(
-        utilArrayUniq(recents.concat(defaults2).concat(extraPresets || [])).slice(0, n2 - 1)
+    _this.index = (id2) => _this.collection.findIndex((d) => d.id === id2);
+    _this.matchGeometry = (geometry) => {
+      return presetCollection(
+        _this.collection.filter((d) => d.matchGeometry(geometry))
       );
-      if (Array.isArray(loc)) {
-        const validLocations = _mainLocations.locationsAt(loc);
-        result.collection = result.collection.filter((a) => !a.locationSetID || validLocations[a.locationSetID]);
-      }
-      return result;
     };
-    _this.addablePresetIDs = function(val) {
-      if (!arguments.length)
-        return _addablePresetIDs;
-      if (Array.isArray(val))
-        val = new Set(val);
-      _addablePresetIDs = val;
-      if (_addablePresetIDs) {
-        _this.collection.forEach((p) => {
-          if (p.addable)
-            p.addable(_addablePresetIDs.has(p.id));
-        });
-      } else {
-        _this.collection.forEach((p) => {
-          if (p.addable)
-            p.addable(true);
-        });
-      }
-      return _this;
+    _this.matchAllGeometry = (geometries) => {
+      return presetCollection(
+        _this.collection.filter((d) => d && d.matchAllGeometry(geometries))
+      );
     };
-    _this.recent = () => {
+    _this.matchAnyGeometry = (geometries) => {
       return presetCollection(
-        utilArrayUniq(_this.getRecents().map((d) => d.preset).filter((d) => d.searchable !== false))
+        _this.collection.filter((d) => geometries.some((geom) => d.matchGeometry(geom)))
       );
     };
-    function RibbonItem(preset, source) {
-      let item = {};
-      item.preset = preset;
-      item.source = source;
-      item.isFavorite = () => item.source === "favorite";
-      item.isRecent = () => item.source === "recent";
-      item.matches = (preset2) => item.preset.id === preset2.id;
-      item.minified = () => ({ pID: item.preset.id });
-      return item;
-    }
-    function ribbonItemForMinified(d, source) {
-      if (d && d.pID) {
-        const preset = _this.item(d.pID);
-        if (!preset)
-          return null;
-        return RibbonItem(preset, source);
+    _this.fallback = (geometry) => {
+      let id2 = geometry;
+      if (id2 === "vertex")
+        id2 = "point";
+      return _this.item(id2);
+    };
+    _this.search = (value, geometry, loc) => {
+      if (!value)
+        return _this;
+      value = value.toLowerCase().trim();
+      function leading(a) {
+        const index = a.indexOf(value);
+        return index === 0 || a[index - 1] === " ";
       }
-      return null;
-    }
-    _this.getGenericRibbonItems = () => {
-      return ["point", "line", "area"].map((id2) => RibbonItem(_this.item(id2), "generic"));
+      function leadingStrict(a) {
+        const index = a.indexOf(value);
+        return index === 0;
+      }
+      function sortPresets(nameProp, aliasesProp) {
+        return function sortNames(a, b) {
+          let aCompare = a[nameProp]();
+          let bCompare = b[nameProp]();
+          if (aliasesProp) {
+            const findMatchingAlias = (strings) => {
+              if (strings.some((s) => s === value)) {
+                return strings.find((s) => s === value);
+              } else {
+                return strings.filter((s) => s.includes(value)).sort((a2, b2) => a2.length - b2.length)[0];
+              }
+            };
+            aCompare = findMatchingAlias([aCompare].concat(a[aliasesProp]()));
+            bCompare = findMatchingAlias([bCompare].concat(b[aliasesProp]()));
+          }
+          if (value === aCompare)
+            return -1;
+          if (value === bCompare)
+            return 1;
+          let i2 = b.originalScore - a.originalScore;
+          if (i2 !== 0)
+            return i2;
+          i2 = aCompare.indexOf(value) - bCompare.indexOf(value);
+          if (i2 !== 0)
+            return i2;
+          return aCompare.length - bCompare.length;
+        };
+      }
+      let pool = _this.collection;
+      if (Array.isArray(loc)) {
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
+        pool = pool.filter((a) => !a.locationSetID || validHere[a.locationSetID]);
+      }
+      const searchable = pool.filter((a) => a.searchable !== false && a.suggestion !== true);
+      const suggestions = pool.filter((a) => a.suggestion === true);
+      const leadingNames = searchable.filter((a) => leading(a.searchName()) || a.searchAliases().some(leading)).sort(sortPresets("searchName", "searchAliases"));
+      const leadingSuggestions = suggestions.filter((a) => leadingStrict(a.searchName())).sort(sortPresets("searchName"));
+      const leadingNamesStripped = searchable.filter((a) => leading(a.searchNameStripped()) || a.searchAliasesStripped().some(leading)).sort(sortPresets("searchNameStripped", "searchAliasesStripped"));
+      const leadingSuggestionsStripped = suggestions.filter((a) => leadingStrict(a.searchNameStripped())).sort(sortPresets("searchNameStripped"));
+      const leadingTerms = searchable.filter((a) => (a.terms() || []).some(leading));
+      const leadingSuggestionTerms = suggestions.filter((a) => (a.terms() || []).some(leading));
+      const leadingTagValues = searchable.filter((a) => Object.values(a.tags || {}).filter((val) => val !== "*").some(leading));
+      const similarName = searchable.map((a) => ({ preset: a, dist: utilEditDistance(value, a.searchName()) })).filter((a) => a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 3).sort((a, b) => a.dist - b.dist).map((a) => a.preset);
+      const similarSuggestions = suggestions.map((a) => ({ preset: a, dist: utilEditDistance(value, a.searchName()) })).filter((a) => a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 1).sort((a, b) => a.dist - b.dist).map((a) => a.preset);
+      const similarTerms = searchable.filter((a) => {
+        return (a.terms() || []).some((b) => {
+          return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
+        });
+      });
+      let leadingTagKeyValues = [];
+      if (value.includes("=")) {
+        leadingTagKeyValues = searchable.filter((a) => a.tags && Object.keys(a.tags).some((key) => key + "=" + a.tags[key] === value)).concat(searchable.filter((a) => a.tags && Object.keys(a.tags).some((key) => leading(key + "=" + a.tags[key]))));
+      }
+      let results = leadingNames.concat(
+        leadingSuggestions,
+        leadingNamesStripped,
+        leadingSuggestionsStripped,
+        leadingTerms,
+        leadingSuggestionTerms,
+        leadingTagValues,
+        similarName,
+        similarSuggestions,
+        similarTerms,
+        leadingTagKeyValues
+      ).slice(0, MAXRESULTS - 1);
+      if (geometry) {
+        if (typeof geometry === "string") {
+          results.push(_this.fallback(geometry));
+        } else {
+          geometry.forEach((geom) => results.push(_this.fallback(geom)));
+        }
+      }
+      return presetCollection(utilArrayUniq(results));
     };
-    _this.getAddable = () => {
-      if (!_addablePresetIDs)
-        return [];
-      return _addablePresetIDs.map((id2) => {
-        const preset = _this.item(id2);
-        if (preset)
-          return RibbonItem(preset, "addable");
-        return null;
-      }).filter(Boolean);
+    return _this;
+  }
+
+  // modules/presets/category.js
+  function presetCategory(categoryID, category, allPresets) {
+    let _this = Object.assign({}, category);
+    let _searchName;
+    let _searchNameStripped;
+    _this.id = categoryID;
+    _this.members = presetCollection(
+      (category.members || []).map((presetID) => allPresets[presetID]).filter(Boolean)
+    );
+    _this.geometry = _this.members.collection.reduce((acc, preset) => {
+      for (let i2 in preset.geometry) {
+        const geometry = preset.geometry[i2];
+        if (acc.indexOf(geometry) === -1) {
+          acc.push(geometry);
+        }
+      }
+      return acc;
+    }, []);
+    _this.matchGeometry = (geom) => _this.geometry.indexOf(geom) >= 0;
+    _this.matchAllGeometry = (geometries) => _this.members.collection.some((preset) => preset.matchAllGeometry(geometries));
+    _this.matchScore = () => -1;
+    _this.name = () => _t(`_tagging.presets.categories.${categoryID}.name`, { "default": categoryID });
+    _this.nameLabel = () => _t.append(`_tagging.presets.categories.${categoryID}.name`, { "default": categoryID });
+    _this.terms = () => [];
+    _this.searchName = () => {
+      if (!_searchName) {
+        _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
+      }
+      return _searchName;
     };
-    function setRecents(items) {
-      _recents = items;
-      const minifiedItems = items.map((d) => d.minified());
-      corePreferences("preset_recents", JSON.stringify(minifiedItems));
-      dispatch10.call("recentsChange");
-    }
-    _this.getRecents = () => {
-      if (!_recents) {
-        _recents = (JSON.parse(corePreferences("preset_recents")) || []).reduce((acc, d) => {
-          let item = ribbonItemForMinified(d, "recent");
-          if (item && item.preset.addable())
-            acc.push(item);
-          return acc;
-        }, []);
+    _this.searchNameStripped = () => {
+      if (!_searchNameStripped) {
+        _searchNameStripped = _this.searchName();
+        if (_searchNameStripped.normalize)
+          _searchNameStripped = _searchNameStripped.normalize("NFD");
+        _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, "");
       }
-      return _recents;
+      return _searchNameStripped;
     };
-    _this.addRecent = (preset, besidePreset, after) => {
-      const recents = _this.getRecents();
-      const beforeItem = _this.recentMatching(besidePreset);
-      let toIndex = recents.indexOf(beforeItem);
-      if (after)
-        toIndex += 1;
-      const newItem = RibbonItem(preset, "recent");
-      recents.splice(toIndex, 0, newItem);
-      setRecents(recents);
+    _this.searchAliases = () => [];
+    _this.searchAliasesStripped = () => [];
+    return _this;
+  }
+
+  // modules/presets/field.js
+  function presetField(fieldID, field, allFields) {
+    allFields = allFields || {};
+    let _this = Object.assign({}, field);
+    _this.id = fieldID;
+    _this.safeid = utilSafeClassName(fieldID);
+    _this.matchGeometry = (geom) => !_this.geometry || _this.geometry.indexOf(geom) !== -1;
+    _this.matchAllGeometry = (geometries) => {
+      return !_this.geometry || geometries.every((geom) => _this.geometry.indexOf(geom) !== -1);
     };
-    _this.removeRecent = (preset) => {
-      const item = _this.recentMatching(preset);
-      if (item) {
-        let items = _this.getRecents();
-        items.splice(items.indexOf(item), 1);
-        setRecents(items);
+    _this.t = (scope, options2) => _t(`_tagging.presets.fields.${fieldID}.${scope}`, options2);
+    _this.t.html = (scope, options2) => _t.html(`_tagging.presets.fields.${fieldID}.${scope}`, options2);
+    _this.t.append = (scope, options2) => _t.append(`_tagging.presets.fields.${fieldID}.${scope}`, options2);
+    _this.hasTextForStringId = (scope) => _mainLocalizer.hasTextForStringId(`_tagging.presets.fields.${fieldID}.${scope}`);
+    _this.resolveReference = (which) => {
+      const referenceRegex = /^\{(.*)\}$/;
+      const match = (field[which] || "").match(referenceRegex);
+      if (match) {
+        const field2 = allFields[match[1]];
+        if (field2) {
+          return field2;
+        }
+        console.error(`Unable to resolve referenced field: ${match[1]}`);
       }
+      return _this;
     };
-    _this.recentMatching = (preset) => {
-      const items = _this.getRecents();
-      for (let i2 in items) {
-        if (items[i2].matches(preset)) {
-          return items[i2];
+    _this.title = () => _this.overrideLabel || _this.resolveReference("label").t("label", { "default": fieldID });
+    _this.label = () => _this.overrideLabel ? (selection2) => selection2.text(_this.overrideLabel) : _this.resolveReference("label").t.append("label", { "default": fieldID });
+    _this.placeholder = () => _this.resolveReference("placeholder").t("placeholder", { "default": "" });
+    _this.originalTerms = (_this.terms || []).join();
+    _this.terms = () => _this.resolveReference("label").t("terms", { "default": _this.originalTerms }).toLowerCase().trim().split(/\s*,+\s*/);
+    _this.increment = _this.type === "number" ? _this.increment || 1 : void 0;
+    return _this;
+  }
+
+  // modules/presets/preset.js
+  var import_lodash = __toESM(require_lodash());
+  function presetPreset(presetID, preset, addable, allFields, allPresets) {
+    allFields = allFields || {};
+    allPresets = allPresets || {};
+    let _this = Object.assign({}, preset);
+    let _addable = addable || false;
+    let _searchName;
+    let _searchNameStripped;
+    let _searchAliases;
+    let _searchAliasesStripped;
+    const referenceRegex = /^\{(.*)\}$/;
+    _this.id = presetID;
+    _this.safeid = utilSafeClassName(presetID);
+    _this.originalTerms = (_this.terms || []).join();
+    _this.originalName = _this.name || "";
+    _this.originalAliases = (_this.aliases || []).join("\n");
+    _this.originalScore = _this.matchScore || 1;
+    _this.originalReference = _this.reference || {};
+    _this.originalFields = _this.fields || [];
+    _this.originalMoreFields = _this.moreFields || [];
+    _this.fields = (loc) => resolveFields("fields", loc);
+    _this.moreFields = (loc) => resolveFields("moreFields", loc);
+    _this.tags = _this.tags || {};
+    _this.addTags = _this.addTags || _this.tags;
+    _this.removeTags = _this.removeTags || _this.addTags;
+    _this.geometry = _this.geometry || [];
+    _this.matchGeometry = (geom) => _this.geometry.indexOf(geom) >= 0;
+    _this.matchAllGeometry = (geoms) => geoms.every(_this.matchGeometry);
+    _this.matchScore = (entityTags) => {
+      const tags = _this.tags;
+      let seen = {};
+      let score = 0;
+      for (let k in tags) {
+        seen[k] = true;
+        if (entityTags[k] === tags[k]) {
+          score += _this.originalScore;
+        } else if (tags[k] === "*" && k in entityTags) {
+          score += _this.originalScore / 2;
+        } else {
+          return -1;
         }
       }
-      return null;
+      const addTags = _this.addTags;
+      for (let k in addTags) {
+        if (!seen[k] && entityTags[k] === addTags[k]) {
+          score += _this.originalScore;
+        }
+      }
+      if (_this.searchable === false) {
+        score *= 0.999;
+      }
+      return score;
     };
-    _this.moveItem = (items, fromIndex, toIndex) => {
-      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;
+    _this.t = (scope, options2) => {
+      const textID = `_tagging.presets.presets.${presetID}.${scope}`;
+      return _t(textID, options2);
     };
-    _this.moveRecent = (item, beforeItem) => {
-      const recents = _this.getRecents();
-      const fromIndex = recents.indexOf(item);
-      const toIndex = recents.indexOf(beforeItem);
-      const items = _this.moveItem(recents, fromIndex, toIndex);
-      if (items)
-        setRecents(items);
+    _this.t.append = (scope, options2) => {
+      const textID = `_tagging.presets.presets.${presetID}.${scope}`;
+      return _t.append(textID, options2);
     };
-    _this.setMostRecent = (preset) => {
-      if (preset.searchable === false)
-        return;
-      let items = _this.getRecents();
-      let item = _this.recentMatching(preset);
-      if (item) {
-        items.splice(items.indexOf(item), 1);
-      } else {
-        item = RibbonItem(preset, "recent");
-      }
-      while (items.length >= MAXRECENTS) {
-        items.pop();
+    function resolveReference(which) {
+      const match = (_this[which] || "").match(referenceRegex);
+      if (match) {
+        const preset2 = allPresets[match[1]];
+        if (preset2) {
+          return preset2;
+        }
+        console.error(`Unable to resolve referenced preset: ${match[1]}`);
       }
-      items.unshift(item);
-      setRecents(items);
-    };
-    function setFavorites(items) {
-      _favorites = items;
-      const minifiedItems = items.map((d) => d.minified());
-      corePreferences("preset_favorites", JSON.stringify(minifiedItems));
-      dispatch10.call("favoritePreset");
+      return _this;
     }
-    _this.addFavorite = (preset, besidePreset, after) => {
-      const favorites = _this.getFavorites();
-      const beforeItem = _this.favoriteMatching(besidePreset);
-      let toIndex = favorites.indexOf(beforeItem);
-      if (after)
-        toIndex += 1;
-      const newItem = RibbonItem(preset, "favorite");
-      favorites.splice(toIndex, 0, newItem);
-      setFavorites(favorites);
+    _this.name = () => {
+      return resolveReference("originalName").t("name", { "default": _this.originalName || presetID });
     };
-    _this.toggleFavorite = (preset) => {
-      const favs = _this.getFavorites();
-      const favorite = _this.favoriteMatching(preset);
-      if (favorite) {
-        favs.splice(favs.indexOf(favorite), 1);
-      } else {
-        if (favs.length === 10) {
-          favs.pop();
-        }
-        favs.push(RibbonItem(preset, "favorite"));
+    _this.nameLabel = () => {
+      return resolveReference("originalName").t.append("name", { "default": _this.originalName || presetID });
+    };
+    _this.subtitle = () => {
+      if (_this.suggestion) {
+        let path = presetID.split("/");
+        path.pop();
+        return _t("_tagging.presets.presets." + path.join("/") + ".name");
       }
-      setFavorites(favs);
+      return null;
     };
-    _this.removeFavorite = (preset) => {
-      const item = _this.favoriteMatching(preset);
-      if (item) {
-        const items = _this.getFavorites();
-        items.splice(items.indexOf(item), 1);
-        setFavorites(items);
+    _this.subtitleLabel = () => {
+      if (_this.suggestion) {
+        let path = presetID.split("/");
+        path.pop();
+        return _t.append("_tagging.presets.presets." + path.join("/") + ".name");
       }
+      return null;
     };
-    _this.getFavorites = () => {
-      if (!_favorites) {
-        let rawFavorites = JSON.parse(corePreferences("preset_favorites"));
-        if (!rawFavorites) {
-          rawFavorites = [];
-          corePreferences("preset_favorites", JSON.stringify(rawFavorites));
-        }
-        _favorites = rawFavorites.reduce((output, d) => {
-          const item = ribbonItemForMinified(d, "favorite");
-          if (item && item.preset.addable())
-            output.push(item);
-          return output;
-        }, []);
+    _this.aliases = () => {
+      return resolveReference("originalName").t("aliases", { "default": _this.originalAliases }).trim().split(/\s*[\r\n]+\s*/);
+    };
+    _this.terms = () => {
+      return resolveReference("originalName").t("terms", { "default": _this.originalTerms }).toLowerCase().trim().split(/\s*,+\s*/);
+    };
+    _this.searchName = () => {
+      if (!_searchName) {
+        _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
       }
-      return _favorites;
+      return _searchName;
     };
-    _this.favoriteMatching = (preset) => {
-      const favs = _this.getFavorites();
-      for (let index in favs) {
-        if (favs[index].matches(preset)) {
-          return favs[index];
-        }
+    _this.searchNameStripped = () => {
+      if (!_searchNameStripped) {
+        _searchNameStripped = stripDiacritics(_this.searchName());
       }
-      return null;
+      return _searchNameStripped;
     };
-    return utilRebind(_this, dispatch10, "on");
-  }
-
-  // modules/util/util.js
-  function utilTagText(entity) {
-    var obj = entity && entity.tags || {};
-    return Object.keys(obj).map(function(k) {
-      return k + "=" + obj[k];
-    }).join(", ");
-  }
-  function utilTotalExtent(array2, graph) {
-    var extent = geoExtent();
-    var val, entity;
-    for (var i2 = 0; i2 < array2.length; i2++) {
-      val = array2[i2];
-      entity = typeof val === "string" ? graph.hasEntity(val) : val;
-      if (entity) {
-        extent._extend(entity.extent(graph));
-      }
-    }
-    return extent;
-  }
-  function utilTagDiff(oldTags, newTags) {
-    var tagDiff = [];
-    var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
-    keys.forEach(function(k) {
-      var oldVal = oldTags[k];
-      var newVal = newTags[k];
-      if ((oldVal || oldVal === "") && (newVal === void 0 || newVal !== oldVal)) {
-        tagDiff.push({
-          type: "-",
-          key: k,
-          oldVal,
-          newVal,
-          display: "- " + k + "=" + oldVal
-        });
+    _this.searchAliases = () => {
+      if (!_searchAliases) {
+        _searchAliases = _this.aliases().map((alias) => alias.toLowerCase());
       }
-      if ((newVal || newVal === "") && (oldVal === void 0 || newVal !== oldVal)) {
-        tagDiff.push({
-          type: "+",
-          key: k,
-          oldVal,
-          newVal,
-          display: "+ " + k + "=" + newVal
-        });
+      return _searchAliases;
+    };
+    _this.searchAliasesStripped = () => {
+      if (!_searchAliasesStripped) {
+        _searchAliasesStripped = _this.searchAliases();
+        _searchAliasesStripped = _searchAliasesStripped.map(stripDiacritics);
       }
-    });
-    return tagDiff;
-  }
-  function utilEntitySelector(ids) {
-    return ids.length ? "." + ids.join(",.") : "nothing";
-  }
-  function utilEntityOrMemberSelector(ids, graph) {
-    var seen = new Set(ids);
-    ids.forEach(collectShallowDescendants);
-    return utilEntitySelector(Array.from(seen));
-    function collectShallowDescendants(id2) {
-      var entity = graph.hasEntity(id2);
-      if (!entity || entity.type !== "relation")
-        return;
-      entity.members.map(function(member) {
-        return member.id;
-      }).forEach(function(id3) {
-        seen.add(id3);
-      });
-    }
-  }
-  function utilEntityOrDeepMemberSelector(ids, graph) {
-    return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
-  }
-  function utilEntityAndDeepMemberIDs(ids, graph) {
-    var seen = /* @__PURE__ */ new Set();
-    ids.forEach(collectDeepDescendants);
-    return Array.from(seen);
-    function collectDeepDescendants(id2) {
-      if (seen.has(id2))
-        return;
-      seen.add(id2);
-      var entity = graph.hasEntity(id2);
-      if (!entity || entity.type !== "relation")
-        return;
-      entity.members.map(function(member) {
-        return member.id;
-      }).forEach(collectDeepDescendants);
-    }
-  }
-  function utilDeepMemberSelector(ids, graph, skipMultipolgonMembers) {
-    var idsSet = new Set(ids);
-    var seen = /* @__PURE__ */ new Set();
-    var returners = /* @__PURE__ */ new Set();
-    ids.forEach(collectDeepDescendants);
-    return utilEntitySelector(Array.from(returners));
-    function collectDeepDescendants(id2) {
-      if (seen.has(id2))
-        return;
-      seen.add(id2);
-      if (!idsSet.has(id2)) {
-        returners.add(id2);
+      return _searchAliasesStripped;
+    };
+    _this.isFallback = () => {
+      const tagCount = Object.keys(_this.tags).length;
+      return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty("area");
+    };
+    _this.addable = function(val) {
+      if (!arguments.length)
+        return _addable;
+      _addable = val;
+      return _this;
+    };
+    _this.reference = () => {
+      const qid = _this.tags.wikidata || _this.tags["flag:wikidata"] || _this.tags["brand:wikidata"] || _this.tags["network:wikidata"] || _this.tags["operator:wikidata"];
+      if (qid) {
+        return { qid };
       }
-      var entity = graph.hasEntity(id2);
-      if (!entity || entity.type !== "relation")
-        return;
-      if (skipMultipolgonMembers && entity.isMultipolygon())
-        return;
-      entity.members.map(function(member) {
-        return member.id;
-      }).forEach(collectDeepDescendants);
-    }
-  }
-  function utilHighlightEntities(ids, highlighted, context) {
-    context.surface().selectAll(utilEntityOrDeepMemberSelector(ids, context.graph())).classed("highlighted", highlighted);
-  }
-  function utilGetAllNodes(ids, graph) {
-    var seen = /* @__PURE__ */ new Set();
-    var nodes = /* @__PURE__ */ new Set();
-    ids.forEach(collectNodes);
-    return Array.from(nodes);
-    function collectNodes(id2) {
-      if (seen.has(id2))
-        return;
-      seen.add(id2);
-      var entity = graph.hasEntity(id2);
-      if (!entity)
-        return;
-      if (entity.type === "node") {
-        nodes.add(entity);
-      } else if (entity.type === "way") {
-        entity.nodes.forEach(collectNodes);
+      let key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, "name"))[0];
+      let value = _this.originalReference.value || _this.tags[key];
+      if (value === "*") {
+        return { key };
       } else {
-        entity.members.map(function(member) {
-          return member.id;
-        }).forEach(collectNodes);
+        return { key, value };
       }
-    }
-  }
-  function utilDisplayName(entity) {
-    var localizedNameKey = "name:" + _mainLocalizer.languageCode().toLowerCase();
-    var name = entity.tags[localizedNameKey] || entity.tags.name || "";
-    if (name)
-      return name;
-    var tags = {
-      direction: entity.tags.direction,
-      from: entity.tags.from,
-      network: entity.tags.cycle_network || entity.tags.network,
-      ref: entity.tags.ref,
-      to: entity.tags.to,
-      via: entity.tags.via
     };
-    var keyComponents = [];
-    if (tags.network) {
-      keyComponents.push("network");
-    }
-    if (tags.ref) {
-      keyComponents.push("ref");
-    }
-    if (entity.tags.route) {
-      if (tags.direction) {
-        keyComponents.push("direction");
-      } else if (tags.from && tags.to) {
-        keyComponents.push("from");
-        keyComponents.push("to");
-        if (tags.via) {
-          keyComponents.push("via");
-        }
+    _this.unsetTags = (tags, geometry, ignoringKeys, skipFieldDefaults, loc) => {
+      let removeTags = ignoringKeys ? utilObjectOmit(_this.removeTags, ignoringKeys) : _this.removeTags;
+      tags = utilObjectOmit(tags, Object.keys(removeTags));
+      if (geometry && !skipFieldDefaults) {
+        _this.fields(loc).forEach((field) => {
+          if (field.matchGeometry(geometry) && field.key && field.default === tags[field.key] && (!ignoringKeys || ignoringKeys.indexOf(field.key) === -1)) {
+            delete tags[field.key];
+          }
+        });
       }
-    }
-    if (keyComponents.length) {
-      name = _t("inspector.display_name." + keyComponents.join("_"), tags);
-    }
-    return name;
-  }
-  function utilDisplayNameForPath(entity) {
-    var name = utilDisplayName(entity);
-    var isFirefox = utilDetect().browser.toLowerCase().indexOf("firefox") > -1;
-    var isNewChromium = Number(utilDetect().version.split(".")[0]) >= 96;
-    if (!isFirefox && !isNewChromium && name && rtlRegex.test(name)) {
-      name = fixRTLTextForSvg(name);
-    }
-    return name;
-  }
-  function utilDisplayType(id2) {
-    return {
-      n: _t("inspector.node"),
-      w: _t("inspector.way"),
-      r: _t("inspector.relation")
-    }[id2.charAt(0)];
-  }
-  function utilDisplayLabel(entity, graphOrGeometry, verbose) {
-    var result;
-    var displayName = utilDisplayName(entity);
-    var preset = typeof graphOrGeometry === "string" ? _mainPresetIndex.matchTags(entity.tags, graphOrGeometry) : _mainPresetIndex.match(entity, graphOrGeometry);
-    var presetName = preset && (preset.suggestion ? preset.subtitle() : preset.name());
-    if (verbose) {
-      result = [presetName, displayName].filter(Boolean).join(" ");
-    } else {
-      result = displayName || presetName;
-    }
-    return result || utilDisplayType(entity.id);
-  }
-  function utilEntityRoot(entityType) {
-    return {
-      node: "n",
-      way: "w",
-      relation: "r"
-    }[entityType];
-  }
-  function utilCombinedTags(entityIDs, graph) {
-    var tags = {};
-    var tagCounts = {};
-    var allKeys = /* @__PURE__ */ new Set();
-    var entities = entityIDs.map(function(entityID) {
-      return graph.hasEntity(entityID);
-    }).filter(Boolean);
-    entities.forEach(function(entity) {
-      var keys = Object.keys(entity.tags).filter(Boolean);
-      keys.forEach(function(key2) {
-        allKeys.add(key2);
-      });
-    });
-    entities.forEach(function(entity) {
-      allKeys.forEach(function(key2) {
-        var value = entity.tags[key2];
-        if (!tags.hasOwnProperty(key2)) {
-          tags[key2] = value;
+      delete tags.area;
+      return tags;
+    };
+    _this.setTags = (tags, geometry, skipFieldDefaults, loc) => {
+      const addTags = _this.addTags;
+      tags = Object.assign({}, tags);
+      for (let k in addTags) {
+        if (addTags[k] === "*") {
+          if (_this.tags[k] || !tags[k]) {
+            tags[k] = "yes";
+          }
         } else {
-          if (!Array.isArray(tags[key2])) {
-            if (tags[key2] !== value) {
-              tags[key2] = [tags[key2], value];
-            }
-          } else {
-            if (tags[key2].indexOf(value) === -1) {
-              tags[key2].push(value);
+          tags[k] = addTags[k];
+        }
+      }
+      if (!addTags.hasOwnProperty("area")) {
+        delete tags.area;
+        if (geometry === "area") {
+          let needsAreaTag = true;
+          for (let k in addTags) {
+            if (_this.geometry.indexOf("line") === -1 && k in osmAreaKeys || k in osmAreaKeysExceptions && addTags[k] in osmAreaKeysExceptions[k]) {
+              needsAreaTag = false;
+              break;
             }
           }
+          if (needsAreaTag) {
+            tags.area = "yes";
+          }
         }
-        var tagHash = key2 + "=" + value;
-        if (!tagCounts[tagHash])
-          tagCounts[tagHash] = 0;
-        tagCounts[tagHash] += 1;
-      });
-    });
-    for (var key in tags) {
-      if (!Array.isArray(tags[key]))
-        continue;
-      tags[key] = tags[key].sort(function(val12, val2) {
-        var key2 = key2;
-        var count2 = tagCounts[key2 + "=" + val2];
-        var count1 = tagCounts[key2 + "=" + val12];
-        if (count2 !== count1) {
-          return count2 - count1;
-        }
-        if (val2 && val12) {
-          return val12.localeCompare(val2);
-        }
-        return val12 ? 1 : -1;
-      });
-    }
-    return tags;
-  }
-  function utilStringQs(str2) {
-    var i2 = 0;
-    while (i2 < str2.length && (str2[i2] === "?" || str2[i2] === "#"))
-      i2++;
-    str2 = str2.slice(i2);
-    return str2.split("&").reduce(function(obj, pair2) {
-      var parts = pair2.split("=");
-      if (parts.length === 2) {
-        obj[parts[0]] = null === parts[1] ? "" : decodeURIComponent(parts[1]);
       }
-      return obj;
-    }, {});
-  }
-  function utilQsString(obj, noencode) {
-    function softEncode(s) {
-      return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
-    }
-    return Object.keys(obj).sort().map(function(key) {
-      return encodeURIComponent(key) + "=" + (noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
-    }).join("&");
-  }
-  function utilPrefixDOMProperty(property) {
-    var prefixes2 = ["webkit", "ms", "moz", "o"];
-    var i2 = -1;
-    var n2 = prefixes2.length;
-    var s = document.body;
-    if (property in s)
-      return property;
-    property = property.slice(0, 1).toUpperCase() + property.slice(1);
-    while (++i2 < n2) {
-      if (prefixes2[i2] + property in s) {
-        return prefixes2[i2] + property;
+      if (geometry && !skipFieldDefaults) {
+        _this.fields(loc).forEach((field) => {
+          if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
+            tags[field.key] = field.default;
+          }
+        });
       }
-    }
-    return false;
-  }
-  function utilPrefixCSSProperty(property) {
-    var prefixes2 = ["webkit", "ms", "Moz", "O"];
-    var i2 = -1;
-    var n2 = prefixes2.length;
-    var s = document.body.style;
-    if (property.toLowerCase() in s) {
-      return property.toLowerCase();
-    }
-    while (++i2 < n2) {
-      if (prefixes2[i2] + property in s) {
-        return "-" + prefixes2[i2].toLowerCase() + property.replace(/([A-Z])/g, "-$1").toLowerCase();
+      return tags;
+    };
+    function resolveFields(which, loc) {
+      const fieldIDs = which === "fields" ? _this.originalFields : _this.originalMoreFields;
+      let resolved = [];
+      fieldIDs.forEach((fieldID) => {
+        const match = fieldID.match(referenceRegex);
+        if (match !== null) {
+          resolved = resolved.concat(inheritFields(allPresets[match[1]], which));
+        } else if (allFields[fieldID]) {
+          resolved.push(allFields[fieldID]);
+        } else {
+          console.log(`Cannot resolve "${fieldID}" found in ${_this.id}.${which}`);
+        }
+      });
+      if (!resolved.length) {
+        const endIndex = _this.id.lastIndexOf("/");
+        const parentID = endIndex && _this.id.substring(0, endIndex);
+        if (parentID) {
+          let parent = allPresets[parentID];
+          if (loc) {
+            const validHere = _sharedLocationManager.locationSetsAt(loc);
+            if (parent?.locationSetID && !validHere[parent.locationSetID]) {
+              const candidateIDs = Object.keys(allPresets).filter((k) => k.startsWith(parentID));
+              parent = allPresets[candidateIDs.find((candidateID) => {
+                const candidate = allPresets[candidateID];
+                return validHere[candidate.locationSetID] && (0, import_lodash.isEqual)(candidate.tags, parent.tags);
+              })];
+            }
+          }
+          resolved = inheritFields(parent, which);
+        }
       }
-    }
-    return false;
-  }
-  var transformProperty;
-  function utilSetTransform(el, x, y, scale) {
-    var prop = transformProperty = transformProperty || utilPrefixCSSProperty("Transform");
-    var translate = utilDetect().opera ? "translate(" + x + "px," + y + "px)" : "translate3d(" + x + "px," + y + "px,0)";
-    return el.style(prop, translate + (scale ? " scale(" + scale + ")" : ""));
-  }
-  function utilEditDistance(a, b) {
-    a = (0, import_diacritics.remove)(a.toLowerCase());
-    b = (0, import_diacritics.remove)(b.toLowerCase());
-    if (a.length === 0)
-      return b.length;
-    if (b.length === 0)
-      return a.length;
-    var matrix = [];
-    var i2, j2;
-    for (i2 = 0; i2 <= b.length; i2++) {
-      matrix[i2] = [i2];
-    }
-    for (j2 = 0; j2 <= a.length; j2++) {
-      matrix[0][j2] = j2;
-    }
-    for (i2 = 1; i2 <= b.length; i2++) {
-      for (j2 = 1; j2 <= a.length; j2++) {
-        if (b.charAt(i2 - 1) === a.charAt(j2 - 1)) {
-          matrix[i2][j2] = matrix[i2 - 1][j2 - 1];
+      return utilArrayUniq(resolved);
+      function inheritFields(parent, which2) {
+        if (!parent)
+          return [];
+        if (which2 === "fields") {
+          return parent.fields().filter(shouldInherit);
+        } else if (which2 === "moreFields") {
+          return parent.moreFields();
         } else {
-          matrix[i2][j2] = Math.min(
-            matrix[i2 - 1][j2 - 1] + 1,
-            Math.min(
-              matrix[i2][j2 - 1] + 1,
-              matrix[i2 - 1][j2] + 1
-            )
-          );
+          return [];
         }
       }
+      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;
+        return true;
+      }
     }
-    return matrix[b.length][a.length];
+    function stripDiacritics(s) {
+      if (s.normalize)
+        s = s.normalize("NFD");
+      s = s.replace(/[\u0300-\u036f]/g, "");
+      return s;
+    }
+    return _this;
   }
-  function utilFastMouse(container) {
-    var rect = container.getBoundingClientRect();
-    var rectLeft = rect.left;
-    var rectTop = rect.top;
-    var clientLeft = +container.clientLeft;
-    var clientTop = +container.clientTop;
-    return function(e) {
-      return [
-        e.clientX - rectLeft - clientLeft,
-        e.clientY - rectTop - clientTop
-      ];
+
+  // modules/presets/index.js
+  var _mainPresetIndex = presetIndex();
+  function presetIndex() {
+    const dispatch10 = dispatch_default("favoritePreset", "recentsChange");
+    const MAXRECENTS = 30;
+    const POINT = presetPreset("point", { name: "Point", tags: {}, geometry: ["point", "vertex"], matchScore: 0.1 });
+    const LINE = presetPreset("line", { name: "Line", tags: {}, geometry: ["line"], matchScore: 0.1 });
+    const AREA = presetPreset("area", { name: "Area", tags: { area: "yes" }, geometry: ["area"], matchScore: 0.1 });
+    const RELATION = presetPreset("relation", { name: "Relation", tags: {}, geometry: ["relation"], matchScore: 0.1 });
+    let _this = presetCollection([POINT, LINE, AREA, RELATION]);
+    let _presets = { point: POINT, line: LINE, area: AREA, relation: RELATION };
+    let _defaults = {
+      point: presetCollection([POINT]),
+      vertex: presetCollection([POINT]),
+      line: presetCollection([LINE]),
+      area: presetCollection([AREA]),
+      relation: presetCollection([RELATION])
     };
-  }
-  function utilAsyncMap(inputs, func, callback) {
-    var remaining = inputs.length;
-    var results = [];
-    var errors = [];
-    inputs.forEach(function(d, i2) {
-      func(d, function done(err, data) {
-        errors[i2] = err;
-        results[i2] = data;
-        remaining--;
-        if (!remaining)
-          callback(errors, results);
+    let _fields = {};
+    let _categories = {};
+    let _universal = [];
+    let _addablePresetIDs = null;
+    let _recents;
+    let _favorites;
+    let _geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
+    let _loadPromise;
+    _this.ensureLoaded = () => {
+      if (_loadPromise)
+        return _loadPromise;
+      return _loadPromise = Promise.all([
+        _mainFileFetcher.get("preset_categories"),
+        _mainFileFetcher.get("preset_defaults"),
+        _mainFileFetcher.get("preset_presets"),
+        _mainFileFetcher.get("preset_fields")
+      ]).then((vals) => {
+        _this.merge({
+          categories: vals[0],
+          defaults: vals[1],
+          presets: vals[2],
+          fields: vals[3]
+        });
+        osmSetAreaKeys(_this.areaKeys());
+        osmSetLineTags(_this.lineTags());
+        osmSetPointTags(_this.pointTags());
+        osmSetVertexTags(_this.vertexTags());
       });
-    });
-  }
-  function utilWrap(index, length) {
-    if (index < 0) {
-      index += Math.ceil(-index / length) * length;
-    }
-    return index % length;
-  }
-  function utilFunctor(value) {
-    if (typeof value === "function")
-      return value;
-    return function() {
-      return value;
     };
-  }
-  function utilNoAuto(selection2) {
-    var isText = selection2.size() && selection2.node().tagName.toLowerCase() === "textarea";
-    return selection2.attr("autocomplete", "new-password").attr("autocorrect", "off").attr("autocapitalize", "off").attr("spellcheck", isText ? "true" : "false");
-  }
-  function utilHashcode(str2) {
-    var hash = 0;
-    if (str2.length === 0) {
-      return hash;
-    }
-    for (var i2 = 0; i2 < str2.length; i2++) {
-      var char = str2.charCodeAt(i2);
-      hash = (hash << 5) - hash + char;
-      hash = hash & hash;
-    }
-    return hash;
-  }
-  function utilSafeClassName(str2) {
-    return str2.toLowerCase().replace(/[^a-z0-9]+/g, "_");
-  }
-  function utilUniqueDomId(val) {
-    return "ideditor-" + utilSafeClassName(val.toString()) + "-" + new Date().getTime().toString();
-  }
-  function utilUnicodeCharsCount(str2) {
-    return Array.from(str2).length;
-  }
-  function utilUnicodeCharsTruncated(str2, limit) {
-    return Array.from(str2).slice(0, limit).join("");
-  }
-  function toNumericID(id2) {
-    var match = id2.match(/^[cnwr](-?\d+)$/);
-    if (match) {
-      return parseInt(match[1], 10);
-    }
-    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);
-    return Math.sign(left - right);
-  }
-  function utilCompareIDs(left, right) {
-    return compareNumericIDs(toNumericID(left), toNumericID(right));
-  }
-  function utilOldestID(ids) {
-    if (ids.length === 0) {
-      return void 0;
-    }
-    var oldestIDIndex = 0;
-    var oldestID = toNumericID(ids[0]);
-    for (var i2 = 1; i2 < ids.length; i2++) {
-      var num = toNumericID(ids[i2]);
-      if (compareNumericIDs(oldestID, num) === 1) {
-        oldestIDIndex = i2;
-        oldestID = num;
+    _this.merge = (d) => {
+      let newLocationSets = [];
+      if (d.fields) {
+        Object.keys(d.fields).forEach((fieldID) => {
+          let f2 = d.fields[fieldID];
+          if (f2) {
+            f2 = presetField(fieldID, f2, _fields);
+            if (f2.locationSet)
+              newLocationSets.push(f2);
+            _fields[fieldID] = f2;
+          } else {
+            delete _fields[fieldID];
+          }
+        });
       }
-    }
-    return ids[oldestIDIndex];
-  }
-
-  // modules/osm/entity.js
-  function osmEntity(attrs) {
-    if (this instanceof osmEntity)
-      return;
-    if (attrs && attrs.type) {
-      return osmEntity[attrs.type].apply(this, arguments);
-    } else if (attrs && attrs.id) {
-      return osmEntity[osmEntity.id.type(attrs.id)].apply(this, arguments);
-    }
-    return new osmEntity().initialize(arguments);
-  }
-  osmEntity.id = function(type3) {
-    return osmEntity.id.fromOSM(type3, osmEntity.id.next[type3]--);
-  };
-  osmEntity.id.next = {
-    changeset: -1,
-    node: -1,
-    way: -1,
-    relation: -1
-  };
-  osmEntity.id.fromOSM = function(type3, id2) {
-    return type3[0] + id2;
-  };
-  osmEntity.id.toOSM = function(id2) {
-    var match = id2.match(/^[cnwr](-?\d+)$/);
-    if (match) {
-      return match[1];
-    }
-    return "";
-  };
-  osmEntity.id.type = function(id2) {
-    return { "c": "changeset", "n": "node", "w": "way", "r": "relation" }[id2[0]];
-  };
-  osmEntity.key = function(entity) {
-    return entity.id + "v" + (entity.v || 0);
-  };
-  var _deprecatedTagValuesByKey;
-  osmEntity.deprecatedTagValuesByKey = function(dataDeprecated) {
-    if (!_deprecatedTagValuesByKey) {
-      _deprecatedTagValuesByKey = {};
-      dataDeprecated.forEach(function(d) {
-        var oldKeys = Object.keys(d.old);
-        if (oldKeys.length === 1) {
-          var oldKey = oldKeys[0];
-          var oldValue = d.old[oldKey];
-          if (oldValue !== "*") {
-            if (!_deprecatedTagValuesByKey[oldKey]) {
-              _deprecatedTagValuesByKey[oldKey] = [oldValue];
-            } else {
-              _deprecatedTagValuesByKey[oldKey].push(oldValue);
+      if (d.presets) {
+        Object.keys(d.presets).forEach((presetID) => {
+          let p = d.presets[presetID];
+          if (p) {
+            const isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
+            p = presetPreset(presetID, p, isAddable, _fields, _presets);
+            if (p.locationSet)
+              newLocationSets.push(p);
+            _presets[presetID] = p;
+          } else {
+            const existing = _presets[presetID];
+            if (existing && !existing.isFallback()) {
+              delete _presets[presetID];
             }
           }
-        }
-      });
-    }
-    return _deprecatedTagValuesByKey;
-  };
-  osmEntity.prototype = {
-    tags: {},
-    initialize: function(sources) {
-      for (var i2 = 0; i2 < sources.length; ++i2) {
-        var source = sources[i2];
-        for (var prop in source) {
-          if (Object.prototype.hasOwnProperty.call(source, prop)) {
-            if (source[prop] === void 0) {
-              delete this[prop];
-            } else {
-              this[prop] = source[prop];
-            }
+        });
+      }
+      if (d.categories) {
+        Object.keys(d.categories).forEach((categoryID) => {
+          let c = d.categories[categoryID];
+          if (c) {
+            c = presetCategory(categoryID, c, _presets);
+            if (c.locationSet)
+              newLocationSets.push(c);
+            _categories[categoryID] = c;
+          } else {
+            delete _categories[categoryID];
           }
-        }
+        });
       }
-      if (!this.id && this.type) {
-        this.id = osmEntity.id(this.type);
+      _this.collection = Object.values(_presets).concat(Object.values(_categories));
+      if (d.defaults) {
+        Object.keys(d.defaults).forEach((geometry) => {
+          const def = d.defaults[geometry];
+          if (Array.isArray(def)) {
+            _defaults[geometry] = presetCollection(
+              def.map((id2) => _presets[id2] || _categories[id2]).filter(Boolean)
+            );
+          } else {
+            delete _defaults[geometry];
+          }
+        });
       }
-      if (!this.hasOwnProperty("visible")) {
-        this.visible = true;
+      _universal = Object.values(_fields).filter((field) => field.universal);
+      _geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
+      _this.collection.forEach((preset) => {
+        (preset.geometry || []).forEach((geometry) => {
+          let g = _geometryIndex[geometry];
+          for (let key in preset.tags) {
+            g[key] = g[key] || {};
+            let value = preset.tags[key];
+            (g[key][value] = g[key][value] || []).push(preset);
+          }
+        });
+      });
+      if (d.featureCollection && Array.isArray(d.featureCollection.features)) {
+        _sharedLocationManager.mergeCustomGeoJSON(d.featureCollection);
       }
-      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 (newLocationSets.length) {
+        _sharedLocationManager.mergeLocationSets(newLocationSets);
       }
-      return this;
-    },
-    copy: function(resolver, copies) {
-      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;
-    },
-    osmId: function() {
-      return osmEntity.id.toOSM(this.id);
-    },
-    isNew: function() {
-      var osmId = osmEntity.id.toOSM(this.id);
-      return osmId.length === 0 || osmId[0] === "-";
-    },
-    update: function(attrs) {
-      return osmEntity(this, attrs, { v: 1 + (this.v || 0) });
-    },
-    mergeTags: function(tags) {
-      var merged = Object.assign({}, this.tags);
-      var changed = false;
-      for (var k in tags) {
-        var t1 = merged[k];
-        var t2 = tags[k];
-        if (!t1) {
-          changed = true;
-          merged[k] = t2;
-        } else if (t1 !== t2) {
-          changed = true;
-          merged[k] = utilUnicodeCharsTruncated(
-            utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(";"),
-            255
-          );
+      return _this;
+    };
+    _this.match = (entity, resolver) => {
+      return resolver.transient(entity, "presetMatch", () => {
+        let geometry = entity.geometry(resolver);
+        if (geometry === "vertex" && entity.isOnAddressLine(resolver)) {
+          geometry = "point";
         }
-      }
-      return changed ? this.update({ tags: merged }) : this;
-    },
-    intersects: function(extent, resolver) {
-      return this.extent(resolver).intersects(extent);
-    },
-    hasNonGeometryTags: function() {
-      return Object.keys(this.tags).some(function(k) {
-        return k !== "area";
+        const entityExtent = entity.extent(resolver);
+        return _this.matchTags(entity.tags, geometry, entityExtent.center());
       });
-    },
-    hasParentRelations: function(resolver) {
-      return resolver.parentRelations(this).length > 0;
-    },
-    hasInterestingTags: function() {
-      return Object.keys(this.tags).some(osmIsInterestingTag);
-    },
-    isHighwayIntersection: function() {
-      return false;
-    },
-    isDegenerate: function() {
-      return true;
-    },
-    deprecatedTags: function(dataDeprecated) {
-      var tags = this.tags;
-      if (Object.keys(tags).length === 0)
-        return [];
-      var deprecated = [];
-      dataDeprecated.forEach(function(d) {
-        var oldKeys = Object.keys(d.old);
-        if (d.replace) {
-          var hasExistingValues = Object.keys(d.replace).some(function(replaceKey) {
-            if (!tags[replaceKey] || d.old[replaceKey])
-              return false;
-            var replaceValue = d.replace[replaceKey];
-            if (replaceValue === "*")
-              return false;
-            if (replaceValue === tags[replaceKey])
-              return false;
-            return true;
-          });
-          if (hasExistingValues)
-            return;
+    };
+    _this.matchTags = (tags, geometry, loc) => {
+      const keyIndex = _geometryIndex[geometry];
+      let bestScore = -1;
+      let bestMatch;
+      let matchCandidates = [];
+      for (let k in tags) {
+        let indexMatches = [];
+        let valueIndex = keyIndex[k];
+        if (!valueIndex)
+          continue;
+        let keyValueMatches = valueIndex[tags[k]];
+        if (keyValueMatches)
+          indexMatches.push(...keyValueMatches);
+        let keyStarMatches = valueIndex["*"];
+        if (keyStarMatches)
+          indexMatches.push(...keyStarMatches);
+        if (indexMatches.length === 0)
+          continue;
+        for (let i2 = 0; i2 < indexMatches.length; i2++) {
+          const candidate = indexMatches[i2];
+          const score = candidate.matchScore(tags);
+          if (score === -1) {
+            continue;
+          }
+          matchCandidates.push({ score, candidate });
+          if (score > bestScore) {
+            bestScore = score;
+            bestMatch = candidate;
+          }
         }
-        var matchesDeprecatedTags = oldKeys.every(function(oldKey) {
-          if (!tags[oldKey])
-            return false;
-          if (d.old[oldKey] === "*")
-            return true;
-          if (d.old[oldKey] === tags[oldKey])
-            return true;
-          var vals = tags[oldKey].split(";").filter(Boolean);
-          if (vals.length === 0) {
-            return false;
-          } else if (vals.length > 1) {
-            return vals.indexOf(d.old[oldKey]) !== -1;
-          } else {
-            if (tags[oldKey] === d.old[oldKey]) {
-              if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
-                var replaceKeys = Object.keys(d.replace);
-                return !replaceKeys.every(function(replaceKey) {
-                  return tags[replaceKey] === d.replace[replaceKey];
-                });
-              } else {
-                return true;
-              }
+      }
+      if (bestMatch && bestMatch.locationSetID && bestMatch.locationSetID !== "+[Q2]" && Array.isArray(loc)) {
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
+        if (!validHere[bestMatch.locationSetID]) {
+          matchCandidates.sort((a, b) => a.score < b.score ? 1 : -1);
+          for (let i2 = 0; i2 < matchCandidates.length; i2++) {
+            const candidateScore = matchCandidates[i2];
+            if (!candidateScore.candidate.locationSetID || validHere[candidateScore.candidate.locationSetID]) {
+              bestMatch = candidateScore.candidate;
+              bestScore = candidateScore.score;
+              break;
             }
           }
+        }
+      }
+      if (!bestMatch || bestMatch.isFallback()) {
+        for (let k in tags) {
+          if (/^addr:/.test(k) && keyIndex["addr:*"] && keyIndex["addr:*"]["*"]) {
+            bestMatch = keyIndex["addr:*"]["*"][0];
+            break;
+          }
+        }
+      }
+      return bestMatch || _this.fallback(geometry);
+    };
+    _this.allowsVertex = (entity, resolver) => {
+      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;
+        const geometries = osmNodeGeometriesForTags(entity.tags);
+        if (geometries.vertex)
+          return true;
+        if (geometries.point)
           return false;
-        });
-        if (matchesDeprecatedTags) {
-          deprecated.push(d);
+        return true;
+      });
+    };
+    _this.areaKeys = () => {
+      const ignore = {
+        barrier: true,
+        highway: true,
+        footway: true,
+        railway: true,
+        junction: true,
+        traffic_calming: true,
+        type: true
+      };
+      let areaKeys = {};
+      const presets = _this.collection.filter((p) => !p.suggestion && !p.replacement);
+      presets.forEach((p) => {
+        const keys2 = p.tags && Object.keys(p.tags);
+        const key = keys2 && keys2.length && keys2[0];
+        if (!key)
+          return;
+        if (ignore[key])
+          return;
+        if (p.geometry.indexOf("area") !== -1) {
+          areaKeys[key] = areaKeys[key] || {};
         }
       });
-      return deprecated;
-    }
-  };
-
-  // modules/osm/lanes.js
-  function osmLanes(entity) {
-    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);
-    var maxspeed = parseMaxspeed(tags);
-    var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
-    var forward = laneDirections.forward;
-    var backward = laneDirections.backward;
-    var bothways = laneDirections.bothways;
-    var turnLanes = {};
-    turnLanes.unspecified = parseTurnLanes(tags["turn:lanes"]);
-    turnLanes.forward = parseTurnLanes(tags["turn:lanes:forward"]);
-    turnLanes.backward = parseTurnLanes(tags["turn:lanes:backward"]);
-    var maxspeedLanes = {};
-    maxspeedLanes.unspecified = parseMaxspeedLanes(tags["maxspeed:lanes"], maxspeed);
-    maxspeedLanes.forward = parseMaxspeedLanes(tags["maxspeed:lanes:forward"], maxspeed);
-    maxspeedLanes.backward = parseMaxspeedLanes(tags["maxspeed:lanes:backward"], maxspeed);
-    var psvLanes = {};
-    psvLanes.unspecified = parseMiscLanes(tags["psv:lanes"]);
-    psvLanes.forward = parseMiscLanes(tags["psv:lanes:forward"]);
-    psvLanes.backward = parseMiscLanes(tags["psv:lanes:backward"]);
-    var busLanes = {};
-    busLanes.unspecified = parseMiscLanes(tags["bus:lanes"]);
-    busLanes.forward = parseMiscLanes(tags["bus:lanes:forward"]);
-    busLanes.backward = parseMiscLanes(tags["bus:lanes:backward"]);
-    var taxiLanes = {};
-    taxiLanes.unspecified = parseMiscLanes(tags["taxi:lanes"]);
-    taxiLanes.forward = parseMiscLanes(tags["taxi:lanes:forward"]);
-    taxiLanes.backward = parseMiscLanes(tags["taxi:lanes:backward"]);
-    var hovLanes = {};
-    hovLanes.unspecified = parseMiscLanes(tags["hov:lanes"]);
-    hovLanes.forward = parseMiscLanes(tags["hov:lanes:forward"]);
-    hovLanes.backward = parseMiscLanes(tags["hov:lanes:backward"]);
-    var hgvLanes = {};
-    hgvLanes.unspecified = parseMiscLanes(tags["hgv:lanes"]);
-    hgvLanes.forward = parseMiscLanes(tags["hgv:lanes:forward"]);
-    hgvLanes.backward = parseMiscLanes(tags["hgv:lanes:backward"]);
-    var bicyclewayLanes = {};
-    bicyclewayLanes.unspecified = parseBicycleWay(tags["bicycleway:lanes"]);
-    bicyclewayLanes.forward = parseBicycleWay(tags["bicycleway:lanes:forward"]);
-    bicyclewayLanes.backward = parseBicycleWay(tags["bicycleway:lanes:backward"]);
-    var lanesObj = {
-      forward: [],
-      backward: [],
-      unspecified: []
+      presets.forEach((p) => {
+        let key;
+        for (key in p.addTags) {
+          const value = p.addTags[key];
+          if (key in areaKeys && // probably an area...
+          p.geometry.indexOf("line") !== -1 && // but sometimes a line
+          value !== "*") {
+            areaKeys[key][value] = true;
+          }
+        }
+      });
+      return areaKeys;
     };
-    mapToLanesObj(lanesObj, turnLanes, "turnLane");
-    mapToLanesObj(lanesObj, maxspeedLanes, "maxspeed");
-    mapToLanesObj(lanesObj, psvLanes, "psv");
-    mapToLanesObj(lanesObj, busLanes, "bus");
-    mapToLanesObj(lanesObj, taxiLanes, "taxi");
-    mapToLanesObj(lanesObj, hovLanes, "hov");
-    mapToLanesObj(lanesObj, hgvLanes, "hgv");
-    mapToLanesObj(lanesObj, bicyclewayLanes, "bicycleway");
-    return {
-      metadata: {
-        count: laneCount,
-        oneway: isOneWay,
-        forward,
-        backward,
-        bothways,
-        turnLanes,
-        maxspeed,
-        maxspeedLanes,
-        psvLanes,
-        busLanes,
-        taxiLanes,
-        hovLanes,
-        hgvLanes,
-        bicyclewayLanes
-      },
-      lanes: lanesObj
+    _this.lineTags = () => {
+      return _this.collection.filter((lineTags, d) => {
+        if (d.suggestion || d.replacement || d.searchable === false)
+          return lineTags;
+        const keys2 = d.tags && Object.keys(d.tags);
+        const key = keys2 && keys2.length && keys2[0];
+        if (!key)
+          return lineTags;
+        if (d.geometry.indexOf("line") !== -1) {
+          lineTags[key] = lineTags[key] || [];
+          lineTags[key].push(d.tags);
+        }
+        return lineTags;
+      }, {});
     };
-  }
-  function getLaneCount(tags, isOneWay) {
-    var count;
-    if (tags.lanes) {
-      count = parseInt(tags.lanes, 10);
-      if (count > 0) {
-        return count;
-      }
-    }
-    switch (tags.highway) {
-      case "trunk":
-      case "motorway":
-        count = isOneWay ? 2 : 4;
-        break;
-      default:
-        count = isOneWay ? 1 : 2;
-        break;
-    }
-    return count;
-  }
-  function parseMaxspeed(tags) {
-    var maxspeed = tags.maxspeed;
-    if (!maxspeed)
-      return;
-    var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
-    if (!maxspeedRegex.test(maxspeed))
-      return;
-    return parseInt(maxspeed, 10);
-  }
-  function parseLaneDirections(tags, isOneWay, laneCount) {
-    var forward = parseInt(tags["lanes:forward"], 10);
-    var backward = parseInt(tags["lanes:backward"], 10);
-    var bothways = parseInt(tags["lanes:both_ways"], 10) > 0 ? 1 : 0;
-    if (parseInt(tags.oneway, 10) === -1) {
-      forward = 0;
-      bothways = 0;
-      backward = laneCount;
-    } else if (isOneWay) {
-      forward = laneCount;
-      bothways = 0;
-      backward = 0;
-    } else if (isNaN(forward) && isNaN(backward)) {
-      backward = Math.floor((laneCount - bothways) / 2);
-      forward = laneCount - bothways - backward;
-    } else if (isNaN(forward)) {
-      if (backward > laneCount - bothways) {
-        backward = laneCount - bothways;
+    _this.pointTags = () => {
+      return _this.collection.reduce((pointTags, d) => {
+        if (d.suggestion || d.replacement || d.searchable === false)
+          return pointTags;
+        const keys2 = d.tags && Object.keys(d.tags);
+        const key = keys2 && keys2.length && keys2[0];
+        if (!key)
+          return pointTags;
+        if (d.geometry.indexOf("point") !== -1) {
+          pointTags[key] = pointTags[key] || {};
+          pointTags[key][d.tags[key]] = true;
+        }
+        return pointTags;
+      }, {});
+    };
+    _this.vertexTags = () => {
+      return _this.collection.reduce((vertexTags, d) => {
+        if (d.suggestion || d.replacement || d.searchable === false)
+          return vertexTags;
+        const keys2 = d.tags && Object.keys(d.tags);
+        const key = keys2 && keys2.length && keys2[0];
+        if (!key)
+          return vertexTags;
+        if (d.geometry.indexOf("vertex") !== -1) {
+          vertexTags[key] = vertexTags[key] || {};
+          vertexTags[key][d.tags[key]] = true;
+        }
+        return vertexTags;
+      }, {});
+    };
+    _this.field = (id2) => _fields[id2];
+    _this.universal = () => _universal;
+    _this.defaults = (geometry, n2, startWithRecents, loc, extraPresets) => {
+      let recents = [];
+      if (startWithRecents) {
+        recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
       }
-      forward = laneCount - bothways - backward;
-    } else if (isNaN(backward)) {
-      if (forward > laneCount - bothways) {
-        forward = laneCount - bothways;
+      let defaults2;
+      if (_addablePresetIDs) {
+        defaults2 = Array.from(_addablePresetIDs).map(function(id2) {
+          var preset = _this.item(id2);
+          if (preset && preset.matchGeometry(geometry))
+            return preset;
+          return null;
+        }).filter(Boolean);
+      } else {
+        defaults2 = _defaults[geometry].collection.concat(_this.fallback(geometry));
       }
-      backward = laneCount - bothways - forward;
+      let result = presetCollection(
+        utilArrayUniq(recents.concat(defaults2).concat(extraPresets || [])).slice(0, n2 - 1)
+      );
+      if (Array.isArray(loc)) {
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
+        result.collection = result.collection.filter((a) => !a.locationSetID || validHere[a.locationSetID]);
+      }
+      return result;
+    };
+    _this.addablePresetIDs = function(val) {
+      if (!arguments.length)
+        return _addablePresetIDs;
+      if (Array.isArray(val))
+        val = new Set(val);
+      _addablePresetIDs = val;
+      if (_addablePresetIDs) {
+        _this.collection.forEach((p) => {
+          if (p.addable)
+            p.addable(_addablePresetIDs.has(p.id));
+        });
+      } else {
+        _this.collection.forEach((p) => {
+          if (p.addable)
+            p.addable(true);
+        });
+      }
+      return _this;
+    };
+    _this.recent = () => {
+      return presetCollection(
+        utilArrayUniq(_this.getRecents().map((d) => d.preset).filter((d) => d.searchable !== false))
+      );
+    };
+    function RibbonItem(preset, source) {
+      let item = {};
+      item.preset = preset;
+      item.source = source;
+      item.isFavorite = () => item.source === "favorite";
+      item.isRecent = () => item.source === "recent";
+      item.matches = (preset2) => item.preset.id === preset2.id;
+      item.minified = () => ({ pID: item.preset.id });
+      return item;
     }
-    return {
-      forward,
-      backward,
-      bothways
+    function ribbonItemForMinified(d, source) {
+      if (d && d.pID) {
+        const preset = _this.item(d.pID);
+        if (!preset)
+          return null;
+        return RibbonItem(preset, source);
+      }
+      return null;
+    }
+    _this.getGenericRibbonItems = () => {
+      return ["point", "line", "area"].map((id2) => RibbonItem(_this.item(id2), "generic"));
+    };
+    _this.getAddable = () => {
+      if (!_addablePresetIDs)
+        return [];
+      return _addablePresetIDs.map((id2) => {
+        const preset = _this.item(id2);
+        if (preset)
+          return RibbonItem(preset, "addable");
+        return null;
+      }).filter(Boolean);
+    };
+    function setRecents(items) {
+      _recents = items;
+      const minifiedItems = items.map((d) => d.minified());
+      corePreferences("preset_recents", JSON.stringify(minifiedItems));
+      dispatch10.call("recentsChange");
+    }
+    _this.getRecents = () => {
+      if (!_recents) {
+        _recents = (JSON.parse(corePreferences("preset_recents")) || []).reduce((acc, d) => {
+          let item = ribbonItemForMinified(d, "recent");
+          if (item && item.preset.addable())
+            acc.push(item);
+          return acc;
+        }, []);
+      }
+      return _recents;
+    };
+    _this.addRecent = (preset, besidePreset, after) => {
+      const recents = _this.getRecents();
+      const beforeItem = _this.recentMatching(besidePreset);
+      let toIndex = recents.indexOf(beforeItem);
+      if (after)
+        toIndex += 1;
+      const newItem = RibbonItem(preset, "recent");
+      recents.splice(toIndex, 0, newItem);
+      setRecents(recents);
+    };
+    _this.removeRecent = (preset) => {
+      const item = _this.recentMatching(preset);
+      if (item) {
+        let items = _this.getRecents();
+        items.splice(items.indexOf(item), 1);
+        setRecents(items);
+      }
+    };
+    _this.recentMatching = (preset) => {
+      const items = _this.getRecents();
+      for (let i2 in items) {
+        if (items[i2].matches(preset)) {
+          return items[i2];
+        }
+      }
+      return null;
+    };
+    _this.moveItem = (items, fromIndex, toIndex) => {
+      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;
+    };
+    _this.moveRecent = (item, beforeItem) => {
+      const recents = _this.getRecents();
+      const fromIndex = recents.indexOf(item);
+      const toIndex = recents.indexOf(beforeItem);
+      const items = _this.moveItem(recents, fromIndex, toIndex);
+      if (items)
+        setRecents(items);
+    };
+    _this.setMostRecent = (preset) => {
+      if (preset.searchable === false)
+        return;
+      let items = _this.getRecents();
+      let item = _this.recentMatching(preset);
+      if (item) {
+        items.splice(items.indexOf(item), 1);
+      } else {
+        item = RibbonItem(preset, "recent");
+      }
+      while (items.length >= MAXRECENTS) {
+        items.pop();
+      }
+      items.unshift(item);
+      setRecents(items);
+    };
+    function setFavorites(items) {
+      _favorites = items;
+      const minifiedItems = items.map((d) => d.minified());
+      corePreferences("preset_favorites", JSON.stringify(minifiedItems));
+      dispatch10.call("favoritePreset");
+    }
+    _this.addFavorite = (preset, besidePreset, after) => {
+      const favorites = _this.getFavorites();
+      const beforeItem = _this.favoriteMatching(besidePreset);
+      let toIndex = favorites.indexOf(beforeItem);
+      if (after)
+        toIndex += 1;
+      const newItem = RibbonItem(preset, "favorite");
+      favorites.splice(toIndex, 0, newItem);
+      setFavorites(favorites);
+    };
+    _this.toggleFavorite = (preset) => {
+      const favs = _this.getFavorites();
+      const favorite = _this.favoriteMatching(preset);
+      if (favorite) {
+        favs.splice(favs.indexOf(favorite), 1);
+      } else {
+        if (favs.length === 10) {
+          favs.pop();
+        }
+        favs.push(RibbonItem(preset, "favorite"));
+      }
+      setFavorites(favs);
+    };
+    _this.removeFavorite = (preset) => {
+      const item = _this.favoriteMatching(preset);
+      if (item) {
+        const items = _this.getFavorites();
+        items.splice(items.indexOf(item), 1);
+        setFavorites(items);
+      }
+    };
+    _this.getFavorites = () => {
+      if (!_favorites) {
+        let rawFavorites = JSON.parse(corePreferences("preset_favorites"));
+        if (!rawFavorites) {
+          rawFavorites = [];
+          corePreferences("preset_favorites", JSON.stringify(rawFavorites));
+        }
+        _favorites = rawFavorites.reduce((output, d) => {
+          const item = ribbonItemForMinified(d, "favorite");
+          if (item && item.preset.addable())
+            output.push(item);
+          return output;
+        }, []);
+      }
+      return _favorites;
+    };
+    _this.favoriteMatching = (preset) => {
+      const favs = _this.getFavorites();
+      for (let index in favs) {
+        if (favs[index].matches(preset)) {
+          return favs[index];
+        }
+      }
+      return null;
     };
+    return utilRebind(_this, dispatch10, "on");
   }
-  function parseTurnLanes(tag) {
-    if (!tag)
-      return;
-    var validValues = [
-      "left",
-      "slight_left",
-      "sharp_left",
-      "through",
-      "right",
-      "slight_right",
-      "sharp_right",
-      "reverse",
-      "merge_to_left",
-      "merge_to_right",
-      "none"
-    ];
-    return tag.split("|").map(function(s) {
-      if (s === "")
-        s = "none";
-      return s.split(";").map(function(d) {
-        return validValues.indexOf(d) === -1 ? "unknown" : d;
-      });
-    });
+
+  // modules/util/util.js
+  function utilTagText(entity) {
+    var obj = entity && entity.tags || {};
+    return Object.keys(obj).map(function(k) {
+      return k + "=" + obj[k];
+    }).join(", ");
   }
-  function parseMaxspeedLanes(tag, maxspeed) {
-    if (!tag)
-      return;
-    return tag.split("|").map(function(s) {
-      if (s === "none")
-        return s;
-      var m = parseInt(s, 10);
-      if (s === "" || m === maxspeed)
-        return null;
-      return isNaN(m) ? "unknown" : m;
-    });
+  function utilTotalExtent(array2, graph) {
+    var extent = geoExtent();
+    var val, entity;
+    for (var i2 = 0; i2 < array2.length; i2++) {
+      val = array2[i2];
+      entity = typeof val === "string" ? graph.hasEntity(val) : val;
+      if (entity) {
+        extent._extend(entity.extent(graph));
+      }
+    }
+    return extent;
   }
-  function parseMiscLanes(tag) {
-    if (!tag)
-      return;
-    var validValues = [
-      "yes",
-      "no",
-      "designated"
-    ];
-    return tag.split("|").map(function(s) {
-      if (s === "")
-        s = "no";
-      return validValues.indexOf(s) === -1 ? "unknown" : s;
+  function utilTagDiff(oldTags, newTags) {
+    var tagDiff = [];
+    var keys2 = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
+    keys2.forEach(function(k) {
+      var oldVal = oldTags[k];
+      var newVal = newTags[k];
+      if ((oldVal || oldVal === "") && (newVal === void 0 || newVal !== oldVal)) {
+        tagDiff.push({
+          type: "-",
+          key: k,
+          oldVal,
+          newVal,
+          display: "- " + k + "=" + oldVal
+        });
+      }
+      if ((newVal || newVal === "") && (oldVal === void 0 || newVal !== oldVal)) {
+        tagDiff.push({
+          type: "+",
+          key: k,
+          oldVal,
+          newVal,
+          display: "+ " + k + "=" + newVal
+        });
+      }
     });
+    return tagDiff;
   }
-  function parseBicycleWay(tag) {
-    if (!tag)
-      return;
-    var validValues = [
-      "yes",
-      "no",
-      "designated",
-      "lane"
-    ];
-    return tag.split("|").map(function(s) {
-      if (s === "")
-        s = "no";
-      return validValues.indexOf(s) === -1 ? "unknown" : s;
-    });
+  function utilEntitySelector(ids) {
+    return ids.length ? "." + ids.join(",.") : "nothing";
   }
-  function mapToLanesObj(lanesObj, data, key) {
-    if (data.forward) {
-      data.forward.forEach(function(l, i2) {
-        if (!lanesObj.forward[i2])
-          lanesObj.forward[i2] = {};
-        lanesObj.forward[i2][key] = l;
+  function utilEntityOrMemberSelector(ids, graph) {
+    var seen = new Set(ids);
+    ids.forEach(collectShallowDescendants);
+    return utilEntitySelector(Array.from(seen));
+    function collectShallowDescendants(id2) {
+      var entity = graph.hasEntity(id2);
+      if (!entity || entity.type !== "relation")
+        return;
+      entity.members.map(function(member) {
+        return member.id;
+      }).forEach(function(id3) {
+        seen.add(id3);
       });
     }
-    if (data.backward) {
-      data.backward.forEach(function(l, i2) {
-        if (!lanesObj.backward[i2])
-          lanesObj.backward[i2] = {};
-        lanesObj.backward[i2][key] = l;
-      });
+  }
+  function utilEntityOrDeepMemberSelector(ids, graph) {
+    return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
+  }
+  function utilEntityAndDeepMemberIDs(ids, graph) {
+    var seen = /* @__PURE__ */ new Set();
+    ids.forEach(collectDeepDescendants);
+    return Array.from(seen);
+    function collectDeepDescendants(id2) {
+      if (seen.has(id2))
+        return;
+      seen.add(id2);
+      var entity = graph.hasEntity(id2);
+      if (!entity || entity.type !== "relation")
+        return;
+      entity.members.map(function(member) {
+        return member.id;
+      }).forEach(collectDeepDescendants);
     }
-    if (data.unspecified) {
-      data.unspecified.forEach(function(l, i2) {
-        if (!lanesObj.unspecified[i2])
-          lanesObj.unspecified[i2] = {};
-        lanesObj.unspecified[i2][key] = l;
-      });
+  }
+  function utilDeepMemberSelector(ids, graph, skipMultipolgonMembers) {
+    var idsSet = new Set(ids);
+    var seen = /* @__PURE__ */ new Set();
+    var returners = /* @__PURE__ */ new Set();
+    ids.forEach(collectDeepDescendants);
+    return utilEntitySelector(Array.from(returners));
+    function collectDeepDescendants(id2) {
+      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;
+      entity.members.map(function(member) {
+        return member.id;
+      }).forEach(collectDeepDescendants);
     }
   }
-
-  // modules/osm/way.js
-  function osmWay() {
-    if (!(this instanceof osmWay)) {
-      return new osmWay().initialize(arguments);
-    } else if (arguments.length) {
-      this.initialize(arguments);
+  function utilHighlightEntities(ids, highlighted, context) {
+    context.surface().selectAll(utilEntityOrDeepMemberSelector(ids, context.graph())).classed("highlighted", highlighted);
+  }
+  function utilGetAllNodes(ids, graph) {
+    var seen = /* @__PURE__ */ new Set();
+    var nodes = /* @__PURE__ */ new Set();
+    ids.forEach(collectNodes);
+    return Array.from(nodes);
+    function collectNodes(id2) {
+      if (seen.has(id2))
+        return;
+      seen.add(id2);
+      var entity = graph.hasEntity(id2);
+      if (!entity)
+        return;
+      if (entity.type === "node") {
+        nodes.add(entity);
+      } else if (entity.type === "way") {
+        entity.nodes.forEach(collectNodes);
+      } else {
+        entity.members.map(function(member) {
+          return member.id;
+        }).forEach(collectNodes);
+      }
     }
   }
-  osmEntity.way = osmWay;
-  osmWay.prototype = Object.create(osmEntity.prototype);
-  Object.assign(osmWay.prototype, {
-    type: "way",
-    nodes: [],
-    copy: function(resolver, copies) {
-      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;
-      });
-      copy2 = copy2.update({ nodes });
-      copies[this.id] = copy2;
-      return copy2;
-    },
-    extent: function(resolver) {
-      return resolver.transient(this, "extent", function() {
-        var extent = geoExtent();
-        for (var i2 = 0; i2 < this.nodes.length; i2++) {
-          var node = resolver.hasEntity(this.nodes[i2]);
-          if (node) {
-            extent._extend(node.extent());
-          }
-        }
-        return extent;
-      });
-    },
-    first: function() {
-      return this.nodes[0];
-    },
-    last: function() {
-      return this.nodes[this.nodes.length - 1];
-    },
-    contains: function(node) {
-      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";
-    },
-    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;
-      return 0;
-    },
-    impliedLineWidthMeters: function() {
-      var averageWidths = {
-        highway: {
-          motorway: 5,
-          motorway_link: 5,
-          trunk: 4.5,
-          trunk_link: 4.5,
-          primary: 4,
-          secondary: 4,
-          tertiary: 4,
-          primary_link: 4,
-          secondary_link: 4,
-          tertiary_link: 4,
-          unclassified: 4,
-          road: 4,
-          living_street: 4,
-          bus_guideway: 4,
-          pedestrian: 4,
-          residential: 3.5,
-          service: 3.5,
-          track: 3,
-          cycleway: 2.5,
-          bridleway: 2,
-          corridor: 2,
-          steps: 2,
-          path: 1.5,
-          footway: 1.5
-        },
-        railway: {
-          rail: 2.5,
-          light_rail: 2.5,
-          tram: 2.5,
-          subway: 2.5,
-          monorail: 2.5,
-          funicular: 2.5,
-          disused: 2.5,
-          preserved: 2.5,
-          miniature: 1.5,
-          narrow_gauge: 1.5
-        },
-        waterway: {
-          river: 50,
-          canal: 25,
-          stream: 5,
-          tidal_channel: 5,
-          fish_pass: 2.5,
-          drain: 2.5,
-          ditch: 1.5
-        }
-      };
-      for (var key in averageWidths) {
-        if (this.tags[key] && averageWidths[key][this.tags[key]]) {
-          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;
-            return width * laneCount;
-          }
-          return width;
-        }
-      }
-      return null;
-    },
-    isOneWay: function() {
-      var values = {
-        "yes": true,
-        "1": true,
-        "-1": true,
-        "reversible": true,
-        "alternating": true,
-        "no": false,
-        "0": false
-      };
-      if (values[this.tags.oneway] !== void 0) {
-        return values[this.tags.oneway];
-      }
-      for (var key in this.tags) {
-        if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) {
-          return true;
+  function utilDisplayName(entity) {
+    var localizedNameKey = "name:" + _mainLocalizer.languageCode().toLowerCase();
+    var name = entity.tags[localizedNameKey] || entity.tags.name || "";
+    if (name)
+      return name;
+    var tags = {
+      direction: entity.tags.direction,
+      from: entity.tags.from,
+      network: entity.tags.cycle_network || entity.tags.network,
+      ref: entity.tags.ref,
+      to: entity.tags.to,
+      via: entity.tags.via
+    };
+    var keyComponents = [];
+    if (tags.network) {
+      keyComponents.push("network");
+    }
+    if (tags.ref) {
+      keyComponents.push("ref");
+    }
+    if (entity.tags.route) {
+      if (tags.direction) {
+        keyComponents.push("direction");
+      } else if (tags.from && tags.to) {
+        keyComponents.push("from");
+        keyComponents.push("to");
+        if (tags.via) {
+          keyComponents.push("via");
         }
       }
-      return false;
-    },
-    sidednessIdentifier: function() {
-      for (var key in this.tags) {
-        var value = this.tags[key];
-        if (key in osmRightSideIsInsideTags && value in osmRightSideIsInsideTags[key]) {
-          if (osmRightSideIsInsideTags[key][value] === true) {
-            return key;
+    }
+    if (keyComponents.length) {
+      name = _t("inspector.display_name." + keyComponents.join("_"), tags);
+    }
+    return name;
+  }
+  function utilDisplayNameForPath(entity) {
+    var name = utilDisplayName(entity);
+    var isFirefox = utilDetect().browser.toLowerCase().indexOf("firefox") > -1;
+    var isNewChromium = Number(utilDetect().version.split(".")[0]) >= 96;
+    if (!isFirefox && !isNewChromium && name && rtlRegex.test(name)) {
+      name = fixRTLTextForSvg(name);
+    }
+    return name;
+  }
+  function utilDisplayType(id2) {
+    return {
+      n: _t("inspector.node"),
+      w: _t("inspector.way"),
+      r: _t("inspector.relation")
+    }[id2.charAt(0)];
+  }
+  function utilDisplayLabel(entity, graphOrGeometry, verbose) {
+    var result;
+    var displayName = utilDisplayName(entity);
+    var preset = typeof graphOrGeometry === "string" ? _mainPresetIndex.matchTags(entity.tags, graphOrGeometry) : _mainPresetIndex.match(entity, graphOrGeometry);
+    var presetName = preset && (preset.suggestion ? preset.subtitle() : preset.name());
+    if (verbose) {
+      result = [presetName, displayName].filter(Boolean).join(" ");
+    } else {
+      result = displayName || presetName;
+    }
+    return result || utilDisplayType(entity.id);
+  }
+  function utilEntityRoot(entityType) {
+    return {
+      node: "n",
+      way: "w",
+      relation: "r"
+    }[entityType];
+  }
+  function utilCombinedTags(entityIDs, graph) {
+    var tags = {};
+    var tagCounts = {};
+    var allKeys = /* @__PURE__ */ new Set();
+    var entities = entityIDs.map(function(entityID) {
+      return graph.hasEntity(entityID);
+    }).filter(Boolean);
+    entities.forEach(function(entity) {
+      var keys2 = Object.keys(entity.tags).filter(Boolean);
+      keys2.forEach(function(key2) {
+        allKeys.add(key2);
+      });
+    });
+    entities.forEach(function(entity) {
+      allKeys.forEach(function(key2) {
+        var value = entity.tags[key2];
+        if (!tags.hasOwnProperty(key2)) {
+          tags[key2] = value;
+        } else {
+          if (!Array.isArray(tags[key2])) {
+            if (tags[key2] !== value) {
+              tags[key2] = [tags[key2], value];
+            }
           } else {
-            return osmRightSideIsInsideTags[key][value];
+            if (tags[key2].indexOf(value) === -1) {
+              tags[key2].push(value);
+            }
           }
         }
-      }
-      return null;
-    },
-    isSided: function() {
-      if (this.tags.two_sided === "yes") {
-        return false;
-      }
-      return this.sidednessIdentifier() !== null;
-    },
-    lanes: function() {
-      return osmLanes(this);
-    },
-    isClosed: function() {
-      return this.nodes.length > 1 && this.first() === this.last();
-    },
-    isConvex: function(resolver) {
-      if (!this.isClosed() || this.isDegenerate())
-        return null;
-      var nodes = utilArrayUniq(resolver.childNodes(this));
-      var coords = nodes.map(function(n2) {
-        return n2.loc;
+        var tagHash = key2 + "=" + value;
+        if (!tagCounts[tagHash])
+          tagCounts[tagHash] = 0;
+        tagCounts[tagHash] += 1;
       });
-      var curr = 0;
-      var prev = 0;
-      for (var i2 = 0; i2 < coords.length; i2++) {
-        var o = coords[(i2 + 1) % coords.length];
-        var a = coords[i2];
-        var b = coords[(i2 + 2) % coords.length];
-        var res = geoVecCross(a, b, o);
-        curr = res > 0 ? 1 : res < 0 ? -1 : 0;
-        if (curr === 0) {
-          continue;
-        } else if (prev && curr !== prev) {
-          return false;
-        }
-        prev = curr;
-      }
-      return true;
-    },
-    tagSuggestingArea: function() {
-      return osmTagSuggestingArea(this.tags);
-    },
-    isArea: function() {
-      if (this.tags.area === "yes")
-        return true;
-      if (!this.isClosed() || this.tags.area === "no")
-        return false;
-      return this.tagSuggestingArea() !== null;
-    },
-    isDegenerate: function() {
-      return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
-    },
-    areAdjacent: function(n1, n2) {
-      for (var i2 = 0; i2 < this.nodes.length; i2++) {
-        if (this.nodes[i2] === n1) {
-          if (this.nodes[i2 - 1] === n2)
-            return true;
-          if (this.nodes[i2 + 1] === n2)
-            return true;
+    });
+    for (var key in tags) {
+      if (!Array.isArray(tags[key]))
+        continue;
+      tags[key] = tags[key].sort(function(val12, val2) {
+        var key2 = key2;
+        var count2 = tagCounts[key2 + "=" + val2];
+        var count1 = tagCounts[key2 + "=" + val12];
+        if (count2 !== count1) {
+          return count2 - count1;
         }
-      }
-      return false;
-    },
-    geometry: function(graph) {
-      return graph.transient(this, "geometry", function() {
-        return this.isArea() ? "area" : "line";
-      });
-    },
-    segments: function(graph) {
-      function segmentExtent(graph2) {
-        var n1 = graph2.hasEntity(this.nodes[0]);
-        var n2 = graph2.hasEntity(this.nodes[1]);
-        return n1 && n2 && geoExtent([
-          [
-            Math.min(n1.loc[0], n2.loc[0]),
-            Math.min(n1.loc[1], n2.loc[1])
-          ],
-          [
-            Math.max(n1.loc[0], n2.loc[0]),
-            Math.max(n1.loc[1], n2.loc[1])
-          ]
-        ]);
-      }
-      return graph.transient(this, "segments", function() {
-        var segments = [];
-        for (var i2 = 0; i2 < this.nodes.length - 1; i2++) {
-          segments.push({
-            id: this.id + "-" + i2,
-            wayId: this.id,
-            index: i2,
-            nodes: [this.nodes[i2], this.nodes[i2 + 1]],
-            extent: segmentExtent
-          });
+        if (val2 && val12) {
+          return val12.localeCompare(val2);
         }
-        return segments;
+        return val12 ? 1 : -1;
       });
-    },
-    close: function() {
-      if (this.isClosed() || !this.nodes.length)
-        return this;
-      var nodes = this.nodes.slice();
-      nodes = nodes.filter(noRepeatNodes);
-      nodes.push(nodes[0]);
-      return this.update({ nodes });
-    },
-    unclose: function() {
-      if (!this.isClosed())
-        return this;
-      var nodes = this.nodes.slice();
-      var connector = this.first();
-      var i2 = nodes.length - 1;
-      while (i2 > 0 && nodes.length > 1 && nodes[i2] === connector) {
-        nodes.splice(i2, 1);
-        i2 = nodes.length - 1;
-      }
-      nodes = nodes.filter(noRepeatNodes);
-      return this.update({ nodes });
-    },
-    addNode: function(id2, index) {
-      var nodes = this.nodes.slice();
-      var isClosed = this.isClosed();
-      var max3 = isClosed ? nodes.length - 1 : nodes.length;
-      if (index === void 0) {
-        index = max3;
-      }
-      if (index < 0 || index > max3) {
-        throw new RangeError("index " + index + " out of range 0.." + max3);
-      }
-      if (isClosed) {
-        var connector = this.first();
-        var i2 = 1;
-        while (i2 < nodes.length && nodes.length > 2 && nodes[i2] === connector) {
-          nodes.splice(i2, 1);
-          if (index > i2)
-            index--;
-        }
-        i2 = nodes.length - 1;
-        while (i2 > 0 && nodes.length > 1 && nodes[i2] === connector) {
-          nodes.splice(i2, 1);
-          if (index > i2)
-            index--;
-          i2 = nodes.length - 1;
-        }
-      }
-      nodes.splice(index, 0, id2);
-      nodes = nodes.filter(noRepeatNodes);
-      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
-        nodes.push(nodes[0]);
-      }
-      return this.update({ nodes });
-    },
-    updateNode: function(id2, index) {
-      var nodes = this.nodes.slice();
-      var isClosed = this.isClosed();
-      var max3 = nodes.length - 1;
-      if (index === void 0 || index < 0 || index > max3) {
-        throw new RangeError("index " + index + " out of range 0.." + max3);
+    }
+    return tags;
+  }
+  function utilStringQs(str2) {
+    var i2 = 0;
+    while (i2 < str2.length && (str2[i2] === "?" || str2[i2] === "#"))
+      i2++;
+    str2 = str2.slice(i2);
+    return str2.split("&").reduce(function(obj, pair2) {
+      var parts = pair2.split("=");
+      if (parts.length === 2) {
+        obj[parts[0]] = null === parts[1] ? "" : decodeURIComponent(parts[1]);
       }
-      if (isClosed) {
-        var connector = this.first();
-        var i2 = 1;
-        while (i2 < nodes.length && nodes.length > 2 && nodes[i2] === connector) {
-          nodes.splice(i2, 1);
-          if (index > i2)
-            index--;
-        }
-        i2 = nodes.length - 1;
-        while (i2 > 0 && nodes.length > 1 && nodes[i2] === connector) {
-          nodes.splice(i2, 1);
-          if (index === i2)
-            index = 0;
-          i2 = nodes.length - 1;
-        }
+      return obj;
+    }, {});
+  }
+  function utilQsString(obj, noencode) {
+    function softEncode(s) {
+      return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
+    }
+    return Object.keys(obj).sort().map(function(key) {
+      return encodeURIComponent(key) + "=" + (noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
+    }).join("&");
+  }
+  function utilPrefixDOMProperty(property) {
+    var prefixes2 = ["webkit", "ms", "moz", "o"];
+    var i2 = -1;
+    var n2 = prefixes2.length;
+    var s = document.body;
+    if (property in s)
+      return property;
+    property = property.slice(0, 1).toUpperCase() + property.slice(1);
+    while (++i2 < n2) {
+      if (prefixes2[i2] + property in s) {
+        return prefixes2[i2] + property;
       }
-      nodes.splice(index, 1, id2);
-      nodes = nodes.filter(noRepeatNodes);
-      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
-        nodes.push(nodes[0]);
+    }
+    return false;
+  }
+  function utilPrefixCSSProperty(property) {
+    var prefixes2 = ["webkit", "ms", "Moz", "O"];
+    var i2 = -1;
+    var n2 = prefixes2.length;
+    var s = document.body.style;
+    if (property.toLowerCase() in s) {
+      return property.toLowerCase();
+    }
+    while (++i2 < n2) {
+      if (prefixes2[i2] + property in s) {
+        return "-" + prefixes2[i2].toLowerCase() + property.replace(/([A-Z])/g, "-$1").toLowerCase();
       }
-      return this.update({ nodes });
-    },
-    replaceNode: function(needleID, replacementID) {
-      var nodes = this.nodes.slice();
-      var isClosed = this.isClosed();
-      for (var i2 = 0; i2 < nodes.length; i2++) {
-        if (nodes[i2] === needleID) {
-          nodes[i2] = replacementID;
+    }
+    return false;
+  }
+  var transformProperty;
+  function utilSetTransform(el, x, y, scale) {
+    var prop = transformProperty = transformProperty || utilPrefixCSSProperty("Transform");
+    var translate = utilDetect().opera ? "translate(" + x + "px," + y + "px)" : "translate3d(" + x + "px," + y + "px,0)";
+    return el.style(prop, translate + (scale ? " scale(" + scale + ")" : ""));
+  }
+  function utilEditDistance(a, b) {
+    a = (0, import_diacritics.remove)(a.toLowerCase());
+    b = (0, import_diacritics.remove)(b.toLowerCase());
+    if (a.length === 0)
+      return b.length;
+    if (b.length === 0)
+      return a.length;
+    var matrix = [];
+    var i2, j2;
+    for (i2 = 0; i2 <= b.length; i2++) {
+      matrix[i2] = [i2];
+    }
+    for (j2 = 0; j2 <= a.length; j2++) {
+      matrix[0][j2] = j2;
+    }
+    for (i2 = 1; i2 <= b.length; i2++) {
+      for (j2 = 1; j2 <= a.length; j2++) {
+        if (b.charAt(i2 - 1) === a.charAt(j2 - 1)) {
+          matrix[i2][j2] = matrix[i2 - 1][j2 - 1];
+        } else {
+          matrix[i2][j2] = Math.min(
+            matrix[i2 - 1][j2 - 1] + 1,
+            // substitution
+            Math.min(
+              matrix[i2][j2 - 1] + 1,
+              // insertion
+              matrix[i2 - 1][j2] + 1
+            )
+          );
         }
       }
-      nodes = nodes.filter(noRepeatNodes);
-      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
-        nodes.push(nodes[0]);
-      }
-      return this.update({ nodes });
-    },
-    removeNode: function(id2) {
-      var nodes = this.nodes.slice();
-      var isClosed = this.isClosed();
-      nodes = nodes.filter(function(node) {
-        return node !== id2;
-      }).filter(noRepeatNodes);
-      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
-        nodes.push(nodes[0]);
-      }
-      return this.update({ nodes });
-    },
-    asJXON: function(changeset_id) {
-      var r = {
-        way: {
-          "@id": this.osmId(),
-          "@version": this.version || 0,
-          nd: this.nodes.map(function(id2) {
-            return { keyAttributes: { ref: osmEntity.id.toOSM(id2) } };
-          }, this),
-          tag: Object.keys(this.tags).map(function(k) {
-            return { keyAttributes: { k, v: this.tags[k] } };
-          }, this)
-        }
-      };
-      if (changeset_id) {
-        r.way["@changeset"] = changeset_id;
-      }
-      return r;
-    },
-    asGeoJSON: function(resolver) {
-      return resolver.transient(this, "GeoJSON", function() {
-        var coordinates = resolver.childNodes(this).map(function(n2) {
-          return n2.loc;
-        });
-        if (this.isArea() && this.isClosed()) {
-          return {
-            type: "Polygon",
-            coordinates: [coordinates]
-          };
-        } else {
-          return {
-            type: "LineString",
-            coordinates
-          };
-        }
-      });
-    },
-    area: function(resolver) {
-      return resolver.transient(this, "area", function() {
-        var nodes = resolver.childNodes(this);
-        var json = {
-          type: "Polygon",
-          coordinates: [nodes.map(function(n2) {
-            return n2.loc;
-          })]
-        };
-        if (!this.isClosed() && nodes.length) {
-          json.coordinates[0].push(nodes[0].loc);
-        }
-        var area = area_default(json);
-        if (area > 2 * Math.PI) {
-          json.coordinates[0] = json.coordinates[0].reverse();
-          area = area_default(json);
-        }
-        return isNaN(area) ? 0 : area;
-      });
     }
-  });
-  function noRepeatNodes(node, i2, arr) {
-    return i2 === 0 || node !== arr[i2 - 1];
+    return matrix[b.length][a.length];
   }
-
-  // modules/osm/multipolygon.js
-  function osmOldMultipolygonOuterMemberOfRelation(entity, graph) {
-    if (entity.type !== "relation" || !entity.isMultipolygon() || Object.keys(entity.tags).filter(osmIsInterestingTag).length > 1) {
-      return false;
-    }
-    var outerMember;
-    for (var memberIndex in entity.members) {
-      var member = entity.members[memberIndex];
-      if (!member.role || member.role === "outer") {
-        if (outerMember)
-          return false;
-        if (member.type !== "way")
-          return false;
-        if (!graph.hasEntity(member.id))
-          return false;
-        outerMember = graph.entity(member.id);
-        if (Object.keys(outerMember.tags).filter(osmIsInterestingTag).length === 0) {
-          return false;
-        }
-      }
+  function utilFastMouse(container) {
+    var rect = container.getBoundingClientRect();
+    var rectLeft = rect.left;
+    var rectTop = rect.top;
+    var clientLeft = +container.clientLeft;
+    var clientTop = +container.clientTop;
+    return function(e) {
+      return [
+        e.clientX - rectLeft - clientLeft,
+        e.clientY - rectTop - clientTop
+      ];
+    };
+  }
+  function utilAsyncMap(inputs, func, callback) {
+    var remaining = inputs.length;
+    var results = [];
+    var errors = [];
+    inputs.forEach(function(d, i2) {
+      func(d, function done(err, data) {
+        errors[i2] = err;
+        results[i2] = data;
+        remaining--;
+        if (!remaining)
+          callback(errors, results);
+      });
+    });
+  }
+  function utilWrap(index, length) {
+    if (index < 0) {
+      index += Math.ceil(-index / length) * length;
     }
-    return outerMember;
+    return index % length;
   }
-  function osmIsOldMultipolygonOuterMember(entity, graph) {
-    if (entity.type !== "way" || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0) {
-      return false;
+  function utilFunctor(value) {
+    if (typeof value === "function")
+      return value;
+    return function() {
+      return value;
+    };
+  }
+  function utilNoAuto(selection2) {
+    var isText = selection2.size() && selection2.node().tagName.toLowerCase() === "textarea";
+    return selection2.attr("autocomplete", "new-password").attr("autocorrect", "off").attr("autocapitalize", "off").attr("spellcheck", isText ? "true" : "false");
+  }
+  function utilHashcode(str2) {
+    var hash = 0;
+    if (str2.length === 0) {
+      return hash;
     }
-    var parents = graph.parentRelations(entity);
-    if (parents.length !== 1)
-      return false;
-    var parent = parents[0];
-    if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
-      return false;
+    for (var i2 = 0; i2 < str2.length; i2++) {
+      var char = str2.charCodeAt(i2);
+      hash = (hash << 5) - hash + char;
+      hash = hash & hash;
     }
-    var members = parent.members, member;
-    for (var i2 = 0; i2 < members.length; i2++) {
-      member = members[i2];
-      if (member.id === entity.id && member.role && member.role !== "outer") {
-        return false;
-      }
-      if (member.id !== entity.id && (!member.role || member.role === "outer")) {
-        return false;
-      }
+    return hash;
+  }
+  function utilSafeClassName(str2) {
+    return str2.toLowerCase().replace(/[^a-z0-9]+/g, "_");
+  }
+  function utilUniqueDomId(val) {
+    return "ideditor-" + utilSafeClassName(val.toString()) + "-" + (/* @__PURE__ */ new Date()).getTime().toString();
+  }
+  function utilUnicodeCharsCount(str2) {
+    return Array.from(str2).length;
+  }
+  function utilUnicodeCharsTruncated(str2, limit) {
+    return Array.from(str2).slice(0, limit).join("");
+  }
+  function toNumericID(id2) {
+    var match = id2.match(/^[cnwr](-?\d+)$/);
+    if (match) {
+      return parseInt(match[1], 10);
     }
-    return parent;
+    return NaN;
   }
-  function osmOldMultipolygonOuterMember(entity, graph) {
-    if (entity.type !== "way")
-      return false;
-    var parents = graph.parentRelations(entity);
-    if (parents.length !== 1)
-      return false;
-    var parent = parents[0];
-    if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
-      return false;
+  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);
+    return Math.sign(left - right);
+  }
+  function utilCompareIDs(left, right) {
+    return compareNumericIDs(toNumericID(left), toNumericID(right));
+  }
+  function utilOldestID(ids) {
+    if (ids.length === 0) {
+      return void 0;
     }
-    var members = parent.members, member, outerMember;
-    for (var i2 = 0; i2 < members.length; i2++) {
-      member = members[i2];
-      if (!member.role || member.role === "outer") {
-        if (outerMember)
-          return false;
-        outerMember = member;
+    var oldestIDIndex = 0;
+    var oldestID = toNumericID(ids[0]);
+    for (var i2 = 1; i2 < ids.length; i2++) {
+      var num = toNumericID(ids[i2]);
+      if (compareNumericIDs(oldestID, num) === 1) {
+        oldestIDIndex = i2;
+        oldestID = num;
       }
     }
-    if (!outerMember)
-      return false;
-    var outerEntity = graph.hasEntity(outerMember.id);
-    if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) {
-      return false;
-    }
-    return outerEntity;
+    return ids[oldestIDIndex];
   }
-  function osmJoinWays(toJoin, graph) {
-    function resolve(member) {
-      return graph.childNodes(graph.entity(member.id));
+  function utilCleanOsmString(val, maxChars) {
+    if (val === void 0 || val === null) {
+      val = "";
+    } else {
+      val = val.toString();
     }
-    function reverse(item2) {
-      var action = actionReverse(item2.id, { reverseOneway: true });
-      sequences.actions.push(action);
-      return item2 instanceof osmWay ? action(graph).entity(item2.id) : item2;
+    val = val.trim();
+    if (val.normalize)
+      val = val.normalize("NFC");
+    return utilUnicodeCharsTruncated(val, maxChars);
+  }
+
+  // modules/osm/entity.js
+  function osmEntity(attrs) {
+    if (this instanceof osmEntity)
+      return;
+    if (attrs && attrs.type) {
+      return osmEntity[attrs.type].apply(this, arguments);
+    } else if (attrs && attrs.id) {
+      return osmEntity[osmEntity.id.type(attrs.id)].apply(this, arguments);
     }
-    toJoin = toJoin.filter(function(member) {
-      return member.type === "way" && graph.hasEntity(member.id);
-    });
-    var i2;
-    var joinAsMembers = true;
-    for (i2 = 0; i2 < toJoin.length; i2++) {
-      if (toJoin[i2] instanceof osmWay) {
-        joinAsMembers = false;
-        break;
-      }
+    return new osmEntity().initialize(arguments);
+  }
+  osmEntity.id = function(type2) {
+    return osmEntity.id.fromOSM(type2, osmEntity.id.next[type2]--);
+  };
+  osmEntity.id.next = {
+    changeset: -1,
+    node: -1,
+    way: -1,
+    relation: -1
+  };
+  osmEntity.id.fromOSM = function(type2, id2) {
+    return type2[0] + id2;
+  };
+  osmEntity.id.toOSM = function(id2) {
+    var match = id2.match(/^[cnwr](-?\d+)$/);
+    if (match) {
+      return match[1];
     }
-    var sequences = [];
-    sequences.actions = [];
-    while (toJoin.length) {
-      var item = toJoin.shift();
-      var currWays = [item];
-      var currNodes = resolve(item).slice();
-      while (toJoin.length) {
-        var start2 = currNodes[0];
-        var end = currNodes[currNodes.length - 1];
-        var fn = null;
-        var nodes = null;
-        for (i2 = 0; i2 < toJoin.length; i2++) {
-          item = toJoin[i2];
-          nodes = resolve(item);
-          if (joinAsMembers && currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end && (nodes[nodes.length - 1] === start2 || nodes[0] === start2)) {
-            currWays[0] = reverse(currWays[0]);
-            currNodes.reverse();
-            start2 = currNodes[0];
-            end = currNodes[currNodes.length - 1];
-          }
-          if (nodes[0] === end) {
-            fn = currNodes.push;
-            nodes = nodes.slice(1);
-            break;
-          } else if (nodes[nodes.length - 1] === end) {
-            fn = currNodes.push;
-            nodes = nodes.slice(0, -1).reverse();
-            item = reverse(item);
-            break;
-          } else if (nodes[nodes.length - 1] === start2) {
-            fn = currNodes.unshift;
-            nodes = nodes.slice(0, -1);
-            break;
-          } else if (nodes[0] === start2) {
-            fn = currNodes.unshift;
-            nodes = nodes.slice(1).reverse();
-            item = reverse(item);
-            break;
-          } else {
-            fn = nodes = null;
+    return "";
+  };
+  osmEntity.id.type = function(id2) {
+    return { "c": "changeset", "n": "node", "w": "way", "r": "relation" }[id2[0]];
+  };
+  osmEntity.key = function(entity) {
+    return entity.id + "v" + (entity.v || 0);
+  };
+  var _deprecatedTagValuesByKey;
+  osmEntity.deprecatedTagValuesByKey = function(dataDeprecated) {
+    if (!_deprecatedTagValuesByKey) {
+      _deprecatedTagValuesByKey = {};
+      dataDeprecated.forEach(function(d) {
+        var oldKeys = Object.keys(d.old);
+        if (oldKeys.length === 1) {
+          var oldKey = oldKeys[0];
+          var oldValue = d.old[oldKey];
+          if (oldValue !== "*") {
+            if (!_deprecatedTagValuesByKey[oldKey]) {
+              _deprecatedTagValuesByKey[oldKey] = [oldValue];
+            } else {
+              _deprecatedTagValuesByKey[oldKey].push(oldValue);
+            }
           }
         }
-        if (!nodes) {
-          break;
-        }
-        fn.apply(currWays, [item]);
-        fn.apply(currNodes, nodes);
-        toJoin.splice(i2, 1);
-      }
-      currWays.nodes = currNodes;
-      sequences.push(currWays);
+      });
     }
-    return sequences;
-  }
-
-  // modules/actions/add_member.js
-  function actionAddMember(relationId, member, memberIndex, insertPair) {
-    return function action(graph) {
-      var relation = graph.entity(relationId);
-      var isPTv2 = /stop|platform/.test(member.role);
-      if ((isNaN(memberIndex) || insertPair) && member.type === "way" && !isPTv2) {
-        graph = addWayMember(relation, graph);
-      } else {
-        if (isPTv2 && isNaN(memberIndex)) {
-          memberIndex = 0;
-        }
-        graph = graph.replace(relation.addMember(member, memberIndex));
-      }
-      return graph;
-    };
-    function addWayMember(relation, graph) {
-      var groups, tempWay, insertPairIsReversed, item, i2, j2, k;
-      var PTv2members = [];
-      var members = [];
-      for (i2 = 0; i2 < relation.members.length; i2++) {
-        var m = relation.members[i2];
-        if (/stop|platform/.test(m.role)) {
-          PTv2members.push(m);
-        } else {
-          members.push(m);
-        }
-      }
-      relation = relation.update({ members });
-      if (insertPair) {
-        tempWay = osmWay({ id: "wTemp", nodes: insertPair.nodes });
-        graph = graph.replace(tempWay);
-        var tempMember = { id: tempWay.id, type: "way", role: member.role };
-        var tempRelation = relation.replaceMember({ id: insertPair.originalID }, tempMember, true);
-        groups = utilArrayGroupBy(tempRelation.members, "type");
-        groups.way = groups.way || [];
-        var originalWay = graph.entity(insertPair.originalID);
-        var insertedWay = graph.entity(insertPair.insertedID);
-        insertPairIsReversed = originalWay.nodes.length > 0 && insertedWay.nodes.length > 0 && insertedWay.nodes[insertedWay.nodes.length - 1] === originalWay.nodes[0] && originalWay.nodes[originalWay.nodes.length - 1] !== insertedWay.nodes[0];
-      } else {
-        groups = utilArrayGroupBy(relation.members, "type");
-        groups.way = groups.way || [];
-        groups.way.push(member);
-      }
-      members = withIndex(groups.way);
-      var joined = osmJoinWays(members, graph);
-      for (i2 = 0; i2 < joined.length; i2++) {
-        var segment = joined[i2];
-        var nodes = segment.nodes.slice();
-        var startIndex = segment[0].index;
-        for (j2 = 0; j2 < members.length; j2++) {
-          if (members[j2].index === startIndex) {
-            break;
-          }
-        }
-        for (k = 0; k < segment.length; k++) {
-          item = segment[k];
-          var way = graph.entity(item.id);
-          if (tempWay && item.id === tempWay.id) {
-            var reverse = nodes[0].id !== insertPair.nodes[0] ^ insertPairIsReversed;
-            if (reverse) {
-              item.pair = [
-                { id: insertPair.insertedID, type: "way", role: item.role },
-                { id: insertPair.originalID, type: "way", role: item.role }
-              ];
+    return _deprecatedTagValuesByKey;
+  };
+  osmEntity.prototype = {
+    tags: {},
+    initialize: function(sources) {
+      for (var i2 = 0; i2 < sources.length; ++i2) {
+        var source = sources[i2];
+        for (var prop in source) {
+          if (Object.prototype.hasOwnProperty.call(source, prop)) {
+            if (source[prop] === void 0) {
+              delete this[prop];
             } else {
-              item.pair = [
-                { id: insertPair.originalID, type: "way", role: item.role },
-                { id: insertPair.insertedID, type: "way", role: item.role }
-              ];
-            }
-          }
-          if (k > 0) {
-            if (j2 + k >= members.length || item.index !== members[j2 + k].index) {
-              moveMember(members, item.index, j2 + k);
+              this[prop] = source[prop];
             }
           }
-          nodes.splice(0, way.nodes.length - 1);
         }
       }
-      if (tempWay) {
-        graph = graph.remove(tempWay);
+      if (!this.id && this.type) {
+        this.id = osmEntity.id(this.type);
       }
-      var wayMembers = [];
-      for (i2 = 0; i2 < members.length; i2++) {
-        item = members[i2];
-        if (item.index === -1)
-          continue;
-        if (item.pair) {
-          wayMembers.push(item.pair[0]);
-          wayMembers.push(item.pair[1]);
-        } else {
-          wayMembers.push(utilObjectOmit(item, ["index"]));
-        }
+      if (!this.hasOwnProperty("visible")) {
+        this.visible = true;
       }
-      var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
-      return graph.replace(relation.update({ members: newMembers }));
-      function moveMember(arr, findIndex, toIndex) {
-        var i3;
-        for (i3 = 0; i3 < arr.length; i3++) {
-          if (arr[i3].index === findIndex) {
-            break;
-          }
-        }
-        var item2 = Object.assign({}, arr[i3]);
-        arr[i3].index = -1;
-        item2.index = toIndex;
-        arr.splice(toIndex, 0, item2);
+      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);
       }
-      function withIndex(arr) {
-        var result = new Array(arr.length);
-        for (var i3 = 0; i3 < arr.length; i3++) {
-          result[i3] = Object.assign({}, arr[i3]);
-          result[i3].index = i3;
+      return this;
+    },
+    copy: function(resolver, copies) {
+      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;
+    },
+    osmId: function() {
+      return osmEntity.id.toOSM(this.id);
+    },
+    isNew: function() {
+      var osmId = osmEntity.id.toOSM(this.id);
+      return osmId.length === 0 || osmId[0] === "-";
+    },
+    update: function(attrs) {
+      return osmEntity(this, attrs, { v: 1 + (this.v || 0) });
+    },
+    mergeTags: function(tags) {
+      var merged = Object.assign({}, this.tags);
+      var changed = false;
+      for (var k in tags) {
+        var t1 = merged[k];
+        var t2 = tags[k];
+        if (!t1) {
+          changed = true;
+          merged[k] = t2;
+        } else if (t1 !== t2) {
+          changed = true;
+          merged[k] = utilUnicodeCharsTruncated(
+            utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(";"),
+            255
+            // avoid exceeding character limit; see also context.maxCharsForTagValue()
+          );
         }
-        return result;
       }
-    }
-  }
-
-  // modules/actions/add_midpoint.js
-  function actionAddMidpoint(midpoint, node) {
-    return function(graph) {
-      graph = graph.replace(node.move(midpoint.loc));
-      var parents = utilArrayIntersection(
-        graph.parentWays(graph.entity(midpoint.edge[0])),
-        graph.parentWays(graph.entity(midpoint.edge[1]))
-      );
-      parents.forEach(function(way) {
-        for (var i2 = 0; i2 < way.nodes.length - 1; i2++) {
-          if (geoEdgeEqual([way.nodes[i2], way.nodes[i2 + 1]], midpoint.edge)) {
-            graph = graph.replace(graph.entity(way.id).addNode(node.id, i2 + 1));
+      return changed ? this.update({ tags: merged }) : this;
+    },
+    intersects: function(extent, resolver) {
+      return this.extent(resolver).intersects(extent);
+    },
+    hasNonGeometryTags: function() {
+      return Object.keys(this.tags).some(function(k) {
+        return k !== "area";
+      });
+    },
+    hasParentRelations: function(resolver) {
+      return resolver.parentRelations(this).length > 0;
+    },
+    hasInterestingTags: function() {
+      return Object.keys(this.tags).some(osmIsInterestingTag);
+    },
+    isHighwayIntersection: function() {
+      return false;
+    },
+    isDegenerate: function() {
+      return true;
+    },
+    deprecatedTags: function(dataDeprecated) {
+      var tags = this.tags;
+      if (Object.keys(tags).length === 0)
+        return [];
+      var deprecated = [];
+      dataDeprecated.forEach(function(d) {
+        var oldKeys = Object.keys(d.old);
+        if (d.replace) {
+          var hasExistingValues = Object.keys(d.replace).some(function(replaceKey) {
+            if (!tags[replaceKey] || d.old[replaceKey])
+              return false;
+            var replaceValue = d.replace[replaceKey];
+            if (replaceValue === "*")
+              return false;
+            if (replaceValue === tags[replaceKey])
+              return false;
+            return true;
+          });
+          if (hasExistingValues)
             return;
+        }
+        var matchesDeprecatedTags = oldKeys.every(function(oldKey) {
+          if (!tags[oldKey])
+            return false;
+          if (d.old[oldKey] === "*")
+            return true;
+          if (d.old[oldKey] === tags[oldKey])
+            return true;
+          var vals = tags[oldKey].split(";").filter(Boolean);
+          if (vals.length === 0) {
+            return false;
+          } else if (vals.length > 1) {
+            return vals.indexOf(d.old[oldKey]) !== -1;
+          } else {
+            if (tags[oldKey] === d.old[oldKey]) {
+              if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
+                var replaceKeys = Object.keys(d.replace);
+                return !replaceKeys.every(function(replaceKey) {
+                  return tags[replaceKey] === d.replace[replaceKey];
+                });
+              } else {
+                return true;
+              }
+            }
           }
+          return false;
+        });
+        if (matchesDeprecatedTags) {
+          deprecated.push(d);
         }
       });
-      return graph;
-    };
-  }
+      return deprecated;
+    }
+  };
 
-  // modules/actions/add_vertex.js
-  function actionAddVertex(wayId, nodeId, index) {
-    return function(graph) {
-      return graph.replace(graph.entity(wayId).addNode(nodeId, index));
+  // modules/osm/lanes.js
+  function osmLanes(entity) {
+    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);
+    var maxspeed = parseMaxspeed(tags);
+    var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
+    var forward = laneDirections.forward;
+    var backward = laneDirections.backward;
+    var bothways = laneDirections.bothways;
+    var turnLanes = {};
+    turnLanes.unspecified = parseTurnLanes(tags["turn:lanes"]);
+    turnLanes.forward = parseTurnLanes(tags["turn:lanes:forward"]);
+    turnLanes.backward = parseTurnLanes(tags["turn:lanes:backward"]);
+    var maxspeedLanes = {};
+    maxspeedLanes.unspecified = parseMaxspeedLanes(tags["maxspeed:lanes"], maxspeed);
+    maxspeedLanes.forward = parseMaxspeedLanes(tags["maxspeed:lanes:forward"], maxspeed);
+    maxspeedLanes.backward = parseMaxspeedLanes(tags["maxspeed:lanes:backward"], maxspeed);
+    var psvLanes = {};
+    psvLanes.unspecified = parseMiscLanes(tags["psv:lanes"]);
+    psvLanes.forward = parseMiscLanes(tags["psv:lanes:forward"]);
+    psvLanes.backward = parseMiscLanes(tags["psv:lanes:backward"]);
+    var busLanes = {};
+    busLanes.unspecified = parseMiscLanes(tags["bus:lanes"]);
+    busLanes.forward = parseMiscLanes(tags["bus:lanes:forward"]);
+    busLanes.backward = parseMiscLanes(tags["bus:lanes:backward"]);
+    var taxiLanes = {};
+    taxiLanes.unspecified = parseMiscLanes(tags["taxi:lanes"]);
+    taxiLanes.forward = parseMiscLanes(tags["taxi:lanes:forward"]);
+    taxiLanes.backward = parseMiscLanes(tags["taxi:lanes:backward"]);
+    var hovLanes = {};
+    hovLanes.unspecified = parseMiscLanes(tags["hov:lanes"]);
+    hovLanes.forward = parseMiscLanes(tags["hov:lanes:forward"]);
+    hovLanes.backward = parseMiscLanes(tags["hov:lanes:backward"]);
+    var hgvLanes = {};
+    hgvLanes.unspecified = parseMiscLanes(tags["hgv:lanes"]);
+    hgvLanes.forward = parseMiscLanes(tags["hgv:lanes:forward"]);
+    hgvLanes.backward = parseMiscLanes(tags["hgv:lanes:backward"]);
+    var bicyclewayLanes = {};
+    bicyclewayLanes.unspecified = parseBicycleWay(tags["bicycleway:lanes"]);
+    bicyclewayLanes.forward = parseBicycleWay(tags["bicycleway:lanes:forward"]);
+    bicyclewayLanes.backward = parseBicycleWay(tags["bicycleway:lanes:backward"]);
+    var lanesObj = {
+      forward: [],
+      backward: [],
+      unspecified: []
     };
-  }
-
-  // modules/actions/change_member.js
-  function actionChangeMember(relationId, member, memberIndex) {
-    return function(graph) {
-      return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
+    mapToLanesObj(lanesObj, turnLanes, "turnLane");
+    mapToLanesObj(lanesObj, maxspeedLanes, "maxspeed");
+    mapToLanesObj(lanesObj, psvLanes, "psv");
+    mapToLanesObj(lanesObj, busLanes, "bus");
+    mapToLanesObj(lanesObj, taxiLanes, "taxi");
+    mapToLanesObj(lanesObj, hovLanes, "hov");
+    mapToLanesObj(lanesObj, hgvLanes, "hgv");
+    mapToLanesObj(lanesObj, bicyclewayLanes, "bicycleway");
+    return {
+      metadata: {
+        count: laneCount,
+        oneway: isOneWay,
+        forward,
+        backward,
+        bothways,
+        turnLanes,
+        maxspeed,
+        maxspeedLanes,
+        psvLanes,
+        busLanes,
+        taxiLanes,
+        hovLanes,
+        hgvLanes,
+        bicyclewayLanes
+      },
+      lanes: lanesObj
     };
   }
-
-  // modules/actions/change_preset.js
-  function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
-    return function action(graph) {
-      var entity = graph.entity(entityID);
-      var geometry = entity.geometry(graph);
-      var tags = entity.tags;
-      if (oldPreset)
-        tags = oldPreset.unsetTags(tags, geometry, newPreset && newPreset.addTags ? Object.keys(newPreset.addTags) : null);
-      if (newPreset)
-        tags = newPreset.setTags(tags, geometry, skipFieldDefaults);
-      return graph.replace(entity.update({ tags }));
-    };
+  function getLaneCount(tags, isOneWay) {
+    var count;
+    if (tags.lanes) {
+      count = parseInt(tags.lanes, 10);
+      if (count > 0) {
+        return count;
+      }
+    }
+    switch (tags.highway) {
+      case "trunk":
+      case "motorway":
+        count = isOneWay ? 2 : 4;
+        break;
+      default:
+        count = isOneWay ? 1 : 2;
+        break;
+    }
+    return count;
   }
-
-  // modules/actions/change_tags.js
-  function actionChangeTags(entityId, tags) {
-    return function(graph) {
-      var entity = graph.entity(entityId);
-      return graph.replace(entity.update({ tags }));
+  function parseMaxspeed(tags) {
+    var maxspeed = tags.maxspeed;
+    if (!maxspeed)
+      return;
+    var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
+    if (!maxspeedRegex.test(maxspeed))
+      return;
+    return parseInt(maxspeed, 10);
+  }
+  function parseLaneDirections(tags, isOneWay, laneCount) {
+    var forward = parseInt(tags["lanes:forward"], 10);
+    var backward = parseInt(tags["lanes:backward"], 10);
+    var bothways = parseInt(tags["lanes:both_ways"], 10) > 0 ? 1 : 0;
+    if (parseInt(tags.oneway, 10) === -1) {
+      forward = 0;
+      bothways = 0;
+      backward = laneCount;
+    } else if (isOneWay) {
+      forward = laneCount;
+      bothways = 0;
+      backward = 0;
+    } else if (isNaN(forward) && isNaN(backward)) {
+      backward = Math.floor((laneCount - bothways) / 2);
+      forward = laneCount - bothways - backward;
+    } else if (isNaN(forward)) {
+      if (backward > laneCount - bothways) {
+        backward = laneCount - bothways;
+      }
+      forward = laneCount - bothways - backward;
+    } else if (isNaN(backward)) {
+      if (forward > laneCount - bothways) {
+        forward = laneCount - bothways;
+      }
+      backward = laneCount - bothways - forward;
+    }
+    return {
+      forward,
+      backward,
+      bothways
     };
   }
+  function parseTurnLanes(tag) {
+    if (!tag)
+      return;
+    var validValues = [
+      "left",
+      "slight_left",
+      "sharp_left",
+      "through",
+      "right",
+      "slight_right",
+      "sharp_right",
+      "reverse",
+      "merge_to_left",
+      "merge_to_right",
+      "none"
+    ];
+    return tag.split("|").map(function(s) {
+      if (s === "")
+        s = "none";
+      return s.split(";").map(function(d) {
+        return validValues.indexOf(d) === -1 ? "unknown" : d;
+      });
+    });
+  }
+  function parseMaxspeedLanes(tag, maxspeed) {
+    if (!tag)
+      return;
+    return tag.split("|").map(function(s) {
+      if (s === "none")
+        return s;
+      var m = parseInt(s, 10);
+      if (s === "" || m === maxspeed)
+        return null;
+      return isNaN(m) ? "unknown" : m;
+    });
+  }
+  function parseMiscLanes(tag) {
+    if (!tag)
+      return;
+    var validValues = [
+      "yes",
+      "no",
+      "designated"
+    ];
+    return tag.split("|").map(function(s) {
+      if (s === "")
+        s = "no";
+      return validValues.indexOf(s) === -1 ? "unknown" : s;
+    });
+  }
+  function parseBicycleWay(tag) {
+    if (!tag)
+      return;
+    var validValues = [
+      "yes",
+      "no",
+      "designated",
+      "lane"
+    ];
+    return tag.split("|").map(function(s) {
+      if (s === "")
+        s = "no";
+      return validValues.indexOf(s) === -1 ? "unknown" : s;
+    });
+  }
+  function mapToLanesObj(lanesObj, data, key) {
+    if (data.forward) {
+      data.forward.forEach(function(l, i2) {
+        if (!lanesObj.forward[i2])
+          lanesObj.forward[i2] = {};
+        lanesObj.forward[i2][key] = l;
+      });
+    }
+    if (data.backward) {
+      data.backward.forEach(function(l, i2) {
+        if (!lanesObj.backward[i2])
+          lanesObj.backward[i2] = {};
+        lanesObj.backward[i2][key] = l;
+      });
+    }
+    if (data.unspecified) {
+      data.unspecified.forEach(function(l, i2) {
+        if (!lanesObj.unspecified[i2])
+          lanesObj.unspecified[i2] = {};
+        lanesObj.unspecified[i2][key] = l;
+      });
+    }
+  }
 
-  // modules/osm/node.js
-  var cardinal = {
-    north: 0,
-    n: 0,
-    northnortheast: 22,
-    nne: 22,
-    northeast: 45,
-    ne: 45,
-    eastnortheast: 67,
-    ene: 67,
-    east: 90,
-    e: 90,
-    eastsoutheast: 112,
-    ese: 112,
-    southeast: 135,
-    se: 135,
-    southsoutheast: 157,
-    sse: 157,
-    south: 180,
-    s: 180,
-    southsouthwest: 202,
-    ssw: 202,
-    southwest: 225,
-    sw: 225,
-    westsouthwest: 247,
-    wsw: 247,
-    west: 270,
-    w: 270,
-    westnorthwest: 292,
-    wnw: 292,
-    northwest: 315,
-    nw: 315,
-    northnorthwest: 337,
-    nnw: 337
-  };
-  function osmNode() {
-    if (!(this instanceof osmNode)) {
-      return new osmNode().initialize(arguments);
+  // modules/osm/way.js
+  function osmWay() {
+    if (!(this instanceof osmWay)) {
+      return new osmWay().initialize(arguments);
     } else if (arguments.length) {
       this.initialize(arguments);
     }
   }
-  osmEntity.node = osmNode;
-  osmNode.prototype = Object.create(osmEntity.prototype);
-  Object.assign(osmNode.prototype, {
-    type: "node",
-    loc: [9999, 9999],
-    extent: function() {
-      return new geoExtent(this.loc);
-    },
-    geometry: function(graph) {
-      return graph.transient(this, "geometry", function() {
-        return graph.isPoi(this) ? "point" : "vertex";
-      });
-    },
-    move: function(loc) {
-      return this.update({ loc });
-    },
-    isDegenerate: function() {
-      return !(Array.isArray(this.loc) && this.loc.length === 2 && this.loc[0] >= -180 && this.loc[0] <= 180 && this.loc[1] >= -90 && this.loc[1] <= 90);
-    },
-    directions: function(resolver, projection2) {
-      var val;
-      var i2;
-      if (this.isHighwayIntersection(resolver) && (this.tags.stop || "").toLowerCase() === "all") {
-        val = "all";
-      } else {
-        val = (this.tags.direction || "").toLowerCase();
-        var re2 = /:direction$/i;
-        var keys = Object.keys(this.tags);
-        for (i2 = 0; i2 < keys.length; i2++) {
-          if (re2.test(keys[i2])) {
-            val = this.tags[keys[i2]].toLowerCase();
-            break;
-          }
-        }
-      }
-      if (val === "")
-        return [];
-      var values = val.split(";");
-      var results = [];
-      values.forEach(function(v) {
-        if (cardinal[v] !== void 0) {
-          v = cardinal[v];
-        }
-        if (v !== "" && !isNaN(+v)) {
-          results.push(+v);
-          return;
-        }
-        var lookBackward = this.tags["traffic_sign:backward"] || v === "backward" || v === "both" || v === "all";
-        var lookForward = this.tags["traffic_sign:forward"] || v === "forward" || v === "both" || v === "all";
-        if (!lookForward && !lookBackward)
-          return;
-        var nodeIds = {};
-        resolver.parentWays(this).forEach(function(parent) {
-          var nodes = parent.nodes;
-          for (i2 = 0; i2 < nodes.length; i2++) {
-            if (nodes[i2] === this.id) {
-              if (lookForward && i2 > 0) {
-                nodeIds[nodes[i2 - 1]] = true;
-              }
-              if (lookBackward && i2 < nodes.length - 1) {
-                nodeIds[nodes[i2 + 1]] = true;
-              }
-            }
-          }
-        }, this);
-        Object.keys(nodeIds).forEach(function(nodeId) {
-          results.push(
-            geoAngle(this, resolver.entity(nodeId), projection2) * (180 / Math.PI) + 90
-          );
-        }, this);
-      }, this);
-      return utilArrayUniq(results);
-    },
-    isCrossing: function() {
-      return this.tags.highway === "crossing" || this.tags.railway && this.tags.railway.indexOf("crossing") !== -1;
-    },
-    isEndpoint: function(resolver) {
-      return resolver.transient(this, "isEndpoint", function() {
-        var id2 = this.id;
-        return resolver.parentWays(this).filter(function(parent) {
-          return !parent.isClosed() && !!parent.affix(id2);
-        }).length > 0;
+  osmEntity.way = osmWay;
+  osmWay.prototype = Object.create(osmEntity.prototype);
+  Object.assign(osmWay.prototype, {
+    type: "way",
+    nodes: [],
+    copy: function(resolver, copies) {
+      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;
       });
+      copy2 = copy2.update({ nodes });
+      copies[this.id] = copy2;
+      return copy2;
     },
-    isConnected: function(resolver) {
-      return resolver.transient(this, "isConnected", function() {
-        var parents = resolver.parentWays(this);
-        if (parents.length > 1) {
-          for (var i2 in parents) {
-            if (parents[i2].geometry(resolver) === "line" && parents[i2].hasInterestingTags())
-              return true;
-          }
-        } else if (parents.length === 1) {
-          var way = parents[0];
-          var nodes = way.nodes.slice();
-          if (way.isClosed()) {
-            nodes.pop();
+    extent: function(resolver) {
+      return resolver.transient(this, "extent", function() {
+        var extent = geoExtent();
+        for (var i2 = 0; i2 < this.nodes.length; i2++) {
+          var node = resolver.hasEntity(this.nodes[i2]);
+          if (node) {
+            extent._extend(node.extent());
           }
-          return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
         }
-        return false;
+        return extent;
       });
     },
-    parentIntersectionWays: function(resolver) {
-      return resolver.transient(this, "parentIntersectionWays", function() {
-        return resolver.parentWays(this).filter(function(parent) {
-          return (parent.tags.highway || parent.tags.waterway || parent.tags.railway || parent.tags.aeroway) && parent.geometry(resolver) === "line";
-        });
-      });
+    first: function() {
+      return this.nodes[0];
     },
-    isIntersection: function(resolver) {
-      return this.parentIntersectionWays(resolver).length > 1;
+    last: function() {
+      return this.nodes[this.nodes.length - 1];
     },
-    isHighwayIntersection: function(resolver) {
-      return resolver.transient(this, "isHighwayIntersection", function() {
-        return resolver.parentWays(this).filter(function(parent) {
-          return parent.tags.highway && parent.geometry(resolver) === "line";
-        }).length > 1;
-      });
+    contains: function(node) {
+      return this.nodes.indexOf(node) >= 0;
     },
-    isOnAddressLine: function(resolver) {
-      return resolver.transient(this, "isOnAddressLine", function() {
-        return resolver.parentWays(this).filter(function(parent) {
-          return parent.tags.hasOwnProperty("addr:interpolation") && parent.geometry(resolver) === "line";
-        }).length > 0;
-      });
+    affix: function(node) {
+      if (this.nodes[0] === node)
+        return "prefix";
+      if (this.nodes[this.nodes.length - 1] === node)
+        return "suffix";
     },
-    asJXON: function(changeset_id) {
-      var r = {
-        node: {
-          "@id": this.osmId(),
-          "@lon": this.loc[0],
-          "@lat": this.loc[1],
-          "@version": this.version || 0,
-          tag: Object.keys(this.tags).map(function(k) {
-            return { keyAttributes: { k, v: this.tags[k] } };
-          }, this)
+    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;
+      return 0;
+    },
+    // the approximate width of the line based on its tags except its `width` tag
+    impliedLineWidthMeters: function() {
+      var averageWidths = {
+        highway: {
+          // width is for single lane
+          motorway: 5,
+          motorway_link: 5,
+          trunk: 4.5,
+          trunk_link: 4.5,
+          primary: 4,
+          secondary: 4,
+          tertiary: 4,
+          primary_link: 4,
+          secondary_link: 4,
+          tertiary_link: 4,
+          unclassified: 4,
+          road: 4,
+          living_street: 4,
+          bus_guideway: 4,
+          pedestrian: 4,
+          residential: 3.5,
+          service: 3.5,
+          track: 3,
+          cycleway: 2.5,
+          bridleway: 2,
+          corridor: 2,
+          steps: 2,
+          path: 1.5,
+          footway: 1.5
+        },
+        railway: {
+          // width includes ties and rail bed, not just track gauge
+          rail: 2.5,
+          light_rail: 2.5,
+          tram: 2.5,
+          subway: 2.5,
+          monorail: 2.5,
+          funicular: 2.5,
+          disused: 2.5,
+          preserved: 2.5,
+          miniature: 1.5,
+          narrow_gauge: 1.5
+        },
+        waterway: {
+          river: 50,
+          canal: 25,
+          stream: 5,
+          tidal_channel: 5,
+          fish_pass: 2.5,
+          drain: 2.5,
+          ditch: 1.5
         }
       };
-      if (changeset_id)
-        r.node["@changeset"] = changeset_id;
-      return r;
+      for (var key in averageWidths) {
+        if (this.tags[key] && averageWidths[key][this.tags[key]]) {
+          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;
+            return width * laneCount;
+          }
+          return width;
+        }
+      }
+      return null;
     },
-    asGeoJSON: function() {
-      return {
-        type: "Point",
-        coordinates: this.loc
+    isOneWay: function() {
+      var values = {
+        "yes": true,
+        "1": true,
+        "-1": true,
+        "reversible": true,
+        "alternating": true,
+        "no": false,
+        "0": false
       };
-    }
-  });
-
-  // modules/actions/circularize.js
-  function actionCircularize(wayId, projection2, maxAngle) {
-    maxAngle = (maxAngle || 20) * Math.PI / 180;
-    var action = function(graph, t) {
-      if (t === null || !isFinite(t))
-        t = 1;
-      t = Math.min(Math.max(+t, 0), 1);
-      var way = graph.entity(wayId);
-      var origNodes = {};
-      graph.childNodes(way).forEach(function(node2) {
-        if (!origNodes[node2.id])
-          origNodes[node2.id] = node2;
-      });
-      if (!way.isConvex(graph)) {
-        graph = action.makeConvex(graph);
-      }
-      var nodes = utilArrayUniq(graph.childNodes(way));
-      var keyNodes = nodes.filter(function(n2) {
-        return graph.parentWays(n2).length !== 1;
-      });
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var keyPoints = keyNodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : centroid_default2(points);
-      var radius = median(points, function(p) {
-        return geoVecLength(centroid, p);
-      });
-      var sign2 = area_default3(points) > 0 ? 1 : -1;
-      var ids, i2, j2, k;
-      if (!keyNodes.length) {
-        keyNodes = [nodes[0]];
-        keyPoints = [points[0]];
-      }
-      if (keyNodes.length === 1) {
-        var index = nodes.indexOf(keyNodes[0]);
-        var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
-        keyNodes.push(nodes[oppositeIndex]);
-        keyPoints.push(points[oppositeIndex]);
+      if (values[this.tags.oneway] !== void 0) {
+        return values[this.tags.oneway];
       }
-      for (i2 = 0; i2 < keyPoints.length; i2++) {
-        var nextKeyNodeIndex = (i2 + 1) % keyNodes.length;
-        var startNode = keyNodes[i2];
-        var endNode = keyNodes[nextKeyNodeIndex];
-        var startNodeIndex = nodes.indexOf(startNode);
-        var endNodeIndex = nodes.indexOf(endNode);
-        var numberNewPoints = -1;
-        var indexRange = endNodeIndex - startNodeIndex;
-        var nearNodes = {};
-        var inBetweenNodes = [];
-        var startAngle, endAngle, totalAngle, eachAngle;
-        var angle2, loc, node, origNode;
-        if (indexRange < 0) {
-          indexRange += nodes.length;
-        }
-        var distance = geoVecLength(centroid, keyPoints[i2]) || 1e-4;
-        keyPoints[i2] = [
-          centroid[0] + (keyPoints[i2][0] - centroid[0]) / distance * radius,
-          centroid[1] + (keyPoints[i2][1] - centroid[1]) / distance * radius
-        ];
-        loc = projection2.invert(keyPoints[i2]);
-        node = keyNodes[i2];
-        origNode = origNodes[node.id];
-        node = node.move(geoVecInterp(origNode.loc, loc, t));
-        graph = graph.replace(node);
-        startAngle = Math.atan2(keyPoints[i2][1] - centroid[1], keyPoints[i2][0] - centroid[0]);
-        endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
-        totalAngle = endAngle - startAngle;
-        if (totalAngle * sign2 > 0) {
-          totalAngle = -sign2 * (2 * Math.PI - Math.abs(totalAngle));
-        }
-        do {
-          numberNewPoints++;
-          eachAngle = totalAngle / (indexRange + numberNewPoints);
-        } while (Math.abs(eachAngle) > maxAngle);
-        for (j2 = 1; j2 < indexRange; j2++) {
-          angle2 = startAngle + j2 * eachAngle;
-          loc = projection2.invert([
-            centroid[0] + Math.cos(angle2) * radius,
-            centroid[1] + Math.sin(angle2) * radius
-          ]);
-          node = nodes[(j2 + startNodeIndex) % nodes.length];
-          origNode = origNodes[node.id];
-          nearNodes[node.id] = angle2;
-          node = node.move(geoVecInterp(origNode.loc, loc, t));
-          graph = graph.replace(node);
-        }
-        for (j2 = 0; j2 < numberNewPoints; j2++) {
-          angle2 = startAngle + (indexRange + j2) * eachAngle;
-          loc = projection2.invert([
-            centroid[0] + Math.cos(angle2) * radius,
-            centroid[1] + Math.sin(angle2) * radius
-          ]);
-          var min3 = Infinity;
-          for (var nodeId in nearNodes) {
-            var nearAngle = nearNodes[nodeId];
-            var dist = Math.abs(nearAngle - angle2);
-            if (dist < min3) {
-              min3 = dist;
-              origNode = origNodes[nodeId];
-            }
-          }
-          node = osmNode({ loc: geoVecInterp(origNode.loc, loc, t) });
-          graph = graph.replace(node);
-          nodes.splice(endNodeIndex + j2, 0, node);
-          inBetweenNodes.push(node.id);
+      for (var key in this.tags) {
+        if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) {
+          return true;
         }
-        if (indexRange === 1 && inBetweenNodes.length) {
-          var startIndex1 = way.nodes.lastIndexOf(startNode.id);
-          var endIndex1 = way.nodes.lastIndexOf(endNode.id);
-          var wayDirection1 = endIndex1 - startIndex1;
-          if (wayDirection1 < -1) {
-            wayDirection1 = 1;
-          }
-          var parentWays = graph.parentWays(keyNodes[i2]);
-          for (j2 = 0; j2 < parentWays.length; j2++) {
-            var sharedWay = parentWays[j2];
-            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);
-              var wayDirection2 = endIndex2 - startIndex2;
-              var insertAt = endIndex2;
-              if (wayDirection2 < -1) {
-                wayDirection2 = 1;
-              }
-              if (wayDirection1 !== wayDirection2) {
-                inBetweenNodes.reverse();
-                insertAt = startIndex2;
-              }
-              for (k = 0; k < inBetweenNodes.length; k++) {
-                sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k);
-              }
-              graph = graph.replace(sharedWay);
-            }
+      }
+      return false;
+    },
+    // Some identifier for tag that implies that this way is "sided",
+    // i.e. the right side is the 'inside' (e.g. the right side of a
+    // natural=cliff is lower).
+    sidednessIdentifier: function() {
+      for (const realKey in this.tags) {
+        const value = this.tags[realKey];
+        const key = osmRemoveLifecyclePrefix(realKey);
+        if (key in osmRightSideIsInsideTags && value in osmRightSideIsInsideTags[key]) {
+          if (osmRightSideIsInsideTags[key][value] === true) {
+            return key;
+          } else {
+            return osmRightSideIsInsideTags[key][value];
           }
         }
       }
-      ids = nodes.map(function(n2) {
-        return n2.id;
-      });
-      ids.push(ids[0]);
-      way = way.update({ nodes: ids });
-      graph = graph.replace(way);
-      return graph;
-    };
-    action.makeConvex = function(graph) {
-      var way = graph.entity(wayId);
-      var nodes = utilArrayUniq(graph.childNodes(way));
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var sign2 = area_default3(points) > 0 ? 1 : -1;
-      var hull = hull_default(points);
-      var i2, j2;
-      if (sign2 === -1) {
-        nodes.reverse();
-        points.reverse();
+      return null;
+    },
+    isSided: function() {
+      if (this.tags.two_sided === "yes") {
+        return false;
       }
-      for (i2 = 0; i2 < hull.length - 1; i2++) {
-        var startIndex = points.indexOf(hull[i2]);
-        var endIndex = points.indexOf(hull[i2 + 1]);
-        var indexRange = endIndex - startIndex;
-        if (indexRange < 0) {
-          indexRange += nodes.length;
-        }
-        for (j2 = 1; j2 < indexRange; j2++) {
-          var point = geoVecInterp(hull[i2], hull[i2 + 1], j2 / indexRange);
-          var node = nodes[(j2 + startIndex) % nodes.length].move(projection2.invert(point));
-          graph = graph.replace(node);
+      return this.sidednessIdentifier() !== null;
+    },
+    lanes: function() {
+      return osmLanes(this);
+    },
+    isClosed: function() {
+      return this.nodes.length > 1 && this.first() === this.last();
+    },
+    isConvex: function(resolver) {
+      if (!this.isClosed() || this.isDegenerate())
+        return null;
+      var nodes = utilArrayUniq(resolver.childNodes(this));
+      var coords = nodes.map(function(n2) {
+        return n2.loc;
+      });
+      var curr = 0;
+      var prev = 0;
+      for (var i2 = 0; i2 < coords.length; i2++) {
+        var o = coords[(i2 + 1) % coords.length];
+        var a = coords[i2];
+        var b = coords[(i2 + 2) % coords.length];
+        var res = geoVecCross(a, b, o);
+        curr = res > 0 ? 1 : res < 0 ? -1 : 0;
+        if (curr === 0) {
+          continue;
+        } else if (prev && curr !== prev) {
+          return false;
         }
+        prev = curr;
       }
-      return graph;
-    };
-    action.disabled = function(graph) {
-      if (!graph.entity(wayId).isClosed()) {
-        return "not_closed";
+      return true;
+    },
+    // returns an object with the tag that implies this is an area, if any
+    tagSuggestingArea: function() {
+      return osmTagSuggestingArea(this.tags);
+    },
+    isArea: function() {
+      if (this.tags.area === "yes")
+        return true;
+      if (!this.isClosed() || this.tags.area === "no")
+        return false;
+      return this.tagSuggestingArea() !== null;
+    },
+    isDegenerate: function() {
+      return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
+    },
+    areAdjacent: function(n1, n2) {
+      for (var i2 = 0; i2 < this.nodes.length; i2++) {
+        if (this.nodes[i2] === n1) {
+          if (this.nodes[i2 - 1] === n2)
+            return true;
+          if (this.nodes[i2 + 1] === n2)
+            return true;
+        }
       }
-      var way = graph.entity(wayId);
-      var nodes = utilArrayUniq(graph.childNodes(way));
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
+      return false;
+    },
+    geometry: function(graph) {
+      return graph.transient(this, "geometry", function() {
+        return this.isArea() ? "area" : "line";
       });
-      var hull = hull_default(points);
-      var epsilonAngle = Math.PI / 180;
-      if (hull.length !== points.length || hull.length < 3) {
-        return false;
+    },
+    // returns an array of objects representing the segments between the nodes in this way
+    segments: function(graph) {
+      function segmentExtent(graph2) {
+        var n1 = graph2.hasEntity(this.nodes[0]);
+        var n2 = graph2.hasEntity(this.nodes[1]);
+        return n1 && n2 && geoExtent([
+          [
+            Math.min(n1.loc[0], n2.loc[0]),
+            Math.min(n1.loc[1], n2.loc[1])
+          ],
+          [
+            Math.max(n1.loc[0], n2.loc[0]),
+            Math.max(n1.loc[1], n2.loc[1])
+          ]
+        ]);
       }
-      var centroid = centroid_default2(points);
-      var radius = geoVecLengthSquare(centroid, points[0]);
-      var i2, actualPoint;
-      for (i2 = 0; i2 < hull.length; i2++) {
-        actualPoint = hull[i2];
-        var actualDist = geoVecLengthSquare(actualPoint, centroid);
-        var diff = Math.abs(actualDist - radius);
-        if (diff > 0.05 * radius) {
-          return false;
+      return graph.transient(this, "segments", function() {
+        var segments = [];
+        for (var i2 = 0; i2 < this.nodes.length - 1; i2++) {
+          segments.push({
+            id: this.id + "-" + i2,
+            wayId: this.id,
+            index: i2,
+            nodes: [this.nodes[i2], this.nodes[i2 + 1]],
+            extent: segmentExtent
+          });
         }
+        return segments;
+      });
+    },
+    // 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;
+      var nodes = this.nodes.slice();
+      nodes = nodes.filter(noRepeatNodes);
+      nodes.push(nodes[0]);
+      return this.update({ nodes });
+    },
+    // 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;
+      var nodes = this.nodes.slice();
+      var connector = this.first();
+      var i2 = nodes.length - 1;
+      while (i2 > 0 && nodes.length > 1 && nodes[i2] === connector) {
+        nodes.splice(i2, 1);
+        i2 = nodes.length - 1;
       }
-      for (i2 = 0; i2 < hull.length; i2++) {
-        actualPoint = hull[i2];
-        var nextPoint = hull[(i2 + 1) % hull.length];
-        var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
-        var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
-        var angle2 = endAngle - startAngle;
-        if (angle2 < 0) {
-          angle2 = -angle2;
+      nodes = nodes.filter(noRepeatNodes);
+      return this.update({ nodes });
+    },
+    // Adds a node (id) in front of the node which is currently at position index.
+    // If index is undefined, the node will be added to the end of the way for linear ways,
+    //   or just before the final connecting node for circular ways.
+    // Consecutive duplicates are eliminated including existing ones.
+    // Circularity is always preserved when adding a node.
+    addNode: function(id2, index) {
+      var nodes = this.nodes.slice();
+      var isClosed = this.isClosed();
+      var max3 = isClosed ? nodes.length - 1 : nodes.length;
+      if (index === void 0) {
+        index = max3;
+      }
+      if (index < 0 || index > max3) {
+        throw new RangeError("index " + index + " out of range 0.." + max3);
+      }
+      if (isClosed) {
+        var connector = this.first();
+        var i2 = 1;
+        while (i2 < nodes.length && nodes.length > 2 && nodes[i2] === connector) {
+          nodes.splice(i2, 1);
+          if (index > i2)
+            index--;
         }
-        if (angle2 > Math.PI) {
-          angle2 = 2 * Math.PI - angle2;
+        i2 = nodes.length - 1;
+        while (i2 > 0 && nodes.length > 1 && nodes[i2] === connector) {
+          nodes.splice(i2, 1);
+          if (index > i2)
+            index--;
+          i2 = nodes.length - 1;
         }
-        if (angle2 > maxAngle + epsilonAngle) {
-          return false;
+      }
+      nodes.splice(index, 0, id2);
+      nodes = nodes.filter(noRepeatNodes);
+      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
+        nodes.push(nodes[0]);
+      }
+      return this.update({ nodes });
+    },
+    // Replaces the node which is currently at position index with the given node (id).
+    // Consecutive duplicates are eliminated including existing ones.
+    // Circularity is preserved when updating a node.
+    updateNode: function(id2, index) {
+      var nodes = this.nodes.slice();
+      var isClosed = this.isClosed();
+      var max3 = nodes.length - 1;
+      if (index === void 0 || index < 0 || index > max3) {
+        throw new RangeError("index " + index + " out of range 0.." + max3);
+      }
+      if (isClosed) {
+        var connector = this.first();
+        var i2 = 1;
+        while (i2 < nodes.length && nodes.length > 2 && nodes[i2] === connector) {
+          nodes.splice(i2, 1);
+          if (index > i2)
+            index--;
+        }
+        i2 = nodes.length - 1;
+        while (i2 > 0 && nodes.length > 1 && nodes[i2] === connector) {
+          nodes.splice(i2, 1);
+          if (index === i2)
+            index = 0;
+          i2 = nodes.length - 1;
         }
       }
-      return "already_circular";
-    };
-    action.transitionable = true;
-    return action;
-  }
-
-  // modules/actions/delete_way.js
-  function actionDeleteWay(wayID) {
-    function canDeleteNode(node, graph) {
-      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;
-      return !node.hasInterestingTags();
-    }
-    var action = function(graph) {
-      var way = graph.entity(wayID);
-      graph.parentRelations(way).forEach(function(parent) {
-        parent = parent.removeMembersWithID(wayID);
-        graph = graph.replace(parent);
-        if (parent.isDegenerate()) {
-          graph = actionDeleteRelation(parent.id)(graph);
+      nodes.splice(index, 1, id2);
+      nodes = nodes.filter(noRepeatNodes);
+      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
+        nodes.push(nodes[0]);
+      }
+      return this.update({ nodes });
+    },
+    // Replaces each occurrence of node id needle with replacement.
+    // Consecutive duplicates are eliminated including existing ones.
+    // Circularity is preserved.
+    replaceNode: function(needleID, replacementID) {
+      var nodes = this.nodes.slice();
+      var isClosed = this.isClosed();
+      for (var i2 = 0; i2 < nodes.length; i2++) {
+        if (nodes[i2] === needleID) {
+          nodes[i2] = replacementID;
         }
-      });
-      new Set(way.nodes).forEach(function(nodeID) {
-        graph = graph.replace(way.removeNode(nodeID));
-        var node = graph.entity(nodeID);
-        if (canDeleteNode(node, graph)) {
-          graph = graph.remove(node);
+      }
+      nodes = nodes.filter(noRepeatNodes);
+      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
+        nodes.push(nodes[0]);
+      }
+      return this.update({ nodes });
+    },
+    // Removes each occurrence of node id.
+    // Consecutive duplicates are eliminated including existing ones.
+    // Circularity is preserved.
+    removeNode: function(id2) {
+      var nodes = this.nodes.slice();
+      var isClosed = this.isClosed();
+      nodes = nodes.filter(function(node) {
+        return node !== id2;
+      }).filter(noRepeatNodes);
+      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
+        nodes.push(nodes[0]);
+      }
+      return this.update({ nodes });
+    },
+    asJXON: function(changeset_id) {
+      var r = {
+        way: {
+          "@id": this.osmId(),
+          "@version": this.version || 0,
+          nd: this.nodes.map(function(id2) {
+            return { keyAttributes: { ref: osmEntity.id.toOSM(id2) } };
+          }, this),
+          tag: Object.keys(this.tags).map(function(k) {
+            return { keyAttributes: { k, v: this.tags[k] } };
+          }, this)
         }
-      });
-      return graph.remove(way);
-    };
-    return action;
-  }
-
-  // modules/actions/delete_multiple.js
-  function actionDeleteMultiple(ids) {
-    var actions = {
-      way: actionDeleteWay,
-      node: actionDeleteNode,
-      relation: actionDeleteRelation
-    };
-    var action = function(graph) {
-      ids.forEach(function(id2) {
-        if (graph.hasEntity(id2)) {
-          graph = actions[graph.entity(id2).type](id2)(graph);
+      };
+      if (changeset_id) {
+        r.way["@changeset"] = changeset_id;
+      }
+      return r;
+    },
+    asGeoJSON: function(resolver) {
+      return resolver.transient(this, "GeoJSON", function() {
+        var coordinates = resolver.childNodes(this).map(function(n2) {
+          return n2.loc;
+        });
+        if (this.isArea() && this.isClosed()) {
+          return {
+            type: "Polygon",
+            coordinates: [coordinates]
+          };
+        } else {
+          return {
+            type: "LineString",
+            coordinates
+          };
         }
       });
-      return graph;
-    };
-    return action;
-  }
-
-  // modules/actions/delete_relation.js
-  function actionDeleteRelation(relationID, allowUntaggedMembers) {
-    function canDeleteEntity(entity, graph) {
-      return !graph.parentWays(entity).length && !graph.parentRelations(entity).length && (!entity.hasInterestingTags() && !allowUntaggedMembers);
-    }
-    var action = function(graph) {
-      var relation = graph.entity(relationID);
-      graph.parentRelations(relation).forEach(function(parent) {
-        parent = parent.removeMembersWithID(relationID);
-        graph = graph.replace(parent);
-        if (parent.isDegenerate()) {
-          graph = actionDeleteRelation(parent.id)(graph);
+    },
+    area: function(resolver) {
+      return resolver.transient(this, "area", function() {
+        var nodes = resolver.childNodes(this);
+        var json = {
+          type: "Polygon",
+          coordinates: [nodes.map(function(n2) {
+            return n2.loc;
+          })]
+        };
+        if (!this.isClosed() && nodes.length) {
+          json.coordinates[0].push(nodes[0].loc);
         }
-      });
-      var memberIDs = utilArrayUniq(relation.members.map(function(m) {
-        return m.id;
-      }));
-      memberIDs.forEach(function(memberID) {
-        graph = graph.replace(relation.removeMembersWithID(memberID));
-        var entity = graph.entity(memberID);
-        if (canDeleteEntity(entity, graph)) {
-          graph = actionDeleteMultiple([memberID])(graph);
+        var area = area_default(json);
+        if (area > 2 * Math.PI) {
+          json.coordinates[0] = json.coordinates[0].reverse();
+          area = area_default(json);
         }
+        return isNaN(area) ? 0 : area;
       });
-      return graph.remove(relation);
-    };
-    return action;
+    }
+  });
+  function noRepeatNodes(node, i2, arr) {
+    return i2 === 0 || node !== arr[i2 - 1];
   }
 
-  // modules/actions/delete_node.js
-  function actionDeleteNode(nodeId) {
-    var action = function(graph) {
-      var node = graph.entity(nodeId);
-      graph.parentWays(node).forEach(function(parent) {
-        parent = parent.removeNode(nodeId);
-        graph = graph.replace(parent);
-        if (parent.isDegenerate()) {
-          graph = actionDeleteWay(parent.id)(graph);
-        }
-      });
-      graph.parentRelations(node).forEach(function(parent) {
-        parent = parent.removeMembersWithID(nodeId);
-        graph = graph.replace(parent);
-        if (parent.isDegenerate()) {
-          graph = actionDeleteRelation(parent.id)(graph);
+  // modules/osm/multipolygon.js
+  function osmOldMultipolygonOuterMemberOfRelation(entity, graph) {
+    if (entity.type !== "relation" || !entity.isMultipolygon() || Object.keys(entity.tags).filter(osmIsInterestingTag).length > 1) {
+      return false;
+    }
+    var outerMember;
+    for (var memberIndex in entity.members) {
+      var member = entity.members[memberIndex];
+      if (!member.role || member.role === "outer") {
+        if (outerMember)
+          return false;
+        if (member.type !== "way")
+          return false;
+        if (!graph.hasEntity(member.id))
+          return false;
+        outerMember = graph.entity(member.id);
+        if (Object.keys(outerMember.tags).filter(osmIsInterestingTag).length === 0) {
+          return false;
         }
-      });
-      return graph.remove(node);
-    };
-    return action;
+      }
+    }
+    return outerMember;
   }
-
-  // modules/actions/connect.js
-  function actionConnect(nodeIDs) {
-    var action = function(graph) {
-      var survivor;
-      var node;
-      var parents;
-      var i2, j2;
-      nodeIDs.reverse();
-      var interestingIDs = [];
-      for (i2 = 0; i2 < nodeIDs.length; i2++) {
-        node = graph.entity(nodeIDs[i2]);
-        if (node.hasInterestingTags()) {
-          if (!node.isNew()) {
-            interestingIDs.push(node.id);
-          }
-        }
+  function osmIsOldMultipolygonOuterMember(entity, graph) {
+    if (entity.type !== "way" || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0) {
+      return false;
+    }
+    var parents = graph.parentRelations(entity);
+    if (parents.length !== 1)
+      return false;
+    var parent = parents[0];
+    if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
+      return false;
+    }
+    var members = parent.members, member;
+    for (var i2 = 0; i2 < members.length; i2++) {
+      member = members[i2];
+      if (member.id === entity.id && member.role && member.role !== "outer") {
+        return false;
       }
-      survivor = graph.entity(utilOldestID(interestingIDs.length > 0 ? interestingIDs : nodeIDs));
-      for (i2 = 0; i2 < nodeIDs.length; i2++) {
-        node = graph.entity(nodeIDs[i2]);
-        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));
+      if (member.id !== entity.id && (!member.role || member.role === "outer")) {
+        return false;
+      }
+    }
+    return parent;
+  }
+  function osmOldMultipolygonOuterMember(entity, graph) {
+    if (entity.type !== "way")
+      return false;
+    var parents = graph.parentRelations(entity);
+    if (parents.length !== 1)
+      return false;
+    var parent = parents[0];
+    if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
+      return false;
+    }
+    var members = parent.members, member, outerMember;
+    for (var i2 = 0; i2 < members.length; i2++) {
+      member = members[i2];
+      if (!member.role || member.role === "outer") {
+        if (outerMember)
+          return false;
+        outerMember = member;
+      }
+    }
+    if (!outerMember)
+      return false;
+    var outerEntity = graph.hasEntity(outerMember.id);
+    if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) {
+      return false;
+    }
+    return outerEntity;
+  }
+  function osmJoinWays(toJoin, graph) {
+    function resolve(member) {
+      return graph.childNodes(graph.entity(member.id));
+    }
+    function reverse(item2) {
+      var action = actionReverse(item2.id, { reverseOneway: true });
+      sequences.actions.push(action);
+      return item2 instanceof osmWay ? action(graph).entity(item2.id) : item2;
+    }
+    toJoin = toJoin.filter(function(member) {
+      return member.type === "way" && graph.hasEntity(member.id);
+    });
+    var i2;
+    var joinAsMembers = true;
+    for (i2 = 0; i2 < toJoin.length; i2++) {
+      if (toJoin[i2] instanceof osmWay) {
+        joinAsMembers = false;
+        break;
+      }
+    }
+    var sequences = [];
+    sequences.actions = [];
+    while (toJoin.length) {
+      var item = toJoin.shift();
+      var currWays = [item];
+      var currNodes = resolve(item).slice();
+      while (toJoin.length) {
+        var start2 = currNodes[0];
+        var end = currNodes[currNodes.length - 1];
+        var fn = null;
+        var nodes = null;
+        for (i2 = 0; i2 < toJoin.length; i2++) {
+          item = toJoin[i2];
+          nodes = resolve(item);
+          if (joinAsMembers && currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end && (nodes[nodes.length - 1] === start2 || nodes[0] === start2)) {
+            currWays[0] = reverse(currWays[0]);
+            currNodes.reverse();
+            start2 = currNodes[0];
+            end = currNodes[currNodes.length - 1];
+          }
+          if (nodes[0] === end) {
+            fn = currNodes.push;
+            nodes = nodes.slice(1);
+            break;
+          } else if (nodes[nodes.length - 1] === end) {
+            fn = currNodes.push;
+            nodes = nodes.slice(0, -1).reverse();
+            item = reverse(item);
+            break;
+          } else if (nodes[nodes.length - 1] === start2) {
+            fn = currNodes.unshift;
+            nodes = nodes.slice(0, -1);
+            break;
+          } else if (nodes[0] === start2) {
+            fn = currNodes.unshift;
+            nodes = nodes.slice(1).reverse();
+            item = reverse(item);
+            break;
+          } else {
+            fn = nodes = null;
+          }
         }
-        parents = graph.parentRelations(node);
-        for (j2 = 0; j2 < parents.length; j2++) {
-          graph = graph.replace(parents[j2].replaceMember(node, survivor));
+        if (!nodes) {
+          break;
         }
-        survivor = survivor.mergeTags(node.tags);
-        graph = actionDeleteNode(node.id)(graph);
+        fn.apply(currWays, [item]);
+        fn.apply(currNodes, nodes);
+        toJoin.splice(i2, 1);
       }
-      graph = graph.replace(survivor);
-      parents = graph.parentWays(survivor);
-      for (i2 = 0; i2 < parents.length; i2++) {
-        if (parents[i2].isDegenerate()) {
-          graph = actionDeleteWay(parents[i2].id)(graph);
+      currWays.nodes = currNodes;
+      sequences.push(currWays);
+    }
+    return sequences;
+  }
+
+  // modules/actions/add_member.js
+  function actionAddMember(relationId, member, memberIndex, insertPair) {
+    return function action(graph) {
+      var relation = graph.entity(relationId);
+      var isPTv2 = /stop|platform/.test(member.role);
+      if ((isNaN(memberIndex) || insertPair) && member.type === "way" && !isPTv2) {
+        graph = addWayMember(relation, graph);
+      } else {
+        if (isPTv2 && isNaN(memberIndex)) {
+          memberIndex = 0;
         }
+        graph = graph.replace(relation.addMember(member, memberIndex));
       }
       return graph;
     };
-    action.disabled = function(graph) {
-      var seen = {};
-      var restrictionIDs = [];
-      var survivor;
-      var node, way;
-      var relations, relation, role;
-      var i2, j2, k;
-      survivor = graph.entity(utilOldestID(nodeIDs));
-      for (i2 = 0; i2 < nodeIDs.length; i2++) {
-        node = graph.entity(nodeIDs[i2]);
-        relations = graph.parentRelations(node);
-        for (j2 = 0; j2 < relations.length; j2++) {
-          relation = relations[j2];
-          role = relation.memberById(node.id).role || "";
-          if (relation.hasFromViaTo()) {
-            restrictionIDs.push(relation.id);
-          }
-          if (seen[relation.id] !== void 0 && seen[relation.id] !== role) {
-            return "relation";
-          } else {
-            seen[relation.id] = role;
-          }
+    function addWayMember(relation, graph) {
+      var groups, tempWay, insertPairIsReversed, item, i2, j2, k;
+      var PTv2members = [];
+      var members = [];
+      for (i2 = 0; i2 < relation.members.length; i2++) {
+        var m = relation.members[i2];
+        if (/stop|platform/.test(m.role)) {
+          PTv2members.push(m);
+        } else {
+          members.push(m);
         }
       }
-      for (i2 = 0; i2 < nodeIDs.length; i2++) {
-        node = graph.entity(nodeIDs[i2]);
-        var parents = graph.parentWays(node);
-        for (j2 = 0; j2 < parents.length; j2++) {
-          var parent = parents[j2];
-          relations = graph.parentRelations(parent);
-          for (k = 0; k < relations.length; k++) {
-            relation = relations[k];
-            if (relation.hasFromViaTo()) {
-              restrictionIDs.push(relation.id);
+      relation = relation.update({ members });
+      if (insertPair) {
+        tempWay = osmWay({ id: "wTemp", nodes: insertPair.nodes });
+        graph = graph.replace(tempWay);
+        var tempMember = { id: tempWay.id, type: "way", role: member.role };
+        var tempRelation = relation.replaceMember({ id: insertPair.originalID }, tempMember, true);
+        groups = utilArrayGroupBy(tempRelation.members, "type");
+        groups.way = groups.way || [];
+        var originalWay = graph.entity(insertPair.originalID);
+        var insertedWay = graph.entity(insertPair.insertedID);
+        insertPairIsReversed = originalWay.nodes.length > 0 && insertedWay.nodes.length > 0 && insertedWay.nodes[insertedWay.nodes.length - 1] === originalWay.nodes[0] && originalWay.nodes[originalWay.nodes.length - 1] !== insertedWay.nodes[0];
+      } else {
+        groups = utilArrayGroupBy(relation.members, "type");
+        groups.way = groups.way || [];
+        groups.way.push(member);
+      }
+      members = withIndex(groups.way);
+      var joined = osmJoinWays(members, graph);
+      for (i2 = 0; i2 < joined.length; i2++) {
+        var segment = joined[i2];
+        var nodes = segment.nodes.slice();
+        var startIndex = segment[0].index;
+        for (j2 = 0; j2 < members.length; j2++) {
+          if (members[j2].index === startIndex) {
+            break;
+          }
+        }
+        for (k = 0; k < segment.length; k++) {
+          item = segment[k];
+          var way = graph.entity(item.id);
+          if (tempWay && item.id === tempWay.id) {
+            var reverse = nodes[0].id !== insertPair.nodes[0] ^ insertPairIsReversed;
+            if (reverse) {
+              item.pair = [
+                { id: insertPair.insertedID, type: "way", role: item.role },
+                { id: insertPair.originalID, type: "way", role: item.role }
+              ];
+            } else {
+              item.pair = [
+                { id: insertPair.originalID, type: "way", role: item.role },
+                { id: insertPair.insertedID, type: "way", role: item.role }
+              ];
+            }
+          }
+          if (k > 0) {
+            if (j2 + k >= members.length || item.index !== members[j2 + k].index) {
+              moveMember(members, item.index, j2 + k);
             }
           }
+          nodes.splice(0, way.nodes.length - 1);
         }
       }
-      restrictionIDs = utilArrayUniq(restrictionIDs);
-      for (i2 = 0; i2 < restrictionIDs.length; i2++) {
-        relation = graph.entity(restrictionIDs[i2]);
-        if (!relation.isComplete(graph))
+      if (tempWay) {
+        graph = graph.remove(tempWay);
+      }
+      var wayMembers = [];
+      for (i2 = 0; i2 < members.length; i2++) {
+        item = members[i2];
+        if (item.index === -1)
           continue;
-        var memberWays = relation.members.filter(function(m) {
-          return m.type === "way";
-        }).map(function(m) {
-          return graph.entity(m.id);
-        });
-        memberWays = utilArrayUniq(memberWays);
-        var f2 = relation.memberByRole("from");
-        var t = relation.memberByRole("to");
-        var isUturn = f2.id === t.id;
-        var nodes = { from: [], via: [], to: [], keyfrom: [], keyto: [] };
-        for (j2 = 0; j2 < relation.members.length; j2++) {
-          collectNodes(relation.members[j2], nodes);
+        if (item.pair) {
+          wayMembers.push(item.pair[0]);
+          wayMembers.push(item.pair[1]);
+        } else {
+          wayMembers.push(utilObjectOmit(item, ["index"]));
         }
-        nodes.keyfrom = utilArrayUniq(nodes.keyfrom.filter(hasDuplicates));
-        nodes.keyto = utilArrayUniq(nodes.keyto.filter(hasDuplicates));
-        var filter2 = keyNodeFilter(nodes.keyfrom, nodes.keyto);
-        nodes.from = nodes.from.filter(filter2);
-        nodes.via = nodes.via.filter(filter2);
-        nodes.to = nodes.to.filter(filter2);
-        var connectFrom = false;
-        var connectVia = false;
-        var connectTo = false;
-        var connectKeyFrom = false;
-        var connectKeyTo = false;
-        for (j2 = 0; j2 < nodeIDs.length; j2++) {
-          var n2 = nodeIDs[j2];
-          if (nodes.from.indexOf(n2) !== -1) {
-            connectFrom = true;
-          }
-          if (nodes.via.indexOf(n2) !== -1) {
-            connectVia = true;
-          }
-          if (nodes.to.indexOf(n2) !== -1) {
-            connectTo = true;
-          }
-          if (nodes.keyfrom.indexOf(n2) !== -1) {
-            connectKeyFrom = true;
-          }
-          if (nodes.keyto.indexOf(n2) !== -1) {
-            connectKeyTo = true;
-          }
-        }
-        if (connectFrom && connectTo && !isUturn) {
-          return "restriction";
-        }
-        if (connectFrom && connectVia) {
-          return "restriction";
-        }
-        if (connectTo && connectVia) {
-          return "restriction";
-        }
-        if (connectKeyFrom || connectKeyTo) {
-          if (nodeIDs.length !== 2) {
-            return "restriction";
-          }
-          var n0 = null;
-          var n1 = null;
-          for (j2 = 0; j2 < memberWays.length; j2++) {
-            way = memberWays[j2];
-            if (way.contains(nodeIDs[0])) {
-              n0 = nodeIDs[0];
-            }
-            if (way.contains(nodeIDs[1])) {
-              n1 = nodeIDs[1];
-            }
-          }
-          if (n0 && n1) {
-            var ok = false;
-            for (j2 = 0; j2 < memberWays.length; j2++) {
-              way = memberWays[j2];
-              if (way.areAdjacent(n0, n1)) {
-                ok = true;
-                break;
-              }
-            }
-            if (!ok) {
-              return "restriction";
-            }
-          }
-        }
-        for (j2 = 0; j2 < memberWays.length; j2++) {
-          way = memberWays[j2].update({});
-          for (k = 0; k < nodeIDs.length; k++) {
-            if (nodeIDs[k] === survivor.id)
-              continue;
-            if (way.areAdjacent(nodeIDs[k], survivor.id)) {
-              way = way.removeNode(nodeIDs[k]);
-            } else {
-              way = way.replaceNode(nodeIDs[k], survivor.id);
-            }
-          }
-          if (way.isDegenerate()) {
-            return "restriction";
+      }
+      var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
+      return graph.replace(relation.update({ members: newMembers }));
+      function moveMember(arr, findIndex, toIndex) {
+        var i3;
+        for (i3 = 0; i3 < arr.length; i3++) {
+          if (arr[i3].index === findIndex) {
+            break;
           }
         }
+        var item2 = Object.assign({}, arr[i3]);
+        arr[i3].index = -1;
+        item2.index = toIndex;
+        arr.splice(toIndex, 0, item2);
       }
-      return false;
-      function hasDuplicates(n3, i3, arr) {
-        return arr.indexOf(n3) !== arr.lastIndexOf(n3);
-      }
-      function keyNodeFilter(froms, tos) {
-        return function(n3) {
-          return froms.indexOf(n3) === -1 && tos.indexOf(n3) === -1;
-        };
-      }
-      function collectNodes(member, collection) {
-        var entity = graph.hasEntity(member.id);
-        if (!entity)
-          return;
-        var role2 = member.role || "";
-        if (!collection[role2]) {
-          collection[role2] = [];
-        }
-        if (member.type === "node") {
-          collection[role2].push(member.id);
-          if (role2 === "via") {
-            collection.keyfrom.push(member.id);
-            collection.keyto.push(member.id);
-          }
-        } else if (member.type === "way") {
-          collection[role2].push.apply(collection[role2], entity.nodes);
-          if (role2 === "from" || role2 === "via") {
-            collection.keyfrom.push(entity.first());
-            collection.keyfrom.push(entity.last());
-          }
-          if (role2 === "to" || role2 === "via") {
-            collection.keyto.push(entity.first());
-            collection.keyto.push(entity.last());
-          }
+      function withIndex(arr) {
+        var result = new Array(arr.length);
+        for (var i3 = 0; i3 < arr.length; i3++) {
+          result[i3] = Object.assign({}, arr[i3]);
+          result[i3].index = i3;
         }
+        return result;
       }
-    };
-    return action;
+    }
   }
 
-  // modules/actions/copy_entities.js
-  function actionCopyEntities(ids, fromGraph) {
-    var _copies = {};
-    var action = function(graph) {
-      ids.forEach(function(id3) {
-        fromGraph.entity(id3).copy(fromGraph, _copies);
+  // modules/actions/add_midpoint.js
+  function actionAddMidpoint(midpoint, node) {
+    return function(graph) {
+      graph = graph.replace(node.move(midpoint.loc));
+      var parents = utilArrayIntersection(
+        graph.parentWays(graph.entity(midpoint.edge[0])),
+        graph.parentWays(graph.entity(midpoint.edge[1]))
+      );
+      parents.forEach(function(way) {
+        for (var i2 = 0; i2 < way.nodes.length - 1; i2++) {
+          if (geoEdgeEqual([way.nodes[i2], way.nodes[i2 + 1]], midpoint.edge)) {
+            graph = graph.replace(graph.entity(way.id).addNode(node.id, i2 + 1));
+            return;
+          }
+        }
       });
-      for (var id2 in _copies) {
-        graph = graph.replace(_copies[id2]);
-      }
       return graph;
     };
-    action.copies = function() {
-      return _copies;
+  }
+
+  // modules/actions/add_vertex.js
+  function actionAddVertex(wayId, nodeId, index) {
+    return function(graph) {
+      return graph.replace(graph.entity(wayId).addNode(nodeId, index));
     };
-    return action;
   }
 
-  // modules/actions/delete_member.js
-  function actionDeleteMember(relationId, memberIndex) {
+  // modules/actions/change_member.js
+  function actionChangeMember(relationId, member, memberIndex) {
     return function(graph) {
-      var relation = graph.entity(relationId).removeMember(memberIndex);
-      graph = graph.replace(relation);
-      if (relation.isDegenerate()) {
-        graph = actionDeleteRelation(relation.id)(graph);
-      }
-      return graph;
+      return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
     };
   }
 
-  // modules/actions/discard_tags.js
-  function actionDiscardTags(difference, discardTags) {
-    discardTags = discardTags || {};
-    return (graph) => {
-      difference.modified().forEach(checkTags);
-      difference.created().forEach(checkTags);
-      return graph;
-      function checkTags(entity) {
-        const keys = Object.keys(entity.tags);
-        let didDiscard = false;
-        let tags = {};
-        for (let i2 = 0; i2 < keys.length; i2++) {
-          const k = keys[i2];
-          if (discardTags[k] || !entity.tags[k]) {
-            didDiscard = true;
-          } else {
-            tags[k] = entity.tags[k];
-          }
+  // modules/actions/change_preset.js
+  function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
+    return function action(graph) {
+      var entity = graph.entity(entityID);
+      var geometry = entity.geometry(graph);
+      var tags = entity.tags;
+      const loc = entity.extent(graph).center();
+      var preserveKeys;
+      if (newPreset) {
+        preserveKeys = [];
+        if (newPreset.addTags) {
+          preserveKeys = preserveKeys.concat(Object.keys(newPreset.addTags));
         }
-        if (didDiscard) {
-          graph = graph.replace(entity.update({ tags }));
+        if (oldPreset && !oldPreset.id.startsWith(newPreset.id)) {
+          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);
+      return graph.replace(entity.update({ tags }));
     };
   }
 
-  // modules/actions/disconnect.js
-  function actionDisconnect(nodeId, newNodeId) {
-    var wayIds;
-    var disconnectableRelationTypes = {
-      "associatedStreet": true,
-      "enforcement": true,
-      "site": true
+  // modules/actions/change_tags.js
+  function actionChangeTags(entityId, tags) {
+    return function(graph) {
+      var entity = graph.entity(entityId);
+      return graph.replace(entity.update({ tags }));
     };
-    var action = function(graph) {
-      var node = graph.entity(nodeId);
-      var connections = action.connections(graph);
-      connections.forEach(function(connection) {
-        var way = graph.entity(connection.wayID);
-        var newNode = osmNode({ id: newNodeId, loc: node.loc, tags: node.tags });
-        graph = graph.replace(newNode);
-        if (connection.index === 0 && way.isArea()) {
-          graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
-        } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
-          graph = graph.replace(way.unclose().addNode(newNode.id));
-        } else {
-          graph = graph.replace(way.updateNode(newNode.id, connection.index));
-        }
+  }
+
+  // modules/osm/node.js
+  var cardinal = {
+    north: 0,
+    n: 0,
+    northnortheast: 22,
+    nne: 22,
+    northeast: 45,
+    ne: 45,
+    eastnortheast: 67,
+    ene: 67,
+    east: 90,
+    e: 90,
+    eastsoutheast: 112,
+    ese: 112,
+    southeast: 135,
+    se: 135,
+    southsoutheast: 157,
+    sse: 157,
+    south: 180,
+    s: 180,
+    southsouthwest: 202,
+    ssw: 202,
+    southwest: 225,
+    sw: 225,
+    westsouthwest: 247,
+    wsw: 247,
+    west: 270,
+    w: 270,
+    westnorthwest: 292,
+    wnw: 292,
+    northwest: 315,
+    nw: 315,
+    northnorthwest: 337,
+    nnw: 337
+  };
+  function osmNode() {
+    if (!(this instanceof osmNode)) {
+      return new osmNode().initialize(arguments);
+    } else if (arguments.length) {
+      this.initialize(arguments);
+    }
+  }
+  osmEntity.node = osmNode;
+  osmNode.prototype = Object.create(osmEntity.prototype);
+  Object.assign(osmNode.prototype, {
+    type: "node",
+    loc: [9999, 9999],
+    extent: function() {
+      return new geoExtent(this.loc);
+    },
+    geometry: function(graph) {
+      return graph.transient(this, "geometry", function() {
+        return graph.isPoi(this) ? "point" : "vertex";
       });
-      return graph;
-    };
-    action.connections = function(graph) {
-      var candidates = [];
-      var keeping = false;
-      var parentWays = graph.parentWays(graph.entity(nodeId));
-      var way, waynode;
-      for (var i2 = 0; i2 < parentWays.length; i2++) {
-        way = parentWays[i2];
-        if (wayIds && wayIds.indexOf(way.id) === -1) {
-          keeping = true;
-          continue;
-        }
-        if (way.isArea() && way.nodes[0] === nodeId) {
-          candidates.push({ wayID: way.id, index: 0 });
-        } else {
-          for (var j2 = 0; j2 < way.nodes.length; j2++) {
-            waynode = way.nodes[j2];
-            if (waynode === nodeId) {
-              if (way.isClosed() && parentWays.length > 1 && wayIds && wayIds.indexOf(way.id) !== -1 && j2 === way.nodes.length - 1) {
-                continue;
-              }
-              candidates.push({ wayID: way.id, index: j2 });
-            }
+    },
+    move: function(loc) {
+      return this.update({ loc });
+    },
+    isDegenerate: function() {
+      return !(Array.isArray(this.loc) && this.loc.length === 2 && this.loc[0] >= -180 && this.loc[0] <= 180 && this.loc[1] >= -90 && this.loc[1] <= 90);
+    },
+    // Inspect tags and geometry to determine which direction(s) this node/vertex points
+    directions: function(resolver, projection2) {
+      var val;
+      var i2;
+      if (this.isHighwayIntersection(resolver) && (this.tags.stop || "").toLowerCase() === "all") {
+        val = "all";
+      } else {
+        val = (this.tags.direction || "").toLowerCase();
+        var re2 = /:direction$/i;
+        var keys2 = Object.keys(this.tags);
+        for (i2 = 0; i2 < keys2.length; i2++) {
+          if (re2.test(keys2[i2])) {
+            val = this.tags[keys2[i2]].toLowerCase();
+            break;
           }
         }
       }
-      return keeping ? candidates : candidates.slice(1);
-    };
-    action.disabled = function(graph) {
-      var connections = action.connections(graph);
-      if (connections.length === 0)
-        return "not_connected";
-      var parentWays = graph.parentWays(graph.entity(nodeId));
-      var seenRelationIds = {};
-      var sharedRelation;
-      parentWays.forEach(function(way) {
-        var relations = graph.parentRelations(way);
-        relations.filter((relation) => !disconnectableRelationTypes[relation.tags.type]).forEach(function(relation) {
-          if (relation.id in seenRelationIds) {
-            if (wayIds) {
-              if (wayIds.indexOf(way.id) !== -1 || wayIds.indexOf(seenRelationIds[relation.id]) !== -1) {
-                sharedRelation = relation;
+      if (val === "")
+        return [];
+      var values = val.split(";");
+      var results = [];
+      values.forEach(function(v) {
+        if (cardinal[v] !== void 0) {
+          v = cardinal[v];
+        }
+        if (v !== "" && !isNaN(+v)) {
+          results.push(+v);
+          return;
+        }
+        var lookBackward = this.tags["traffic_sign:backward"] || v === "backward" || v === "both" || v === "all";
+        var lookForward = this.tags["traffic_sign:forward"] || v === "forward" || v === "both" || v === "all";
+        if (!lookForward && !lookBackward)
+          return;
+        var nodeIds = {};
+        resolver.parentWays(this).forEach(function(parent) {
+          var nodes = parent.nodes;
+          for (i2 = 0; i2 < nodes.length; i2++) {
+            if (nodes[i2] === this.id) {
+              if (lookForward && i2 > 0) {
+                nodeIds[nodes[i2 - 1]] = true;
+              }
+              if (lookBackward && i2 < nodes.length - 1) {
+                nodeIds[nodes[i2 + 1]] = true;
               }
-            } else {
-              sharedRelation = relation;
             }
-          } else {
-            seenRelationIds[relation.id] = way.id;
           }
-        });
+        }, this);
+        Object.keys(nodeIds).forEach(function(nodeId) {
+          results.push(
+            geoAngle(this, resolver.entity(nodeId), projection2) * (180 / Math.PI) + 90
+          );
+        }, this);
+      }, this);
+      return utilArrayUniq(results);
+    },
+    isCrossing: function() {
+      return this.tags.highway === "crossing" || this.tags.railway && this.tags.railway.indexOf("crossing") !== -1;
+    },
+    isEndpoint: function(resolver) {
+      return resolver.transient(this, "isEndpoint", function() {
+        var id2 = this.id;
+        return resolver.parentWays(this).filter(function(parent) {
+          return !parent.isClosed() && !!parent.affix(id2);
+        }).length > 0;
       });
-      if (sharedRelation)
-        return "relation";
-    };
-    action.limitWays = function(val) {
-      if (!arguments.length)
-        return wayIds;
-      wayIds = val;
-      return action;
-    };
-    return action;
-  }
-
-  // modules/actions/extract.js
-  function actionExtract(entityID, projection2) {
-    var extractedNodeID;
-    var action = function(graph) {
-      var entity = graph.entity(entityID);
-      if (entity.type === "node") {
-        return extractFromNode(entity, graph);
-      }
-      return extractFromWayOrRelation(entity, graph);
-    };
-    function extractFromNode(node, graph) {
-      extractedNodeID = node.id;
-      var replacement = osmNode({ loc: node.loc });
-      graph = graph.replace(replacement);
-      graph = graph.parentWays(node).reduce(function(accGraph, parentWay) {
-        return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
-      }, graph);
-      return graph.parentRelations(node).reduce(function(accGraph, parentRel) {
-        return accGraph.replace(parentRel.replaceMember(node, replacement));
-      }, graph);
-    }
-    function extractFromWayOrRelation(entity, graph) {
-      var fromGeometry = entity.geometry(graph);
-      var keysToCopyAndRetain = ["source", "wheelchair"];
-      var keysToRetain = ["area"];
-      var buildingKeysToRetain = ["architect", "building", "height", "layer"];
-      var extractedLoc = path_default(projection2).centroid(entity.asGeoJSON(graph));
-      extractedLoc = extractedLoc && projection2.invert(extractedLoc);
-      if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
-        extractedLoc = entity.extent(graph).center();
-      }
-      var indoorAreaValues = {
-        area: true,
-        corridor: true,
-        elevator: true,
-        level: true,
-        room: true
-      };
-      var isBuilding = entity.tags.building && entity.tags.building !== "no" || entity.tags["building:part"] && entity.tags["building:part"] !== "no";
-      var isIndoorArea = fromGeometry === "area" && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
-      var entityTags = Object.assign({}, entity.tags);
-      var pointTags = {};
-      for (var key in entityTags) {
-        if (entity.type === "relation" && key === "type") {
-          continue;
-        }
-        if (keysToRetain.indexOf(key) !== -1) {
-          continue;
-        }
-        if (isBuilding) {
-          if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/))
-            continue;
-        }
-        if (isIndoorArea && key === "indoor") {
-          continue;
-        }
-        pointTags[key] = entityTags[key];
-        if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
-          continue;
-        } else if (isIndoorArea && key === "level") {
-          continue;
+    },
+    isConnected: function(resolver) {
+      return resolver.transient(this, "isConnected", function() {
+        var parents = resolver.parentWays(this);
+        if (parents.length > 1) {
+          for (var i2 in parents) {
+            if (parents[i2].geometry(resolver) === "line" && parents[i2].hasInterestingTags())
+              return true;
+          }
+        } else if (parents.length === 1) {
+          var way = parents[0];
+          var nodes = way.nodes.slice();
+          if (way.isClosed()) {
+            nodes.pop();
+          }
+          return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
         }
-        delete entityTags[key];
-      }
-      if (!isBuilding && !isIndoorArea && fromGeometry === "area") {
-        entityTags.area = "yes";
-      }
-      var replacement = osmNode({ loc: extractedLoc, tags: pointTags });
-      graph = graph.replace(replacement);
-      extractedNodeID = replacement.id;
-      return graph.replace(entity.update({ tags: entityTags }));
-    }
-    action.getExtractedNodeID = function() {
-      return extractedNodeID;
-    };
-    return action;
-  }
-
-  // modules/actions/join.js
-  function actionJoin(ids) {
-    function groupEntitiesByGeometry(graph) {
-      var entities = ids.map(function(id2) {
-        return graph.entity(id2);
-      });
-      return Object.assign(
-        { line: [] },
-        utilArrayGroupBy(entities, function(entity) {
-          return entity.geometry(graph);
-        })
-      );
-    }
-    var action = function(graph) {
-      var ways = ids.map(graph.entity, graph);
-      var survivorID = utilOldestID(ways.map((way) => way.id));
-      ways.sort(function(a, b) {
-        var aSided = a.isSided();
-        var bSided = b.isSided();
-        return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
+        return false;
       });
-      var sequences = osmJoinWays(ways, graph);
-      var joined = sequences[0];
-      graph = sequences.actions.reduce(function(g, action2) {
-        return action2(g);
-      }, graph);
-      var survivor = graph.entity(survivorID);
-      survivor = survivor.update({ nodes: joined.nodes.map(function(n2) {
-        return n2.id;
-      }) });
-      graph = graph.replace(survivor);
-      joined.forEach(function(way) {
-        if (way.id === survivorID)
-          return;
-        graph.parentRelations(way).forEach(function(parent) {
-          graph = graph.replace(parent.replaceMember(way, survivor));
+    },
+    parentIntersectionWays: function(resolver) {
+      return resolver.transient(this, "parentIntersectionWays", function() {
+        return resolver.parentWays(this).filter(function(parent) {
+          return (parent.tags.highway || parent.tags.waterway || parent.tags.railway || parent.tags.aeroway) && parent.geometry(resolver) === "line";
         });
-        survivor = survivor.mergeTags(way.tags);
-        graph = graph.replace(survivor);
-        graph = actionDeleteWay(way.id)(graph);
       });
-      function checkForSimpleMultipolygon() {
-        if (!survivor.isClosed())
-          return;
-        var multipolygons = graph.parentMultipolygons(survivor).filter(function(multipolygon2) {
-          return multipolygon2.members.length === 1;
-        });
-        if (multipolygons.length !== 1)
-          return;
-        var multipolygon = multipolygons[0];
-        for (var key in survivor.tags) {
-          if (multipolygon.tags[key] && multipolygon.tags[key] !== survivor.tags[key])
-            return;
-        }
-        survivor = survivor.mergeTags(multipolygon.tags);
-        graph = graph.replace(survivor);
-        graph = actionDeleteRelation(multipolygon.id, true)(graph);
-        var tags = Object.assign({}, survivor.tags);
-        if (survivor.geometry(graph) !== "area") {
-          tags.area = "yes";
+    },
+    isIntersection: function(resolver) {
+      return this.parentIntersectionWays(resolver).length > 1;
+    },
+    isHighwayIntersection: function(resolver) {
+      return resolver.transient(this, "isHighwayIntersection", function() {
+        return resolver.parentWays(this).filter(function(parent) {
+          return parent.tags.highway && parent.geometry(resolver) === "line";
+        }).length > 1;
+      });
+    },
+    isOnAddressLine: function(resolver) {
+      return resolver.transient(this, "isOnAddressLine", function() {
+        return resolver.parentWays(this).filter(function(parent) {
+          return parent.tags.hasOwnProperty("addr:interpolation") && parent.geometry(resolver) === "line";
+        }).length > 0;
+      });
+    },
+    asJXON: function(changeset_id) {
+      var r = {
+        node: {
+          "@id": this.osmId(),
+          "@lon": this.loc[0],
+          "@lat": this.loc[1],
+          "@version": this.version || 0,
+          tag: Object.keys(this.tags).map(function(k) {
+            return { keyAttributes: { k, v: this.tags[k] } };
+          }, this)
         }
-        delete tags.type;
-        survivor = survivor.update({ tags });
-        graph = graph.replace(survivor);
+      };
+      if (changeset_id)
+        r.node["@changeset"] = changeset_id;
+      return r;
+    },
+    asGeoJSON: function() {
+      return {
+        type: "Point",
+        coordinates: this.loc
+      };
+    }
+  });
+
+  // modules/actions/circularize.js
+  function actionCircularize(wayId, projection2, maxAngle) {
+    maxAngle = (maxAngle || 20) * Math.PI / 180;
+    var action = function(graph, t) {
+      if (t === null || !isFinite(t))
+        t = 1;
+      t = Math.min(Math.max(+t, 0), 1);
+      var way = graph.entity(wayId);
+      var origNodes = {};
+      graph.childNodes(way).forEach(function(node2) {
+        if (!origNodes[node2.id])
+          origNodes[node2.id] = node2;
+      });
+      if (!way.isConvex(graph)) {
+        graph = action.makeConvex(graph);
       }
-      checkForSimpleMultipolygon();
-      return graph;
-    };
-    action.resultingWayNodesLength = function(graph) {
-      return ids.reduce(function(count, id2) {
-        return count + graph.entity(id2).nodes.length;
-      }, 0) - ids.length - 1;
-    };
-    action.disabled = function(graph) {
-      var geometries = groupEntitiesByGeometry(graph);
-      if (ids.length < 2 || ids.length !== geometries.line.length) {
-        return "not_eligible";
+      var nodes = utilArrayUniq(graph.childNodes(way));
+      var keyNodes = nodes.filter(function(n2) {
+        return graph.parentWays(n2).length !== 1;
+      });
+      var points = nodes.map(function(n2) {
+        return projection2(n2.loc);
+      });
+      var keyPoints = keyNodes.map(function(n2) {
+        return projection2(n2.loc);
+      });
+      var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : centroid_default2(points);
+      var radius = median(points, function(p) {
+        return geoVecLength(centroid, p);
+      });
+      var sign2 = area_default3(points) > 0 ? 1 : -1;
+      var ids, i2, j2, k;
+      if (!keyNodes.length) {
+        keyNodes = [nodes[0]];
+        keyPoints = [points[0]];
       }
-      var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
-      if (joined.length > 1) {
-        return "not_adjacent";
+      if (keyNodes.length === 1) {
+        var index = nodes.indexOf(keyNodes[0]);
+        var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
+        keyNodes.push(nodes[oppositeIndex]);
+        keyPoints.push(points[oppositeIndex]);
       }
-      var i2;
-      var sortedParentRelations = function(id2) {
-        return graph.parentRelations(graph.entity(id2)).filter((rel) => !rel.isRestriction() && !rel.isConnectivity()).sort((a, b) => a.id - b.id);
-      };
-      var relsA = sortedParentRelations(ids[0]);
-      for (i2 = 1; i2 < ids.length; i2++) {
-        var relsB = sortedParentRelations(ids[i2]);
-        if (!utilArrayIdentical(relsA, relsB)) {
-          return "conflicting_relations";
+      for (i2 = 0; i2 < keyPoints.length; i2++) {
+        var nextKeyNodeIndex = (i2 + 1) % keyNodes.length;
+        var startNode = keyNodes[i2];
+        var endNode = keyNodes[nextKeyNodeIndex];
+        var startNodeIndex = nodes.indexOf(startNode);
+        var endNodeIndex = nodes.indexOf(endNode);
+        var numberNewPoints = -1;
+        var indexRange = endNodeIndex - startNodeIndex;
+        var nearNodes = {};
+        var inBetweenNodes = [];
+        var startAngle, endAngle, totalAngle, eachAngle;
+        var angle2, loc, node, origNode;
+        if (indexRange < 0) {
+          indexRange += nodes.length;
         }
-      }
-      for (i2 = 0; i2 < ids.length - 1; i2++) {
-        for (var j2 = i2 + 1; j2 < ids.length; j2++) {
-          var path1 = graph.childNodes(graph.entity(ids[i2])).map(function(e) {
-            return e.loc;
-          });
-          var path2 = graph.childNodes(graph.entity(ids[j2])).map(function(e) {
-            return e.loc;
-          });
-          var intersections = geoPathIntersections(path1, path2);
-          var common = utilArrayIntersection(
-            joined[0].nodes.map(function(n2) {
-              return n2.loc.toString();
-            }),
-            intersections.map(function(n2) {
-              return n2.toString();
-            })
-          );
-          if (common.length !== intersections.length) {
-            return "paths_intersect";
-          }
+        var distance = geoVecLength(centroid, keyPoints[i2]) || 1e-4;
+        keyPoints[i2] = [
+          centroid[0] + (keyPoints[i2][0] - centroid[0]) / distance * radius,
+          centroid[1] + (keyPoints[i2][1] - centroid[1]) / distance * radius
+        ];
+        loc = projection2.invert(keyPoints[i2]);
+        node = keyNodes[i2];
+        origNode = origNodes[node.id];
+        node = node.move(geoVecInterp(origNode.loc, loc, t));
+        graph = graph.replace(node);
+        startAngle = Math.atan2(keyPoints[i2][1] - centroid[1], keyPoints[i2][0] - centroid[0]);
+        endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
+        totalAngle = endAngle - startAngle;
+        if (totalAngle * sign2 > 0) {
+          totalAngle = -sign2 * (2 * Math.PI - Math.abs(totalAngle));
         }
-      }
-      var nodeIds = joined[0].nodes.map(function(n2) {
-        return n2.id;
-      }).slice(1, -1);
-      var relation;
-      var tags = {};
-      var conflicting = false;
-      joined[0].forEach(function(way) {
-        var parents = graph.parentRelations(way);
-        parents.forEach(function(parent) {
-          if ((parent.isRestriction() || parent.isConnectivity()) && parent.members.some(function(m) {
-            return nodeIds.indexOf(m.id) >= 0;
-          })) {
-            relation = parent;
-          }
-        });
-        for (var k in way.tags) {
-          if (!(k in tags)) {
-            tags[k] = way.tags[k];
-          } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
-            conflicting = true;
-          }
+        do {
+          numberNewPoints++;
+          eachAngle = totalAngle / (indexRange + numberNewPoints);
+        } while (Math.abs(eachAngle) > maxAngle);
+        for (j2 = 1; j2 < indexRange; j2++) {
+          angle2 = startAngle + j2 * eachAngle;
+          loc = projection2.invert([
+            centroid[0] + Math.cos(angle2) * radius,
+            centroid[1] + Math.sin(angle2) * radius
+          ]);
+          node = nodes[(j2 + startNodeIndex) % nodes.length];
+          origNode = origNodes[node.id];
+          nearNodes[node.id] = angle2;
+          node = node.move(geoVecInterp(origNode.loc, loc, t));
+          graph = graph.replace(node);
         }
-      });
-      if (relation) {
-        return relation.isRestriction() ? "restriction" : "connectivity";
-      }
-      if (conflicting) {
-        return "conflicting_tags";
-      }
-    };
-    return action;
-  }
-
-  // modules/actions/merge.js
-  function actionMerge(ids) {
-    function groupEntitiesByGeometry(graph) {
-      var entities = ids.map(function(id2) {
-        return graph.entity(id2);
-      });
-      return Object.assign(
-        { point: [], area: [], line: [], relation: [] },
-        utilArrayGroupBy(entities, function(entity) {
-          return entity.geometry(graph);
-        })
-      );
-    }
-    var action = function(graph) {
-      var geometries = groupEntitiesByGeometry(graph);
-      var target = geometries.area[0] || geometries.line[0];
-      var points = geometries.point;
-      points.forEach(function(point) {
-        target = target.mergeTags(point.tags);
-        graph = graph.replace(target);
-        graph.parentRelations(point).forEach(function(parent) {
-          graph = graph.replace(parent.replaceMember(point, target));
-        });
-        var nodes = utilArrayUniq(graph.childNodes(target));
-        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(point.update({ tags: node2.tags, loc: node2.loc }));
-            target = target.replaceNode(node2.id, point.id);
-            graph = graph.replace(target);
-            removeNode = node2;
-            inserted = true;
-          };
-          var i2;
-          var node;
-          for (i2 = 0; i2 < nodes.length; i2++) {
-            node = nodes[i2];
-            if (canBeReplaced(node) && node.isNew()) {
-              replaceNode(node);
-              break;
+        for (j2 = 0; j2 < numberNewPoints; j2++) {
+          angle2 = startAngle + (indexRange + j2) * eachAngle;
+          loc = projection2.invert([
+            centroid[0] + Math.cos(angle2) * radius,
+            centroid[1] + Math.sin(angle2) * radius
+          ]);
+          var min3 = Infinity;
+          for (var nodeId in nearNodes) {
+            var nearAngle = nearNodes[nodeId];
+            var dist = Math.abs(nearAngle - angle2);
+            if (dist < min3) {
+              min3 = dist;
+              origNode = origNodes[nodeId];
             }
           }
-          if (!inserted && point.hasInterestingTags()) {
-            for (i2 = 0; i2 < nodes.length; i2++) {
-              node = nodes[i2];
-              if (canBeReplaced(node) && !node.hasInterestingTags()) {
-                replaceNode(node);
-                break;
+          node = osmNode({ loc: geoVecInterp(origNode.loc, loc, t) });
+          graph = graph.replace(node);
+          nodes.splice(endNodeIndex + j2, 0, node);
+          inBetweenNodes.push(node.id);
+        }
+        if (indexRange === 1 && inBetweenNodes.length) {
+          var startIndex1 = way.nodes.lastIndexOf(startNode.id);
+          var endIndex1 = way.nodes.lastIndexOf(endNode.id);
+          var wayDirection1 = endIndex1 - startIndex1;
+          if (wayDirection1 < -1) {
+            wayDirection1 = 1;
+          }
+          var parentWays = graph.parentWays(keyNodes[i2]);
+          for (j2 = 0; j2 < parentWays.length; j2++) {
+            var sharedWay = parentWays[j2];
+            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);
+              var wayDirection2 = endIndex2 - startIndex2;
+              var insertAt = endIndex2;
+              if (wayDirection2 < -1) {
+                wayDirection2 = 1;
               }
-            }
-            if (!inserted) {
-              for (i2 = 0; i2 < nodes.length; i2++) {
-                node = nodes[i2];
-                if (canBeReplaced(node) && utilCompareIDs(point.id, node.id) < 0) {
-                  replaceNode(node);
-                  break;
-                }
+              if (wayDirection1 !== wayDirection2) {
+                inBetweenNodes.reverse();
+                insertAt = startIndex2;
+              }
+              for (k = 0; k < inBetweenNodes.length; k++) {
+                sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k);
               }
+              graph = graph.replace(sharedWay);
             }
           }
         }
-        graph = graph.remove(removeNode);
+      }
+      ids = nodes.map(function(n2) {
+        return n2.id;
       });
-      if (target.tags.area === "yes") {
-        var tags = Object.assign({}, target.tags);
-        delete tags.area;
-        if (osmTagSuggestingArea(tags)) {
-          target = target.update({ tags });
-          graph = graph.replace(target);
+      ids.push(ids[0]);
+      way = way.update({ nodes: ids });
+      graph = graph.replace(way);
+      return graph;
+    };
+    action.makeConvex = function(graph) {
+      var way = graph.entity(wayId);
+      var nodes = utilArrayUniq(graph.childNodes(way));
+      var points = nodes.map(function(n2) {
+        return projection2(n2.loc);
+      });
+      var sign2 = area_default3(points) > 0 ? 1 : -1;
+      var hull = hull_default(points);
+      var i2, j2;
+      if (sign2 === -1) {
+        nodes.reverse();
+        points.reverse();
+      }
+      for (i2 = 0; i2 < hull.length - 1; i2++) {
+        var startIndex = points.indexOf(hull[i2]);
+        var endIndex = points.indexOf(hull[i2 + 1]);
+        var indexRange = endIndex - startIndex;
+        if (indexRange < 0) {
+          indexRange += nodes.length;
+        }
+        for (j2 = 1; j2 < indexRange; j2++) {
+          var point2 = geoVecInterp(hull[i2], hull[i2 + 1], j2 / indexRange);
+          var node = nodes[(j2 + startIndex) % nodes.length].move(projection2.invert(point2));
+          graph = graph.replace(node);
         }
       }
       return graph;
     };
     action.disabled = function(graph) {
-      var geometries = groupEntitiesByGeometry(graph);
-      if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
-        return "not_eligible";
+      if (!graph.entity(wayId).isClosed()) {
+        return "not_closed";
+      }
+      var way = graph.entity(wayId);
+      var nodes = utilArrayUniq(graph.childNodes(way));
+      var points = nodes.map(function(n2) {
+        return projection2(n2.loc);
+      });
+      var hull = hull_default(points);
+      var epsilonAngle = Math.PI / 180;
+      if (hull.length !== points.length || hull.length < 3) {
+        return false;
+      }
+      var centroid = centroid_default2(points);
+      var radius = geoVecLengthSquare(centroid, points[0]);
+      var i2, actualPoint;
+      for (i2 = 0; i2 < hull.length; i2++) {
+        actualPoint = hull[i2];
+        var actualDist = geoVecLengthSquare(actualPoint, centroid);
+        var diff = Math.abs(actualDist - radius);
+        if (diff > 0.05 * radius) {
+          return false;
+        }
+      }
+      for (i2 = 0; i2 < hull.length; i2++) {
+        actualPoint = hull[i2];
+        var nextPoint = hull[(i2 + 1) % hull.length];
+        var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
+        var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
+        var angle2 = endAngle - startAngle;
+        if (angle2 < 0) {
+          angle2 = -angle2;
+        }
+        if (angle2 > Math.PI) {
+          angle2 = 2 * Math.PI - angle2;
+        }
+        if (angle2 > maxAngle + epsilonAngle) {
+          return false;
+        }
       }
+      return "already_circular";
     };
+    action.transitionable = true;
     return action;
   }
 
-  // modules/actions/merge_nodes.js
-  function actionMergeNodes(nodeIDs, loc) {
-    function chooseLoc(graph) {
-      if (!nodeIDs.length)
-        return null;
-      var sum = [0, 0];
-      var interestingCount = 0;
-      var interestingLoc;
-      for (var i2 = 0; i2 < nodeIDs.length; i2++) {
-        var node = graph.entity(nodeIDs[i2]);
-        if (node.hasInterestingTags()) {
-          interestingLoc = ++interestingCount === 1 ? node.loc : null;
-        }
-        sum = geoVecAdd(sum, node.loc);
-      }
-      return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
+  // modules/actions/delete_way.js
+  function actionDeleteWay(wayID) {
+    function canDeleteNode(node, graph) {
+      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;
+      return !node.hasInterestingTags();
     }
     var action = function(graph) {
-      if (nodeIDs.length < 2)
-        return graph;
-      var toLoc = loc;
-      if (!toLoc) {
-        toLoc = chooseLoc(graph);
-      }
-      for (var i2 = 0; i2 < nodeIDs.length; i2++) {
-        var node = graph.entity(nodeIDs[i2]);
-        if (node.loc !== toLoc) {
-          graph = graph.replace(node.move(toLoc));
+      var way = graph.entity(wayID);
+      graph.parentRelations(way).forEach(function(parent) {
+        parent = parent.removeMembersWithID(wayID);
+        graph = graph.replace(parent);
+        if (parent.isDegenerate()) {
+          graph = actionDeleteRelation(parent.id)(graph);
         }
-      }
-      return actionConnect(nodeIDs)(graph);
+      });
+      new Set(way.nodes).forEach(function(nodeID) {
+        graph = graph.replace(way.removeNode(nodeID));
+        var node = graph.entity(nodeID);
+        if (canDeleteNode(node, graph)) {
+          graph = graph.remove(node);
+        }
+      });
+      return graph.remove(way);
     };
-    action.disabled = function(graph) {
-      if (nodeIDs.length < 2)
-        return "not_eligible";
-      for (var i2 = 0; i2 < nodeIDs.length; i2++) {
-        var entity = graph.entity(nodeIDs[i2]);
-        if (entity.type !== "node")
-          return "not_eligible";
-      }
-      return actionConnect(nodeIDs).disabled(graph);
+    return action;
+  }
+
+  // modules/actions/delete_multiple.js
+  function actionDeleteMultiple(ids) {
+    var actions = {
+      way: actionDeleteWay,
+      node: actionDeleteNode,
+      relation: actionDeleteRelation
+    };
+    var action = function(graph) {
+      ids.forEach(function(id2) {
+        if (graph.hasEntity(id2)) {
+          graph = actions[graph.entity(id2).type](id2)(graph);
+        }
+      });
+      return graph;
     };
     return action;
   }
 
-  // modules/osm/changeset.js
-  function osmChangeset() {
-    if (!(this instanceof osmChangeset)) {
-      return new osmChangeset().initialize(arguments);
-    } else if (arguments.length) {
-      this.initialize(arguments);
+  // modules/actions/delete_relation.js
+  function actionDeleteRelation(relationID, allowUntaggedMembers) {
+    function canDeleteEntity(entity, graph) {
+      return !graph.parentWays(entity).length && !graph.parentRelations(entity).length && (!entity.hasInterestingTags() && !allowUntaggedMembers);
     }
-  }
-  osmEntity.changeset = osmChangeset;
-  osmChangeset.prototype = Object.create(osmEntity.prototype);
-  Object.assign(osmChangeset.prototype, {
-    type: "changeset",
-    extent: function() {
-      return new geoExtent();
-    },
-    geometry: function() {
-      return "changeset";
-    },
-    asJXON: function() {
-      return {
-        osm: {
-          changeset: {
-            tag: Object.keys(this.tags).map(function(k) {
-              return { "@k": k, "@v": this.tags[k] };
-            }, this),
-            "@version": 0.6,
-            "@generator": "iD"
-          }
+    var action = function(graph) {
+      var relation = graph.entity(relationID);
+      graph.parentRelations(relation).forEach(function(parent) {
+        parent = parent.removeMembersWithID(relationID);
+        graph = graph.replace(parent);
+        if (parent.isDegenerate()) {
+          graph = actionDeleteRelation(parent.id)(graph);
         }
-      };
-    },
-    osmChangeJXON: function(changes) {
-      var changeset_id = this.id;
-      function nest(x, order) {
-        var groups = {};
-        for (var i2 = 0; i2 < x.length; i2++) {
-          var tagName = Object.keys(x[i2])[0];
-          if (!groups[tagName])
-            groups[tagName] = [];
-          groups[tagName].push(x[i2][tagName]);
+      });
+      var memberIDs = utilArrayUniq(relation.members.map(function(m) {
+        return m.id;
+      }));
+      memberIDs.forEach(function(memberID) {
+        graph = graph.replace(relation.removeMembersWithID(memberID));
+        var entity = graph.entity(memberID);
+        if (canDeleteEntity(entity, graph)) {
+          graph = actionDeleteMultiple([memberID])(graph);
+        }
+      });
+      return graph.remove(relation);
+    };
+    return action;
+  }
+
+  // modules/actions/delete_node.js
+  function actionDeleteNode(nodeId) {
+    var action = function(graph) {
+      var node = graph.entity(nodeId);
+      graph.parentWays(node).forEach(function(parent) {
+        parent = parent.removeNode(nodeId);
+        graph = graph.replace(parent);
+        if (parent.isDegenerate()) {
+          graph = actionDeleteWay(parent.id)(graph);
+        }
+      });
+      graph.parentRelations(node).forEach(function(parent) {
+        parent = parent.removeMembersWithID(nodeId);
+        graph = graph.replace(parent);
+        if (parent.isDegenerate()) {
+          graph = actionDeleteRelation(parent.id)(graph);
+        }
+      });
+      return graph.remove(node);
+    };
+    return action;
+  }
+
+  // modules/actions/connect.js
+  function actionConnect(nodeIDs) {
+    var action = function(graph) {
+      var survivor;
+      var node;
+      var parents;
+      var i2, j2;
+      nodeIDs.reverse();
+      var interestingIDs = [];
+      for (i2 = 0; i2 < nodeIDs.length; i2++) {
+        node = graph.entity(nodeIDs[i2]);
+        if (node.hasInterestingTags()) {
+          if (!node.isNew()) {
+            interestingIDs.push(node.id);
+          }
         }
-        var ordered = {};
-        order.forEach(function(o) {
-          if (groups[o])
-            ordered[o] = groups[o];
-        });
-        return ordered;
       }
-      function sort(changes2) {
-        function resolve(item) {
-          return relations.find(function(relation2) {
-            return item.keyAttributes.type === "relation" && item.keyAttributes.ref === relation2["@id"];
-          });
+      survivor = graph.entity(utilOldestID(interestingIDs.length > 0 ? interestingIDs : nodeIDs));
+      for (i2 = 0; i2 < nodeIDs.length; i2++) {
+        node = graph.entity(nodeIDs[i2]);
+        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));
         }
-        function isNew(item) {
-          return !sorted[item["@id"]] && !processing.find(function(proc) {
-            return proc["@id"] === item["@id"];
-          });
+        parents = graph.parentRelations(node);
+        for (j2 = 0; j2 < parents.length; j2++) {
+          graph = graph.replace(parents[j2].replaceMember(node, survivor));
         }
-        var processing = [];
-        var sorted = {};
-        var relations = changes2.relation;
-        if (!relations)
-          return changes2;
-        for (var i2 = 0; i2 < relations.length; i2++) {
-          var relation = relations[i2];
-          if (!sorted[relation["@id"]]) {
-            processing.push(relation);
+        survivor = survivor.mergeTags(node.tags);
+        graph = actionDeleteNode(node.id)(graph);
+      }
+      graph = graph.replace(survivor);
+      parents = graph.parentWays(survivor);
+      for (i2 = 0; i2 < parents.length; i2++) {
+        if (parents[i2].isDegenerate()) {
+          graph = actionDeleteWay(parents[i2].id)(graph);
+        }
+      }
+      return graph;
+    };
+    action.disabled = function(graph) {
+      var seen = {};
+      var restrictionIDs = [];
+      var survivor;
+      var node, way;
+      var relations, relation, role;
+      var i2, j2, k;
+      survivor = graph.entity(utilOldestID(nodeIDs));
+      for (i2 = 0; i2 < nodeIDs.length; i2++) {
+        node = graph.entity(nodeIDs[i2]);
+        relations = graph.parentRelations(node);
+        for (j2 = 0; j2 < relations.length; j2++) {
+          relation = relations[j2];
+          role = relation.memberById(node.id).role || "";
+          if (relation.hasFromViaTo()) {
+            restrictionIDs.push(relation.id);
           }
-          while (processing.length > 0) {
-            var next = processing[0], deps = next.member.map(resolve).filter(Boolean).filter(isNew);
-            if (deps.length === 0) {
-              sorted[next["@id"]] = next;
-              processing.shift();
-            } else {
-              processing = deps.concat(processing);
-            }
+          if (seen[relation.id] !== void 0 && seen[relation.id] !== role) {
+            return "relation";
+          } else {
+            seen[relation.id] = role;
           }
         }
-        changes2.relation = Object.values(sorted);
-        return changes2;
       }
-      function rep2(entity) {
-        return entity.asJXON(changeset_id);
+      for (i2 = 0; i2 < nodeIDs.length; i2++) {
+        node = graph.entity(nodeIDs[i2]);
+        var parents = graph.parentWays(node);
+        for (j2 = 0; j2 < parents.length; j2++) {
+          var parent = parents[j2];
+          relations = graph.parentRelations(parent);
+          for (k = 0; k < relations.length; k++) {
+            relation = relations[k];
+            if (relation.hasFromViaTo()) {
+              restrictionIDs.push(relation.id);
+            }
+          }
+        }
       }
-      return {
-        osmChange: {
-          "@version": 0.6,
-          "@generator": "iD",
-          "create": sort(nest(changes.created.map(rep2), ["node", "way", "relation"])),
-          "modify": nest(changes.modified.map(rep2), ["node", "way", "relation"]),
-          "delete": Object.assign(nest(changes.deleted.map(rep2), ["relation", "way", "node"]), { "@if-unused": true })
+      restrictionIDs = utilArrayUniq(restrictionIDs);
+      for (i2 = 0; i2 < restrictionIDs.length; i2++) {
+        relation = graph.entity(restrictionIDs[i2]);
+        if (!relation.isComplete(graph))
+          continue;
+        var memberWays = relation.members.filter(function(m) {
+          return m.type === "way";
+        }).map(function(m) {
+          return graph.entity(m.id);
+        });
+        memberWays = utilArrayUniq(memberWays);
+        var f2 = relation.memberByRole("from");
+        var t = relation.memberByRole("to");
+        var isUturn = f2.id === t.id;
+        var nodes = { from: [], via: [], to: [], keyfrom: [], keyto: [] };
+        for (j2 = 0; j2 < relation.members.length; j2++) {
+          collectNodes(relation.members[j2], nodes);
         }
-      };
-    },
-    asGeoJSON: function() {
-      return {};
-    }
-  });
-
-  // modules/osm/note.js
-  function osmNote() {
-    if (!(this instanceof osmNote)) {
-      return new osmNote().initialize(arguments);
-    } else if (arguments.length) {
-      this.initialize(arguments);
-    }
-  }
-  osmNote.id = function() {
-    return osmNote.id.next--;
-  };
-  osmNote.id.next = -1;
-  Object.assign(osmNote.prototype, {
-    type: "note",
-    initialize: function(sources) {
-      for (var i2 = 0; i2 < sources.length; ++i2) {
-        var source = sources[i2];
-        for (var prop in source) {
-          if (Object.prototype.hasOwnProperty.call(source, prop)) {
-            if (source[prop] === void 0) {
-              delete this[prop];
+        nodes.keyfrom = utilArrayUniq(nodes.keyfrom.filter(hasDuplicates));
+        nodes.keyto = utilArrayUniq(nodes.keyto.filter(hasDuplicates));
+        var filter2 = keyNodeFilter(nodes.keyfrom, nodes.keyto);
+        nodes.from = nodes.from.filter(filter2);
+        nodes.via = nodes.via.filter(filter2);
+        nodes.to = nodes.to.filter(filter2);
+        var connectFrom = false;
+        var connectVia = false;
+        var connectTo = false;
+        var connectKeyFrom = false;
+        var connectKeyTo = false;
+        for (j2 = 0; j2 < nodeIDs.length; j2++) {
+          var n2 = nodeIDs[j2];
+          if (nodes.from.indexOf(n2) !== -1) {
+            connectFrom = true;
+          }
+          if (nodes.via.indexOf(n2) !== -1) {
+            connectVia = true;
+          }
+          if (nodes.to.indexOf(n2) !== -1) {
+            connectTo = true;
+          }
+          if (nodes.keyfrom.indexOf(n2) !== -1) {
+            connectKeyFrom = true;
+          }
+          if (nodes.keyto.indexOf(n2) !== -1) {
+            connectKeyTo = true;
+          }
+        }
+        if (connectFrom && connectTo && !isUturn) {
+          return "restriction";
+        }
+        if (connectFrom && connectVia) {
+          return "restriction";
+        }
+        if (connectTo && connectVia) {
+          return "restriction";
+        }
+        if (connectKeyFrom || connectKeyTo) {
+          if (nodeIDs.length !== 2) {
+            return "restriction";
+          }
+          var n0 = null;
+          var n1 = null;
+          for (j2 = 0; j2 < memberWays.length; j2++) {
+            way = memberWays[j2];
+            if (way.contains(nodeIDs[0])) {
+              n0 = nodeIDs[0];
+            }
+            if (way.contains(nodeIDs[1])) {
+              n1 = nodeIDs[1];
+            }
+          }
+          if (n0 && n1) {
+            var ok = false;
+            for (j2 = 0; j2 < memberWays.length; j2++) {
+              way = memberWays[j2];
+              if (way.areAdjacent(n0, n1)) {
+                ok = true;
+                break;
+              }
+            }
+            if (!ok) {
+              return "restriction";
+            }
+          }
+        }
+        for (j2 = 0; j2 < memberWays.length; j2++) {
+          way = memberWays[j2].update({});
+          for (k = 0; k < nodeIDs.length; k++) {
+            if (nodeIDs[k] === survivor.id)
+              continue;
+            if (way.areAdjacent(nodeIDs[k], survivor.id)) {
+              way = way.removeNode(nodeIDs[k]);
             } else {
-              this[prop] = source[prop];
+              way = way.replaceNode(nodeIDs[k], survivor.id);
             }
           }
+          if (way.isDegenerate()) {
+            return "restriction";
+          }
         }
       }
-      if (!this.id) {
-        this.id = osmNote.id().toString();
+      return false;
+      function hasDuplicates(n3, i3, arr) {
+        return arr.indexOf(n3) !== arr.lastIndexOf(n3);
       }
-      return this;
-    },
-    extent: function() {
-      return new geoExtent(this.loc);
-    },
-    update: function(attrs) {
-      return osmNote(this, attrs);
-    },
-    isNew: function() {
-      return this.id < 0;
-    },
-    move: function(loc) {
-      return this.update({ loc });
-    }
-  });
-
-  // modules/osm/relation.js
-  function osmRelation() {
-    if (!(this instanceof osmRelation)) {
-      return new osmRelation().initialize(arguments);
-    } else if (arguments.length) {
-      this.initialize(arguments);
-    }
-  }
-  osmEntity.relation = osmRelation;
-  osmRelation.prototype = Object.create(osmEntity.prototype);
-  osmRelation.creationOrder = function(a, b) {
-    var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
-    var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
-    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];
-      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 });
-      });
-      copy2 = copy2.update({ members });
-      copies[this.id] = copy2;
-      return copy2;
-    },
-    extent: function(resolver, memo) {
-      return resolver.transient(this, "extent", function() {
-        if (memo && memo[this.id])
-          return geoExtent();
-        memo = memo || {};
-        memo[this.id] = true;
-        var extent = geoExtent();
-        for (var i2 = 0; i2 < this.members.length; i2++) {
-          var member = resolver.hasEntity(this.members[i2].id);
-          if (member) {
-            extent._extend(member.extent(resolver, memo));
+      function keyNodeFilter(froms, tos) {
+        return function(n3) {
+          return froms.indexOf(n3) === -1 && tos.indexOf(n3) === -1;
+        };
+      }
+      function collectNodes(member, collection) {
+        var entity = graph.hasEntity(member.id);
+        if (!entity)
+          return;
+        var role2 = member.role || "";
+        if (!collection[role2]) {
+          collection[role2] = [];
+        }
+        if (member.type === "node") {
+          collection[role2].push(member.id);
+          if (role2 === "via") {
+            collection.keyfrom.push(member.id);
+            collection.keyto.push(member.id);
+          }
+        } else if (member.type === "way") {
+          collection[role2].push.apply(collection[role2], entity.nodes);
+          if (role2 === "from" || role2 === "via") {
+            collection.keyfrom.push(entity.first());
+            collection.keyfrom.push(entity.last());
+          }
+          if (role2 === "to" || role2 === "via") {
+            collection.keyto.push(entity.first());
+            collection.keyto.push(entity.last());
           }
         }
-        return extent;
-      });
-    },
-    geometry: function(graph) {
-      return graph.transient(this, "geometry", function() {
-        return this.isMultipolygon() ? "area" : "relation";
+      }
+    };
+    return action;
+  }
+
+  // modules/actions/copy_entities.js
+  function actionCopyEntities(ids, fromGraph) {
+    var _copies = {};
+    var action = function(graph) {
+      ids.forEach(function(id3) {
+        fromGraph.entity(id3).copy(fromGraph, _copies);
       });
-    },
-    isDegenerate: function() {
-      return this.members.length === 0;
-    },
-    indexedMembers: function() {
-      var result = new Array(this.members.length);
-      for (var i2 = 0; i2 < this.members.length; i2++) {
-        result[i2] = Object.assign({}, this.members[i2], { index: i2 });
+      for (var id2 in _copies) {
+        graph = graph.replace(_copies[id2]);
       }
-      return result;
-    },
-    memberByRole: function(role) {
-      for (var i2 = 0; i2 < this.members.length; i2++) {
-        if (this.members[i2].role === role) {
-          return Object.assign({}, this.members[i2], { index: i2 });
-        }
+      return graph;
+    };
+    action.copies = function() {
+      return _copies;
+    };
+    return action;
+  }
+
+  // modules/actions/delete_member.js
+  function actionDeleteMember(relationId, memberIndex) {
+    return function(graph) {
+      var relation = graph.entity(relationId).removeMember(memberIndex);
+      graph = graph.replace(relation);
+      if (relation.isDegenerate()) {
+        graph = actionDeleteRelation(relation.id)(graph);
       }
-    },
-    membersByRole: function(role) {
-      var result = [];
-      for (var i2 = 0; i2 < this.members.length; i2++) {
-        if (this.members[i2].role === role) {
-          result.push(Object.assign({}, this.members[i2], { index: i2 }));
+      return graph;
+    };
+  }
+
+  // modules/actions/discard_tags.js
+  function actionDiscardTags(difference, discardTags) {
+    discardTags = discardTags || {};
+    return (graph) => {
+      difference.modified().forEach(checkTags);
+      difference.created().forEach(checkTags);
+      return graph;
+      function checkTags(entity) {
+        const keys2 = Object.keys(entity.tags);
+        let didDiscard = false;
+        let tags = {};
+        for (let i2 = 0; i2 < keys2.length; i2++) {
+          const k = keys2[i2];
+          if (discardTags[k] || !entity.tags[k]) {
+            didDiscard = true;
+          } else {
+            tags[k] = entity.tags[k];
+          }
         }
-      }
-      return result;
-    },
-    memberById: function(id2) {
-      for (var i2 = 0; i2 < this.members.length; i2++) {
-        if (this.members[i2].id === id2) {
-          return Object.assign({}, this.members[i2], { index: i2 });
+        if (didDiscard) {
+          graph = graph.replace(entity.update({ tags }));
         }
       }
-    },
-    memberByIdAndRole: function(id2, role) {
-      for (var i2 = 0; i2 < this.members.length; i2++) {
-        if (this.members[i2].id === id2 && this.members[i2].role === role) {
-          return Object.assign({}, this.members[i2], { index: i2 });
+    };
+  }
+
+  // modules/actions/disconnect.js
+  function actionDisconnect(nodeId, newNodeId) {
+    var wayIds;
+    var disconnectableRelationTypes = {
+      "associatedStreet": true,
+      "enforcement": true,
+      "site": true
+    };
+    var action = function(graph) {
+      var node = graph.entity(nodeId);
+      var connections = action.connections(graph);
+      connections.forEach(function(connection) {
+        var way = graph.entity(connection.wayID);
+        var newNode = osmNode({ id: newNodeId, loc: node.loc, tags: node.tags });
+        graph = graph.replace(newNode);
+        if (connection.index === 0 && way.isArea()) {
+          graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
+        } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
+          graph = graph.replace(way.unclose().addNode(newNode.id));
+        } else {
+          graph = graph.replace(way.updateNode(newNode.id, connection.index));
         }
-      }
-    },
-    addMember: function(member, index) {
-      var members = this.members.slice();
-      members.splice(index === void 0 ? members.length : index, 0, member);
-      return this.update({ members });
-    },
-    updateMember: function(member, index) {
-      var members = this.members.slice();
-      members.splice(index, 1, Object.assign({}, members[index], member));
-      return this.update({ members });
-    },
-    removeMember: function(index) {
-      var members = this.members.slice();
-      members.splice(index, 1);
-      return this.update({ members });
-    },
-    removeMembersWithID: function(id2) {
-      var members = this.members.filter(function(m) {
-        return m.id !== id2;
       });
-      return this.update({ members });
-    },
-    moveMember: function(fromIndex, toIndex) {
-      var members = this.members.slice();
-      members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
-      return this.update({ members });
-    },
-    replaceMember: function(needle, replacement, keepDuplicates) {
-      if (!this.memberById(needle.id))
-        return this;
-      var members = [];
-      for (var i2 = 0; i2 < this.members.length; i2++) {
-        var member = this.members[i2];
-        if (member.id !== needle.id) {
-          members.push(member);
-        } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
-          members.push({ id: replacement.id, type: replacement.type, role: member.role });
+      return graph;
+    };
+    action.connections = function(graph) {
+      var candidates = [];
+      var keeping = false;
+      var parentWays = graph.parentWays(graph.entity(nodeId));
+      var way, waynode;
+      for (var i2 = 0; i2 < parentWays.length; i2++) {
+        way = parentWays[i2];
+        if (wayIds && wayIds.indexOf(way.id) === -1) {
+          keeping = true;
+          continue;
         }
-      }
-      return this.update({ members });
-    },
-    asJXON: function(changeset_id) {
-      var r = {
-        relation: {
-          "@id": this.osmId(),
-          "@version": this.version || 0,
-          member: this.members.map(function(member) {
-            return {
-              keyAttributes: {
-                type: member.type,
-                role: member.role,
-                ref: osmEntity.id.toOSM(member.id)
+        if (way.isArea() && way.nodes[0] === nodeId) {
+          candidates.push({ wayID: way.id, index: 0 });
+        } else {
+          for (var j2 = 0; j2 < way.nodes.length; j2++) {
+            waynode = way.nodes[j2];
+            if (waynode === nodeId) {
+              if (way.isClosed() && parentWays.length > 1 && wayIds && wayIds.indexOf(way.id) !== -1 && j2 === way.nodes.length - 1) {
+                continue;
               }
-            };
-          }, this),
-          tag: Object.keys(this.tags).map(function(k) {
-            return { keyAttributes: { k, v: this.tags[k] } };
-          }, this)
+              candidates.push({ wayID: way.id, index: j2 });
+            }
+          }
         }
-      };
-      if (changeset_id) {
-        r.relation["@changeset"] = changeset_id;
       }
-      return r;
-    },
-    asGeoJSON: function(resolver) {
-      return resolver.transient(this, "GeoJSON", function() {
-        if (this.isMultipolygon()) {
-          return {
-            type: "MultiPolygon",
-            coordinates: this.multipolygon(resolver)
-          };
-        } else {
-          return {
-            type: "FeatureCollection",
-            properties: this.tags,
-            features: this.members.map(function(member) {
-              return Object.assign({ role: member.role }, resolver.entity(member.id).asGeoJSON(resolver));
-            })
-          };
-        }
-      });
-    },
-    area: function(resolver) {
-      return resolver.transient(this, "area", function() {
-        return area_default(this.asGeoJSON(resolver));
+      return keeping ? candidates : candidates.slice(1);
+    };
+    action.disabled = function(graph) {
+      var connections = action.connections(graph);
+      if (connections.length === 0)
+        return "not_connected";
+      var parentWays = graph.parentWays(graph.entity(nodeId));
+      var seenRelationIds = {};
+      var sharedRelation;
+      parentWays.forEach(function(way) {
+        var relations = graph.parentRelations(way);
+        relations.filter((relation) => !disconnectableRelationTypes[relation.tags.type]).forEach(function(relation) {
+          if (relation.id in seenRelationIds) {
+            if (wayIds) {
+              if (wayIds.indexOf(way.id) !== -1 || wayIds.indexOf(seenRelationIds[relation.id]) !== -1) {
+                sharedRelation = relation;
+              }
+            } else {
+              sharedRelation = relation;
+            }
+          } else {
+            seenRelationIds[relation.id] = way.id;
+          }
+        });
       });
-    },
-    isMultipolygon: function() {
-      return this.tags.type === "multipolygon";
-    },
-    isComplete: function(resolver) {
-      for (var i2 = 0; i2 < this.members.length; i2++) {
-        if (!resolver.hasEntity(this.members[i2].id)) {
-          return false;
-        }
+      if (sharedRelation)
+        return "relation";
+    };
+    action.limitWays = function(val) {
+      if (!arguments.length)
+        return wayIds;
+      wayIds = val;
+      return action;
+    };
+    return action;
+  }
+
+  // modules/actions/extract.js
+  function actionExtract(entityID, projection2) {
+    var extractedNodeID;
+    var action = function(graph) {
+      var entity = graph.entity(entityID);
+      if (entity.type === "node") {
+        return extractFromNode(entity, graph);
       }
-      return true;
-    },
-    hasFromViaTo: function() {
-      return this.members.some(function(m) {
-        return m.role === "from";
-      }) && this.members.some(function(m) {
-        return m.role === "via";
-      }) && this.members.some(function(m) {
-        return m.role === "to";
-      });
-    },
-    isRestriction: function() {
-      return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
-    },
-    isValidRestriction: function() {
-      if (!this.isRestriction())
-        return false;
-      var froms = this.members.filter(function(m) {
-        return m.role === "from";
-      });
-      var vias = this.members.filter(function(m) {
-        return m.role === "via";
-      });
-      var tos = this.members.filter(function(m) {
-        return m.role === "to";
-      });
-      if (froms.length !== 1 && this.tags.restriction !== "no_entry")
-        return false;
-      if (froms.some(function(m) {
-        return m.type !== "way";
-      }))
-        return false;
-      if (tos.length !== 1 && this.tags.restriction !== "no_exit")
-        return false;
-      if (tos.some(function(m) {
-        return m.type !== "way";
-      }))
-        return false;
-      if (vias.length === 0)
-        return false;
-      if (vias.length > 1 && vias.some(function(m) {
-        return m.type !== "way";
-      }))
-        return false;
-      return true;
-    },
-    isConnectivity: function() {
-      return !!(this.tags.type && this.tags.type.match(/^connectivity:?/));
-    },
-    multipolygon: function(resolver) {
-      var outers = this.members.filter(function(m) {
-        return "outer" === (m.role || "outer");
-      });
-      var inners = this.members.filter(function(m) {
-        return "inner" === m.role;
-      });
-      outers = osmJoinWays(outers, resolver);
-      inners = osmJoinWays(inners, resolver);
-      var sequenceToLineString = function(sequence) {
-        if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
-          sequence.nodes.push(sequence.nodes[0]);
-        }
-        return sequence.nodes.map(function(node) {
-          return node.loc;
-        });
+      return extractFromWayOrRelation(entity, graph);
+    };
+    function extractFromNode(node, graph) {
+      extractedNodeID = node.id;
+      var replacement = osmNode({ loc: node.loc });
+      graph = graph.replace(replacement);
+      graph = graph.parentWays(node).reduce(function(accGraph, parentWay) {
+        return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
+      }, graph);
+      return graph.parentRelations(node).reduce(function(accGraph, parentRel) {
+        return accGraph.replace(parentRel.replaceMember(node, replacement));
+      }, graph);
+    }
+    function extractFromWayOrRelation(entity, graph) {
+      var fromGeometry = entity.geometry(graph);
+      var keysToCopyAndRetain = ["source", "wheelchair"];
+      var keysToRetain = ["area"];
+      var buildingKeysToRetain = ["architect", "building", "height", "layer"];
+      var extractedLoc = path_default(projection2).centroid(entity.asGeoJSON(graph));
+      extractedLoc = extractedLoc && projection2.invert(extractedLoc);
+      if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
+        extractedLoc = entity.extent(graph).center();
+      }
+      var indoorAreaValues = {
+        area: true,
+        corridor: true,
+        elevator: true,
+        level: true,
+        room: true
       };
-      outers = outers.map(sequenceToLineString);
-      inners = inners.map(sequenceToLineString);
-      var result = outers.map(function(o2) {
-        return [area_default({ type: "Polygon", coordinates: [o2] }) > 2 * Math.PI ? o2.reverse() : o2];
-      });
-      function findOuter(inner2) {
-        var o2, outer;
-        for (o2 = 0; o2 < outers.length; o2++) {
-          outer = outers[o2];
-          if (geoPolygonContainsPolygon(outer, inner2)) {
-            return o2;
-          }
+      var isBuilding = entity.tags.building && entity.tags.building !== "no" || entity.tags["building:part"] && entity.tags["building:part"] !== "no";
+      var isIndoorArea = fromGeometry === "area" && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
+      var entityTags = Object.assign({}, entity.tags);
+      var pointTags = {};
+      for (var key in entityTags) {
+        if (entity.type === "relation" && key === "type") {
+          continue;
         }
-        for (o2 = 0; o2 < outers.length; o2++) {
-          outer = outers[o2];
-          if (geoPolygonIntersectsPolygon(outer, inner2, false)) {
-            return o2;
-          }
+        if (keysToRetain.indexOf(key) !== -1) {
+          continue;
         }
-      }
-      for (var i2 = 0; i2 < inners.length; i2++) {
-        var inner = inners[i2];
-        if (area_default({ type: "Polygon", coordinates: [inner] }) < 2 * Math.PI) {
-          inner = inner.reverse();
+        if (isBuilding) {
+          if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/))
+            continue;
         }
-        var o = findOuter(inners[i2]);
-        if (o !== void 0) {
-          result[o].push(inners[i2]);
-        } else {
-          result.push([inners[i2]]);
+        if (isIndoorArea && key === "indoor") {
+          continue;
+        }
+        pointTags[key] = entityTags[key];
+        if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
+          continue;
+        } else if (isIndoorArea && key === "level") {
+          continue;
         }
+        delete entityTags[key];
       }
-      return result;
-    }
-  });
-
-  // modules/osm/qa_item.js
-  var QAItem = class {
-    constructor(loc, service, itemType, id2, props) {
-      this.loc = loc;
-      this.service = service.title;
-      this.itemType = itemType;
-      this.id = id2 ? id2 : `${QAItem.id()}`;
-      this.update(props);
-      if (service && typeof service.getIcon === "function") {
-        this.icon = service.getIcon(itemType);
+      if (!isBuilding && !isIndoorArea && fromGeometry === "area") {
+        entityTags.area = "yes";
       }
+      var replacement = osmNode({ loc: extractedLoc, tags: pointTags });
+      graph = graph.replace(replacement);
+      extractedNodeID = replacement.id;
+      return graph.replace(entity.update({ tags: entityTags }));
     }
-    update(props) {
-      const { loc, service, itemType, id: id2 } = this;
-      Object.keys(props).forEach((prop) => this[prop] = props[prop]);
-      this.loc = loc;
-      this.service = service;
-      this.itemType = itemType;
-      this.id = id2;
-      return this;
-    }
-    static id() {
-      return this.nextId--;
-    }
-  };
-  QAItem.nextId = -1;
+    action.getExtractedNodeID = function() {
+      return extractedNodeID;
+    };
+    return action;
+  }
 
-  // modules/actions/split.js
-  function actionSplit(nodeIds, newWayIds) {
-    if (typeof nodeIds === "string")
-      nodeIds = [nodeIds];
-    var _wayIDs;
-    var _keepHistoryOn = "longest";
-    var _createdWayIDs = [];
-    function dist(graph, nA, nB) {
-      var locA = graph.entity(nA).loc;
-      var locB = graph.entity(nB).loc;
-      var epsilon3 = 1e-6;
-      return locA && locB ? geoSphericalDistance(locA, locB) : epsilon3;
+  // modules/actions/join.js
+  function actionJoin(ids) {
+    function groupEntitiesByGeometry(graph) {
+      var entities = ids.map(function(id2) {
+        return graph.entity(id2);
+      });
+      return Object.assign(
+        { line: [] },
+        utilArrayGroupBy(entities, function(entity) {
+          return entity.geometry(graph);
+        })
+      );
     }
-    function splitArea(nodes, idxA, graph) {
-      var lengths = new Array(nodes.length);
-      var length;
-      var i2;
-      var best = 0;
-      var idxB;
-      function wrap2(index) {
-        return utilWrap(index, nodes.length);
-      }
-      length = 0;
-      for (i2 = wrap2(idxA + 1); i2 !== idxA; i2 = wrap2(i2 + 1)) {
-        length += dist(graph, nodes[i2], nodes[wrap2(i2 - 1)]);
-        lengths[i2] = length;
-      }
-      length = 0;
-      for (i2 = wrap2(idxA - 1); i2 !== idxA; i2 = wrap2(i2 - 1)) {
-        length += dist(graph, nodes[i2], nodes[wrap2(i2 + 1)]);
-        if (length < lengths[i2]) {
-          lengths[i2] = length;
+    var action = function(graph) {
+      var ways = ids.map(graph.entity, graph);
+      var survivorID = utilOldestID(ways.map((way) => way.id));
+      ways.sort(function(a, b) {
+        var aSided = a.isSided();
+        var bSided = b.isSided();
+        return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
+      });
+      var sequences = osmJoinWays(ways, graph);
+      var joined = sequences[0];
+      graph = sequences.actions.reduce(function(g, action2) {
+        return action2(g);
+      }, graph);
+      var survivor = graph.entity(survivorID);
+      survivor = survivor.update({ nodes: joined.nodes.map(function(n2) {
+        return n2.id;
+      }) });
+      graph = graph.replace(survivor);
+      joined.forEach(function(way) {
+        if (way.id === survivorID)
+          return;
+        graph.parentRelations(way).forEach(function(parent) {
+          graph = graph.replace(parent.replaceMember(way, survivor));
+        });
+        survivor = survivor.mergeTags(way.tags);
+        graph = graph.replace(survivor);
+        graph = actionDeleteWay(way.id)(graph);
+      });
+      function checkForSimpleMultipolygon() {
+        if (!survivor.isClosed())
+          return;
+        var multipolygons = graph.parentMultipolygons(survivor).filter(function(multipolygon2) {
+          return multipolygon2.members.length === 1;
+        });
+        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;
         }
-      }
-      for (i2 = 0; i2 < nodes.length; i2++) {
-        var cost = lengths[i2] / dist(graph, nodes[idxA], nodes[i2]);
-        if (cost > best) {
-          idxB = i2;
-          best = cost;
+        survivor = survivor.mergeTags(multipolygon.tags);
+        graph = graph.replace(survivor);
+        graph = actionDeleteRelation(
+          multipolygon.id,
+          true
+          /* allow untagged members */
+        )(graph);
+        var tags = Object.assign({}, survivor.tags);
+        if (survivor.geometry(graph) !== "area") {
+          tags.area = "yes";
         }
+        delete tags.type;
+        survivor = survivor.update({ tags });
+        graph = graph.replace(survivor);
       }
-      return idxB;
-    }
-    function totalLengthBetweenNodes(graph, nodes) {
-      var totalLength = 0;
-      for (var i2 = 0; i2 < nodes.length - 1; i2++) {
-        totalLength += dist(graph, nodes[i2], nodes[i2 + 1]);
+      checkForSimpleMultipolygon();
+      return graph;
+    };
+    action.resultingWayNodesLength = function(graph) {
+      return ids.reduce(function(count, id2) {
+        return count + graph.entity(id2).nodes.length;
+      }, 0) - ids.length - 1;
+    };
+    action.disabled = function(graph) {
+      var geometries = groupEntitiesByGeometry(graph);
+      if (ids.length < 2 || ids.length !== geometries.line.length) {
+        return "not_eligible";
       }
-      return totalLength;
-    }
-    function split(graph, nodeId, wayA, newWayId) {
-      var wayB = osmWay({ id: newWayId, tags: wayA.tags });
-      var origNodes = wayA.nodes.slice();
-      var nodesA;
-      var nodesB;
-      var isArea = wayA.isArea();
-      var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
-      if (wayA.isClosed()) {
-        var nodes = wayA.nodes.slice(0, -1);
-        var idxA = nodes.indexOf(nodeId);
-        var idxB = splitArea(nodes, idxA, graph);
-        if (idxB < idxA) {
-          nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
-          nodesB = nodes.slice(idxB, idxA + 1);
-        } else {
-          nodesA = nodes.slice(idxA, idxB + 1);
-          nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
-        }
-      } else {
-        var idx = wayA.nodes.indexOf(nodeId, 1);
-        nodesA = wayA.nodes.slice(0, idx + 1);
-        nodesB = wayA.nodes.slice(idx);
+      var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
+      if (joined.length > 1) {
+        return "not_adjacent";
       }
-      var lengthA = totalLengthBetweenNodes(graph, nodesA);
-      var lengthB = totalLengthBetweenNodes(graph, nodesB);
-      if (_keepHistoryOn === "longest" && lengthB > lengthA) {
-        wayA = wayA.update({ nodes: nodesB });
-        wayB = wayB.update({ nodes: nodesA });
-        var temp = lengthA;
-        lengthA = lengthB;
-        lengthB = temp;
-      } else {
-        wayA = wayA.update({ nodes: nodesA });
-        wayB = wayB.update({ nodes: nodesB });
+      var i2;
+      var sortedParentRelations = function(id2) {
+        return graph.parentRelations(graph.entity(id2)).filter((rel) => !rel.isRestriction() && !rel.isConnectivity()).sort((a, b) => a.id - b.id);
+      };
+      var relsA = sortedParentRelations(ids[0]);
+      for (i2 = 1; i2 < ids.length; i2++) {
+        var relsB = sortedParentRelations(ids[i2]);
+        if (!utilArrayIdentical(relsA, relsB)) {
+          return "conflicting_relations";
+        }
       }
-      if (wayA.tags.step_count) {
-        var stepCount = parseFloat(wayA.tags.step_count);
-        if (stepCount && isFinite(stepCount) && stepCount > 0 && Math.round(stepCount) === stepCount) {
-          var tagsA = Object.assign({}, wayA.tags);
-          var tagsB = Object.assign({}, wayB.tags);
-          var ratioA = lengthA / (lengthA + lengthB);
-          var countA = Math.round(stepCount * ratioA);
-          tagsA.step_count = countA.toString();
-          tagsB.step_count = (stepCount - countA).toString();
-          wayA = wayA.update({ tags: tagsA });
-          wayB = wayB.update({ tags: tagsB });
+      for (i2 = 0; i2 < ids.length - 1; i2++) {
+        for (var j2 = i2 + 1; j2 < ids.length; j2++) {
+          var path1 = graph.childNodes(graph.entity(ids[i2])).map(function(e) {
+            return e.loc;
+          });
+          var path2 = graph.childNodes(graph.entity(ids[j2])).map(function(e) {
+            return e.loc;
+          });
+          var intersections = geoPathIntersections(path1, path2);
+          var common = utilArrayIntersection(
+            joined[0].nodes.map(function(n2) {
+              return n2.loc.toString();
+            }),
+            intersections.map(function(n2) {
+              return n2.toString();
+            })
+          );
+          if (common.length !== intersections.length) {
+            return "paths_intersect";
+          }
         }
       }
-      graph = graph.replace(wayA);
-      graph = graph.replace(wayB);
-      graph.parentRelations(wayA).forEach(function(relation) {
-        var member;
-        if (relation.hasFromViaTo()) {
-          var f2 = relation.memberByRole("from");
-          var v = relation.membersByRole("via");
-          var t = relation.memberByRole("to");
-          var i2;
-          if (f2.id === wayA.id || t.id === wayA.id) {
-            var keepB = false;
-            if (v.length === 1 && v[0].type === "node") {
-              keepB = wayB.contains(v[0].id);
-            } else {
-              for (i2 = 0; i2 < v.length; i2++) {
-                if (v[i2].type === "way") {
-                  var wayVia = graph.hasEntity(v[i2].id);
-                  if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
-                    keepB = true;
-                    break;
-                  }
-                }
-              }
-            }
-            if (keepB) {
-              relation = relation.replaceMember(wayA, wayB);
-              graph = graph.replace(relation);
-            }
-          } else {
-            for (i2 = 0; i2 < v.length; i2++) {
-              if (v[i2].type === "way" && v[i2].id === wayA.id) {
-                member = {
-                  id: wayB.id,
-                  type: "way",
-                  role: "via"
-                };
-                graph = actionAddMember(relation.id, member, v[i2].index + 1)(graph);
-                break;
-              }
-            }
+      var nodeIds = joined[0].nodes.map(function(n2) {
+        return n2.id;
+      }).slice(1, -1);
+      var relation;
+      var tags = {};
+      var conflicting = false;
+      joined[0].forEach(function(way) {
+        var parents = graph.parentRelations(way);
+        parents.forEach(function(parent) {
+          if ((parent.isRestriction() || parent.isConnectivity()) && parent.members.some(function(m) {
+            return nodeIds.indexOf(m.id) >= 0;
+          })) {
+            relation = parent;
           }
-        } else {
-          if (relation === isOuter) {
-            graph = graph.replace(relation.mergeTags(wayA.tags));
-            graph = graph.replace(wayA.update({ tags: {} }));
-            graph = graph.replace(wayB.update({ tags: {} }));
+        });
+        for (var k in way.tags) {
+          if (!(k in tags)) {
+            tags[k] = way.tags[k];
+          } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
+            conflicting = true;
           }
-          member = {
-            id: wayB.id,
-            type: "way",
-            role: relation.memberById(wayA.id).role
-          };
-          var insertPair = {
-            originalID: wayA.id,
-            insertedID: wayB.id,
-            nodes: origNodes
-          };
-          graph = actionAddMember(relation.id, member, void 0, insertPair)(graph);
         }
       });
-      if (!isOuter && isArea) {
-        var multipolygon = osmRelation({
-          tags: Object.assign({}, wayA.tags, { type: "multipolygon" }),
-          members: [
-            { id: wayA.id, role: "outer", type: "way" },
-            { id: wayB.id, role: "outer", type: "way" }
-          ]
-        });
-        graph = graph.replace(multipolygon);
-        graph = graph.replace(wayA.update({ tags: {} }));
-        graph = graph.replace(wayB.update({ tags: {} }));
+      if (relation) {
+        return relation.isRestriction() ? "restriction" : "connectivity";
       }
-      _createdWayIDs.push(wayB.id);
-      return graph;
+      if (conflicting) {
+        return "conflicting_tags";
+      }
+    };
+    return action;
+  }
+
+  // modules/actions/merge.js
+  function actionMerge(ids) {
+    function groupEntitiesByGeometry(graph) {
+      var entities = ids.map(function(id2) {
+        return graph.entity(id2);
+      });
+      return Object.assign(
+        { point: [], area: [], line: [], relation: [] },
+        utilArrayGroupBy(entities, function(entity) {
+          return entity.geometry(graph);
+        })
+      );
     }
     var action = function(graph) {
-      _createdWayIDs = [];
-      var newWayIndex = 0;
-      for (var i2 = 0; i2 < nodeIds.length; i2++) {
-        var nodeId = nodeIds[i2];
-        var candidates = action.waysForNode(nodeId, graph);
-        for (var j2 = 0; j2 < candidates.length; j2++) {
-          graph = split(graph, nodeId, candidates[j2], newWayIds && newWayIds[newWayIndex]);
-          newWayIndex += 1;
+      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);
+        graph = graph.replace(target);
+        graph.parentRelations(point2).forEach(function(parent) {
+          graph = graph.replace(parent.replaceMember(point2, target));
+        });
+        var nodes = utilArrayUniq(graph.childNodes(target));
+        var removeNode = point2;
+        if (!point2.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(target);
+            removeNode = node2;
+            inserted = true;
+          };
+          var i2;
+          var node;
+          for (i2 = 0; i2 < nodes.length; i2++) {
+            node = nodes[i2];
+            if (canBeReplaced(node) && node.isNew()) {
+              replaceNode(node);
+              break;
+            }
+          }
+          if (!inserted && point2.hasInterestingTags()) {
+            for (i2 = 0; i2 < nodes.length; i2++) {
+              node = nodes[i2];
+              if (canBeReplaced(node) && !node.hasInterestingTags()) {
+                replaceNode(node);
+                break;
+              }
+            }
+            if (!inserted) {
+              for (i2 = 0; i2 < nodes.length; i2++) {
+                node = nodes[i2];
+                if (canBeReplaced(node) && utilCompareIDs(point2.id, node.id) < 0) {
+                  replaceNode(node);
+                  break;
+                }
+              }
+            }
+          }
+        }
+        graph = graph.remove(removeNode);
+      });
+      if (target.tags.area === "yes") {
+        var tags = Object.assign({}, target.tags);
+        delete tags.area;
+        if (osmTagSuggestingArea(tags)) {
+          target = target.update({ tags });
+          graph = graph.replace(target);
         }
       }
       return graph;
     };
-    action.getCreatedWayIDs = function() {
-      return _createdWayIDs;
+    action.disabled = function(graph) {
+      var geometries = groupEntitiesByGeometry(graph);
+      if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
+        return "not_eligible";
+      }
     };
-    action.waysForNode = function(nodeId, graph) {
-      var node = graph.entity(nodeId);
-      var splittableParents = graph.parentWays(node).filter(isSplittable);
-      if (!_wayIDs) {
-        var hasLine = splittableParents.some(function(parent) {
-          return parent.geometry(graph) === "line";
-        });
-        if (hasLine) {
-          return splittableParents.filter(function(parent) {
-            return parent.geometry(graph) === "line";
-          });
+    return action;
+  }
+
+  // modules/actions/merge_nodes.js
+  function actionMergeNodes(nodeIDs, loc) {
+    function chooseLoc(graph) {
+      if (!nodeIDs.length)
+        return null;
+      var sum = [0, 0];
+      var interestingCount = 0;
+      var interestingLoc;
+      for (var i2 = 0; i2 < nodeIDs.length; i2++) {
+        var node = graph.entity(nodeIDs[i2]);
+        if (node.hasInterestingTags()) {
+          interestingLoc = ++interestingCount === 1 ? node.loc : null;
         }
+        sum = geoVecAdd(sum, node.loc);
       }
-      return splittableParents;
-      function isSplittable(parent) {
-        if (_wayIDs && _wayIDs.indexOf(parent.id) === -1)
-          return false;
-        if (parent.isClosed())
-          return true;
-        for (var i2 = 1; i2 < parent.nodes.length - 1; i2++) {
-          if (parent.nodes[i2] === nodeId)
-            return true;
+      return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
+    }
+    var action = function(graph) {
+      if (nodeIDs.length < 2)
+        return graph;
+      var toLoc = loc;
+      if (!toLoc) {
+        toLoc = chooseLoc(graph);
+      }
+      for (var i2 = 0; i2 < nodeIDs.length; i2++) {
+        var node = graph.entity(nodeIDs[i2]);
+        if (node.loc !== toLoc) {
+          graph = graph.replace(node.move(toLoc));
         }
-        return false;
       }
-    };
-    action.ways = function(graph) {
-      return utilArrayUniq([].concat.apply([], nodeIds.map(function(nodeId) {
-        return action.waysForNode(nodeId, graph);
-      })));
+      return actionConnect(nodeIDs)(graph);
     };
     action.disabled = function(graph) {
-      for (var i2 = 0; i2 < nodeIds.length; i2++) {
-        var nodeId = nodeIds[i2];
-        var candidates = action.waysForNode(nodeId, graph);
-        if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
+      if (nodeIDs.length < 2)
+        return "not_eligible";
+      for (var i2 = 0; i2 < nodeIDs.length; i2++) {
+        var entity = graph.entity(nodeIDs[i2]);
+        if (entity.type !== "node")
           return "not_eligible";
-        }
       }
-    };
-    action.limitWays = function(val) {
-      if (!arguments.length)
-        return _wayIDs;
-      _wayIDs = val;
-      return action;
-    };
-    action.keepHistoryOn = function(val) {
-      if (!arguments.length)
-        return _keepHistoryOn;
-      _keepHistoryOn = val;
-      return action;
+      return actionConnect(nodeIDs).disabled(graph);
     };
     return action;
   }
 
-  // modules/core/graph.js
-  function 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);
-      this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
-      this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
-    } else {
-      this.entities = /* @__PURE__ */ Object.create({});
-      this._parentWays = /* @__PURE__ */ Object.create({});
-      this._parentRels = /* @__PURE__ */ Object.create({});
-      this.rebase(other || [], [this]);
+  // modules/osm/changeset.js
+  function osmChangeset() {
+    if (!(this instanceof osmChangeset)) {
+      return new osmChangeset().initialize(arguments);
+    } else if (arguments.length) {
+      this.initialize(arguments);
     }
-    this.transients = {};
-    this._childNodes = {};
-    this.frozen = !mutable;
   }
-  coreGraph.prototype = {
-    hasEntity: function(id2) {
-      return this.entities[id2];
-    },
-    entity: function(id2) {
-      var entity = this.entities[id2];
-      if (!entity) {
-        entity = this.entities.__proto__[id2];
-      }
-      if (!entity) {
-        throw new Error("entity " + id2 + " not found");
-      }
-      return entity;
+  osmEntity.changeset = osmChangeset;
+  osmChangeset.prototype = Object.create(osmEntity.prototype);
+  Object.assign(osmChangeset.prototype, {
+    type: "changeset",
+    extent: function() {
+      return new geoExtent();
     },
-    geometry: function(id2) {
-      return this.entity(id2).geometry(this);
+    geometry: function() {
+      return "changeset";
     },
-    transient: function(entity, key, fn) {
-      var id2 = entity.id;
-      var transients = this.transients[id2] || (this.transients[id2] = {});
-      if (transients[key] !== void 0) {
-        return transients[key];
-      }
-      transients[key] = fn.call(entity);
-      return transients[key];
+    asJXON: function() {
+      return {
+        osm: {
+          changeset: {
+            tag: Object.keys(this.tags).map(function(k) {
+              return { "@k": k, "@v": this.tags[k] };
+            }, this),
+            "@version": 0.6,
+            "@generator": "iD"
+          }
+        }
+      };
     },
-    parentWays: function(entity) {
-      var parents = this._parentWays[entity.id];
-      var result = [];
-      if (parents) {
-        parents.forEach(function(id2) {
-          result.push(this.entity(id2));
-        }, this);
+    // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
+    // XML. Returns a string.
+    osmChangeJXON: function(changes) {
+      var changeset_id = this.id;
+      function nest(x, order) {
+        var groups = {};
+        for (var i2 = 0; i2 < x.length; i2++) {
+          var tagName = Object.keys(x[i2])[0];
+          if (!groups[tagName])
+            groups[tagName] = [];
+          groups[tagName].push(x[i2][tagName]);
+        }
+        var ordered = {};
+        order.forEach(function(o) {
+          if (groups[o])
+            ordered[o] = groups[o];
+        });
+        return ordered;
       }
-      return result;
-    },
-    isPoi: function(entity) {
-      var parents = this._parentWays[entity.id];
-      return !parents || parents.size === 0;
-    },
-    isShared: function(entity) {
-      var parents = this._parentWays[entity.id];
-      return parents && parents.size > 1;
-    },
-    parentRelations: function(entity) {
-      var parents = this._parentRels[entity.id];
-      var result = [];
-      if (parents) {
-        parents.forEach(function(id2) {
-          result.push(this.entity(id2));
-        }, this);
+      function sort(changes2) {
+        function resolve(item) {
+          return relations.find(function(relation2) {
+            return item.keyAttributes.type === "relation" && item.keyAttributes.ref === relation2["@id"];
+          });
+        }
+        function isNew(item) {
+          return !sorted[item["@id"]] && !processing.find(function(proc) {
+            return proc["@id"] === item["@id"];
+          });
+        }
+        var processing = [];
+        var sorted = {};
+        var relations = changes2.relation;
+        if (!relations)
+          return changes2;
+        for (var i2 = 0; i2 < relations.length; i2++) {
+          var relation = relations[i2];
+          if (!sorted[relation["@id"]]) {
+            processing.push(relation);
+          }
+          while (processing.length > 0) {
+            var next = processing[0], deps = next.member.map(resolve).filter(Boolean).filter(isNew);
+            if (deps.length === 0) {
+              sorted[next["@id"]] = next;
+              processing.shift();
+            } else {
+              processing = deps.concat(processing);
+            }
+          }
+        }
+        changes2.relation = Object.values(sorted);
+        return changes2;
       }
-      return result;
-    },
-    parentMultipolygons: function(entity) {
-      return this.parentRelations(entity).filter(function(relation) {
-        return relation.isMultipolygon();
-      });
-    },
-    childNodes: function(entity) {
-      if (this._childNodes[entity.id])
-        return this._childNodes[entity.id];
-      if (!entity.nodes)
-        return [];
-      var nodes = [];
-      for (var i2 = 0; i2 < entity.nodes.length; i2++) {
-        nodes[i2] = this.entity(entity.nodes[i2]);
+      function rep2(entity) {
+        return entity.asJXON(changeset_id);
       }
-      if (debug)
-        Object.freeze(nodes);
-      this._childNodes[entity.id] = nodes;
-      return this._childNodes[entity.id];
-    },
-    base: function() {
       return {
-        "entities": Object.getPrototypeOf(this.entities),
-        "parentWays": Object.getPrototypeOf(this._parentWays),
-        "parentRels": Object.getPrototypeOf(this._parentRels)
+        osmChange: {
+          "@version": 0.6,
+          "@generator": "iD",
+          "create": sort(nest(changes.created.map(rep2), ["node", "way", "relation"])),
+          "modify": nest(changes.modified.map(rep2), ["node", "way", "relation"]),
+          "delete": Object.assign(nest(changes.deleted.map(rep2), ["relation", "way", "node"]), { "@if-unused": true })
+        }
       };
     },
-    rebase: function(entities, stack, force) {
-      var base = this.base();
-      var i2, j2, k, id2;
-      for (i2 = 0; i2 < entities.length; i2++) {
-        var entity = entities[i2];
-        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") {
-          for (j2 = 0; j2 < entity.nodes.length; j2++) {
-            id2 = entity.nodes[j2];
-            for (k = 1; k < stack.length; k++) {
-              var ents = stack[k].entities;
-              if (ents.hasOwnProperty(id2) && ents[id2] === void 0) {
-                delete ents[id2];
-              }
+    asGeoJSON: function() {
+      return {};
+    }
+  });
+
+  // modules/osm/note.js
+  function osmNote() {
+    if (!(this instanceof osmNote)) {
+      return new osmNote().initialize(arguments);
+    } else if (arguments.length) {
+      this.initialize(arguments);
+    }
+  }
+  osmNote.id = function() {
+    return osmNote.id.next--;
+  };
+  osmNote.id.next = -1;
+  Object.assign(osmNote.prototype, {
+    type: "note",
+    initialize: function(sources) {
+      for (var i2 = 0; i2 < sources.length; ++i2) {
+        var source = sources[i2];
+        for (var prop in source) {
+          if (Object.prototype.hasOwnProperty.call(source, prop)) {
+            if (source[prop] === void 0) {
+              delete this[prop];
+            } else {
+              this[prop] = source[prop];
             }
           }
         }
       }
-      for (i2 = 0; i2 < stack.length; i2++) {
-        stack[i2]._updateRebased();
+      if (!this.id) {
+        this.id = osmNote.id().toString();
       }
+      return this;
     },
-    _updateRebased: function() {
-      var base = this.base();
-      Object.keys(this._parentWays).forEach(function(child) {
-        if (base.parentWays[child]) {
-          base.parentWays[child].forEach(function(id2) {
-            if (!this.entities.hasOwnProperty(id2)) {
-              this._parentWays[child].add(id2);
-            }
-          }, this);
-        }
-      }, this);
-      Object.keys(this._parentRels).forEach(function(child) {
-        if (base.parentRels[child]) {
-          base.parentRels[child].forEach(function(id2) {
-            if (!this.entities.hasOwnProperty(id2)) {
-              this._parentRels[child].add(id2);
-            }
-          }, this);
-        }
-      }, this);
-      this.transients = {};
+    extent: function() {
+      return new geoExtent(this.loc);
     },
-    _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
-      parentWays = parentWays || this._parentWays;
-      parentRels = parentRels || this._parentRels;
-      var type3 = entity && entity.type || oldentity && oldentity.type;
-      var removed, added, i2;
-      if (type3 === "way") {
-        if (oldentity && entity) {
-          removed = utilArrayDifference(oldentity.nodes, entity.nodes);
-          added = utilArrayDifference(entity.nodes, oldentity.nodes);
-        } else if (oldentity) {
-          removed = oldentity.nodes;
-          added = [];
-        } else if (entity) {
-          removed = [];
-          added = entity.nodes;
-        }
-        for (i2 = 0; i2 < removed.length; i2++) {
-          parentWays[removed[i2]] = new Set(parentWays[removed[i2]]);
-          parentWays[removed[i2]].delete(oldentity.id);
-        }
-        for (i2 = 0; i2 < added.length; i2++) {
-          parentWays[added[i2]] = new Set(parentWays[added[i2]]);
-          parentWays[added[i2]].add(entity.id);
-        }
-      } else if (type3 === "relation") {
-        var oldentityMemberIDs = oldentity ? oldentity.members.map(function(m) {
-          return m.id;
-        }) : [];
-        var entityMemberIDs = entity ? entity.members.map(function(m) {
-          return m.id;
-        }) : [];
-        if (oldentity && entity) {
-          removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
-          added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
-        } else if (oldentity) {
-          removed = oldentityMemberIDs;
-          added = [];
-        } else if (entity) {
-          removed = [];
-          added = entityMemberIDs;
+    update: function(attrs) {
+      return osmNote(this, attrs);
+    },
+    isNew: function() {
+      return this.id < 0;
+    },
+    move: function(loc) {
+      return this.update({ loc });
+    }
+  });
+
+  // modules/osm/relation.js
+  function osmRelation() {
+    if (!(this instanceof osmRelation)) {
+      return new osmRelation().initialize(arguments);
+    } else if (arguments.length) {
+      this.initialize(arguments);
+    }
+  }
+  osmEntity.relation = osmRelation;
+  osmRelation.prototype = Object.create(osmEntity.prototype);
+  osmRelation.creationOrder = function(a, b) {
+    var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
+    var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
+    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];
+      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 });
+      });
+      copy2 = copy2.update({ members });
+      copies[this.id] = copy2;
+      return copy2;
+    },
+    extent: function(resolver, memo) {
+      return resolver.transient(this, "extent", function() {
+        if (memo && memo[this.id])
+          return geoExtent();
+        memo = memo || {};
+        memo[this.id] = true;
+        var extent = geoExtent();
+        for (var i2 = 0; i2 < this.members.length; i2++) {
+          var member = resolver.hasEntity(this.members[i2].id);
+          if (member) {
+            extent._extend(member.extent(resolver, memo));
+          }
         }
-        for (i2 = 0; i2 < removed.length; i2++) {
-          parentRels[removed[i2]] = new Set(parentRels[removed[i2]]);
-          parentRels[removed[i2]].delete(oldentity.id);
+        return extent;
+      });
+    },
+    geometry: function(graph) {
+      return graph.transient(this, "geometry", function() {
+        return this.isMultipolygon() ? "area" : "relation";
+      });
+    },
+    isDegenerate: function() {
+      return this.members.length === 0;
+    },
+    // Return an array of members, each extended with an 'index' property whose value
+    // is the member index.
+    indexedMembers: function() {
+      var result = new Array(this.members.length);
+      for (var i2 = 0; i2 < this.members.length; i2++) {
+        result[i2] = Object.assign({}, this.members[i2], { index: i2 });
+      }
+      return result;
+    },
+    // Return the first member with the given role. A copy of the member object
+    // is returned, extended with an 'index' property whose value is the member index.
+    memberByRole: function(role) {
+      for (var i2 = 0; i2 < this.members.length; i2++) {
+        if (this.members[i2].role === role) {
+          return Object.assign({}, this.members[i2], { index: i2 });
         }
-        for (i2 = 0; i2 < added.length; i2++) {
-          parentRels[added[i2]] = new Set(parentRels[added[i2]]);
-          parentRels[added[i2]].add(entity.id);
+      }
+    },
+    // Same as memberByRole, but returns all members with the given role
+    membersByRole: function(role) {
+      var result = [];
+      for (var i2 = 0; i2 < this.members.length; i2++) {
+        if (this.members[i2].role === role) {
+          result.push(Object.assign({}, this.members[i2], { index: i2 }));
         }
       }
+      return result;
     },
-    replace: function(entity) {
-      if (this.entities[entity.id] === entity)
-        return this;
-      return this.update(function() {
-        this._updateCalculated(this.entities[entity.id], entity);
-        this.entities[entity.id] = entity;
-      });
+    // Return the first member with the given id. A copy of the member object
+    // is returned, extended with an 'index' property whose value is the member index.
+    memberById: function(id2) {
+      for (var i2 = 0; i2 < this.members.length; i2++) {
+        if (this.members[i2].id === id2) {
+          return Object.assign({}, this.members[i2], { index: i2 });
+        }
+      }
     },
-    remove: function(entity) {
-      return this.update(function() {
-        this._updateCalculated(entity, void 0);
-        this.entities[entity.id] = void 0;
+    // Return the first member with the given id and role. A copy of the member object
+    // is returned, extended with an 'index' property whose value is the member index.
+    memberByIdAndRole: function(id2, role) {
+      for (var i2 = 0; i2 < this.members.length; i2++) {
+        if (this.members[i2].id === id2 && this.members[i2].role === role) {
+          return Object.assign({}, this.members[i2], { index: i2 });
+        }
+      }
+    },
+    addMember: function(member, index) {
+      var members = this.members.slice();
+      members.splice(index === void 0 ? members.length : index, 0, member);
+      return this.update({ members });
+    },
+    updateMember: function(member, index) {
+      var members = this.members.slice();
+      members.splice(index, 1, Object.assign({}, members[index], member));
+      return this.update({ members });
+    },
+    removeMember: function(index) {
+      var members = this.members.slice();
+      members.splice(index, 1);
+      return this.update({ members });
+    },
+    removeMembersWithID: function(id2) {
+      var members = this.members.filter(function(m) {
+        return m.id !== id2;
       });
+      return this.update({ members });
     },
-    revert: function(id2) {
-      var baseEntity = this.base().entities[id2];
-      var headEntity = this.entities[id2];
-      if (headEntity === baseEntity)
+    moveMember: function(fromIndex, toIndex) {
+      var members = this.members.slice();
+      members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
+      return this.update({ members });
+    },
+    // Wherever a member appears with id `needle.id`, replace it with a member
+    // with id `replacement.id`, type `replacement.type`, and the original role,
+    // 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;
-      return this.update(function() {
-        this._updateCalculated(headEntity, baseEntity);
-        delete this.entities[id2];
-      });
+      var members = [];
+      for (var i2 = 0; i2 < this.members.length; i2++) {
+        var member = this.members[i2];
+        if (member.id !== needle.id) {
+          members.push(member);
+        } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
+          members.push({ id: replacement.id, type: replacement.type, role: member.role });
+        }
+      }
+      return this.update({ members });
     },
-    update: function() {
-      var graph = this.frozen ? coreGraph(this, true) : this;
-      for (var i2 = 0; i2 < arguments.length; i2++) {
-        arguments[i2].call(graph, graph);
+    asJXON: function(changeset_id) {
+      var r = {
+        relation: {
+          "@id": this.osmId(),
+          "@version": this.version || 0,
+          member: this.members.map(function(member) {
+            return {
+              keyAttributes: {
+                type: member.type,
+                role: member.role,
+                ref: osmEntity.id.toOSM(member.id)
+              }
+            };
+          }, this),
+          tag: Object.keys(this.tags).map(function(k) {
+            return { keyAttributes: { k, v: this.tags[k] } };
+          }, this)
+        }
+      };
+      if (changeset_id) {
+        r.relation["@changeset"] = changeset_id;
       }
-      if (this.frozen)
-        graph.frozen = true;
-      return graph;
+      return r;
     },
-    load: function(entities) {
-      var base = this.base();
-      this.entities = Object.create(base.entities);
-      for (var i2 in entities) {
-        this.entities[i2] = entities[i2];
-        this._updateCalculated(base.entities[i2], this.entities[i2]);
+    asGeoJSON: function(resolver) {
+      return resolver.transient(this, "GeoJSON", function() {
+        if (this.isMultipolygon()) {
+          return {
+            type: "MultiPolygon",
+            coordinates: this.multipolygon(resolver)
+          };
+        } else {
+          return {
+            type: "FeatureCollection",
+            properties: this.tags,
+            features: this.members.map(function(member) {
+              return Object.assign({ role: member.role }, resolver.entity(member.id).asGeoJSON(resolver));
+            })
+          };
+        }
+      });
+    },
+    area: function(resolver) {
+      return resolver.transient(this, "area", function() {
+        return area_default(this.asGeoJSON(resolver));
+      });
+    },
+    isMultipolygon: function() {
+      return this.tags.type === "multipolygon";
+    },
+    isComplete: function(resolver) {
+      for (var i2 = 0; i2 < this.members.length; i2++) {
+        if (!resolver.hasEntity(this.members[i2].id)) {
+          return false;
+        }
       }
-      return this;
-    }
-  };
-
-  // modules/osm/intersection.js
-  function osmTurn(turn) {
-    if (!(this instanceof osmTurn)) {
-      return new osmTurn(turn);
-    }
-    Object.assign(this, turn);
-  }
-  function osmIntersection(graph, startVertexId, maxDistance) {
-    maxDistance = maxDistance || 30;
-    var vgraph = coreGraph();
-    var i2, j2, k;
-    function memberOfRestriction(entity) {
-      return graph.parentRelations(entity).some(function(r) {
-        return r.isRestriction();
+      return true;
+    },
+    hasFromViaTo: function() {
+      return this.members.some(function(m) {
+        return m.role === "from";
+      }) && this.members.some(function(m) {
+        return m.role === "via";
+      }) && this.members.some(function(m) {
+        return m.role === "to";
       });
-    }
-    function isRoad(way2) {
-      if (way2.isArea() || way2.isDegenerate())
+    },
+    isRestriction: function() {
+      return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
+    },
+    isValidRestriction: function() {
+      if (!this.isRestriction())
         return false;
-      var 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,
-        "service": true,
-        "road": true,
-        "track": true
+      var froms = this.members.filter(function(m) {
+        return m.role === "from";
+      });
+      var vias = this.members.filter(function(m) {
+        return m.role === "via";
+      });
+      var tos = this.members.filter(function(m) {
+        return m.role === "to";
+      });
+      if (froms.length !== 1 && this.tags.restriction !== "no_entry")
+        return false;
+      if (froms.some(function(m) {
+        return m.type !== "way";
+      }))
+        return false;
+      if (tos.length !== 1 && this.tags.restriction !== "no_exit")
+        return false;
+      if (tos.some(function(m) {
+        return m.type !== "way";
+      }))
+        return false;
+      if (vias.length === 0)
+        return false;
+      if (vias.length > 1 && vias.some(function(m) {
+        return m.type !== "way";
+      }))
+        return false;
+      return true;
+    },
+    isConnectivity: function() {
+      return !!(this.tags.type && this.tags.type.match(/^connectivity:?/));
+    },
+    // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
+    // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
+    //
+    // This corresponds to the structure needed for rendering a multipolygon path using a
+    // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
+    //
+    // In the case of invalid geometries, this function will still return a result which
+    // includes the nodes of all way members, but some Nds may be unclosed and some inner
+    // rings not matched with the intended outer ring.
+    //
+    multipolygon: function(resolver) {
+      var outers = this.members.filter(function(m) {
+        return "outer" === (m.role || "outer");
+      });
+      var inners = this.members.filter(function(m) {
+        return "inner" === m.role;
+      });
+      outers = osmJoinWays(outers, resolver);
+      inners = osmJoinWays(inners, resolver);
+      var sequenceToLineString = function(sequence) {
+        if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
+          sequence.nodes.push(sequence.nodes[0]);
+        }
+        return sequence.nodes.map(function(node) {
+          return node.loc;
+        });
       };
-      return roads[way2.tags.highway];
-    }
-    var startNode = graph.entity(startVertexId);
-    var checkVertices = [startNode];
-    var checkWays;
-    var vertices = [];
-    var vertexIds = [];
-    var vertex;
-    var ways = [];
-    var wayIds = [];
-    var way;
-    var nodes = [];
-    var node;
-    var parents = [];
-    var parent;
-    var actions = [];
-    while (checkVertices.length) {
-      vertex = checkVertices.pop();
-      checkWays = graph.parentWays(vertex);
-      var hasWays = false;
-      for (i2 = 0; i2 < checkWays.length; i2++) {
-        way = checkWays[i2];
-        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;
-          var hasParents = false;
-          parents = graph.parentWays(node);
-          for (k = 0; k < parents.length; k++) {
-            parent = parents[k];
-            if (parent === way)
-              continue;
-            if (ways.indexOf(parent) !== -1)
-              continue;
-            if (!isRoad(parent))
-              continue;
-            hasParents = true;
-            break;
+      outers = outers.map(sequenceToLineString);
+      inners = inners.map(sequenceToLineString);
+      var result = outers.map(function(o2) {
+        return [area_default({ type: "Polygon", coordinates: [o2] }) > 2 * Math.PI ? o2.reverse() : o2];
+      });
+      function findOuter(inner2) {
+        var o2, outer;
+        for (o2 = 0; o2 < outers.length; o2++) {
+          outer = outers[o2];
+          if (geoPolygonContainsPolygon(outer, inner2)) {
+            return o2;
           }
-          if (hasParents) {
-            checkVertices.push(node);
+        }
+        for (o2 = 0; o2 < outers.length; o2++) {
+          outer = outers[o2];
+          if (geoPolygonIntersectsPolygon(outer, inner2, false)) {
+            return o2;
           }
         }
       }
-      if (hasWays) {
-        vertices.push(vertex);
-      }
-    }
-    vertices = utilArrayUniq(vertices);
-    ways = utilArrayUniq(ways);
-    ways.forEach(function(way2) {
-      graph.childNodes(way2).forEach(function(node2) {
-        vgraph = vgraph.replace(node2);
-      });
-      vgraph = vgraph.replace(way2);
-      graph.parentRelations(way2).forEach(function(relation) {
-        if (relation.isRestriction()) {
-          if (relation.isValidRestriction(graph)) {
-            vgraph = vgraph.replace(relation);
-          } else if (relation.isComplete(graph)) {
-            actions.push(actionDeleteRelation(relation.id));
-          }
+      for (var i2 = 0; i2 < inners.length; i2++) {
+        var inner = inners[i2];
+        if (area_default({ type: "Polygon", coordinates: [inner] }) < 2 * Math.PI) {
+          inner = inner.reverse();
+        }
+        var o = findOuter(inners[i2]);
+        if (o !== void 0) {
+          result[o].push(inners[i2]);
+        } else {
+          result.push([inners[i2]]);
         }
-      });
-    });
-    ways.forEach(function(w) {
-      var way2 = vgraph.entity(w.id);
-      if (way2.tags.oneway === "-1") {
-        var action = actionReverse(way2.id, { reverseOneway: true });
-        actions.push(action);
-        vgraph = action(vgraph);
       }
-    });
-    var origCount = osmEntity.id.next.way;
-    vertices.forEach(function(v) {
-      var splitAll = actionSplit([v.id]).keepHistoryOn("first");
-      if (!splitAll.disabled(vgraph)) {
-        splitAll.ways(vgraph).forEach(function(way2) {
-          var splitOne = actionSplit([v.id]).limitWays([way2.id]).keepHistoryOn("first");
-          actions.push(splitOne);
-          vgraph = splitOne(vgraph);
-        });
+      return result;
+    }
+  });
+
+  // modules/osm/qa_item.js
+  var QAItem = class _QAItem {
+    constructor(loc, service, itemType, id2, props) {
+      this.loc = loc;
+      this.service = service.title;
+      this.itemType = itemType;
+      this.id = id2 ? id2 : `${_QAItem.id()}`;
+      this.update(props);
+      if (service && typeof service.getIcon === "function") {
+        this.icon = service.getIcon(itemType);
       }
-    });
-    osmEntity.id.next.way = origCount;
-    vertexIds = vertices.map(function(v) {
-      return v.id;
-    });
-    vertices = [];
-    ways = [];
-    vertexIds.forEach(function(id2) {
-      var vertex2 = vgraph.entity(id2);
-      var parents2 = vgraph.parentWays(vertex2);
-      vertices.push(vertex2);
-      ways = ways.concat(parents2);
-    });
-    vertices = utilArrayUniq(vertices);
-    ways = utilArrayUniq(ways);
-    vertexIds = vertices.map(function(v) {
-      return v.id;
-    });
-    wayIds = ways.map(function(w) {
-      return w.id;
-    });
-    function withMetadata(way2, vertexIds2) {
-      var __oneWay = way2.isOneWay();
-      var __first = vertexIds2.indexOf(way2.first()) !== -1;
-      var __last = vertexIds2.indexOf(way2.last()) !== -1;
-      var __via = __first && __last;
-      var __from = __first && !__oneWay || __last;
-      var __to = __first || __last && !__oneWay;
-      return way2.update({
-        __first,
-        __last,
-        __from,
-        __via,
-        __to,
-        __oneWay
-      });
     }
-    ways = [];
-    wayIds.forEach(function(id2) {
-      var way2 = withMetadata(vgraph.entity(id2), vertexIds);
-      vgraph = vgraph.replace(way2);
-      ways.push(way2);
-    });
-    var keepGoing;
-    var removeWayIds = [];
-    var removeVertexIds = [];
-    do {
-      keepGoing = false;
-      checkVertices = vertexIds.slice();
-      for (i2 = 0; i2 < checkVertices.length; i2++) {
-        var vertexId = checkVertices[i2];
-        vertex = vgraph.hasEntity(vertexId);
-        if (!vertex) {
-          if (vertexIds.indexOf(vertexId) !== -1) {
-            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
-          }
-          removeVertexIds.push(vertexId);
-          continue;
-        }
-        parents = vgraph.parentWays(vertex);
-        if (parents.length < 3) {
-          if (vertexIds.indexOf(vertexId) !== -1) {
-            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
-          }
+    update(props) {
+      const { loc, service, itemType, id: id2 } = this;
+      Object.keys(props).forEach((prop) => this[prop] = props[prop]);
+      this.loc = loc;
+      this.service = service;
+      this.itemType = itemType;
+      this.id = id2;
+      return this;
+    }
+    // Generic handling for newly created QAItems
+    static id() {
+      return this.nextId--;
+    }
+  };
+  QAItem.nextId = -1;
+
+  // modules/actions/split.js
+  function actionSplit(nodeIds, newWayIds) {
+    if (typeof nodeIds === "string")
+      nodeIds = [nodeIds];
+    var _wayIDs;
+    var _keepHistoryOn = "longest";
+    var _createdWayIDs = [];
+    function dist(graph, nA, nB) {
+      var locA = graph.entity(nA).loc;
+      var locB = graph.entity(nB).loc;
+      var epsilon3 = 1e-6;
+      return locA && locB ? geoSphericalDistance(locA, locB) : epsilon3;
+    }
+    function splitArea(nodes, idxA, graph) {
+      var lengths = new Array(nodes.length);
+      var length;
+      var i2;
+      var best = 0;
+      var idxB;
+      function wrap2(index) {
+        return utilWrap(index, nodes.length);
+      }
+      length = 0;
+      for (i2 = wrap2(idxA + 1); i2 !== idxA; i2 = wrap2(i2 + 1)) {
+        length += dist(graph, nodes[i2], nodes[wrap2(i2 - 1)]);
+        lengths[i2] = length;
+      }
+      length = 0;
+      for (i2 = wrap2(idxA - 1); i2 !== idxA; i2 = wrap2(i2 - 1)) {
+        length += dist(graph, nodes[i2], nodes[wrap2(i2 + 1)]);
+        if (length < lengths[i2]) {
+          lengths[i2] = length;
         }
-        if (parents.length === 2) {
-          var a = parents[0];
-          var b = parents[1];
-          var aIsLeaf = a && !a.__via;
-          var bIsLeaf = b && !b.__via;
-          var leaf, survivor;
-          if (aIsLeaf && !bIsLeaf) {
-            leaf = a;
-            survivor = b;
-          } else if (!aIsLeaf && bIsLeaf) {
-            leaf = b;
-            survivor = a;
-          }
-          if (leaf && survivor) {
-            survivor = withMetadata(survivor, vertexIds);
-            vgraph = vgraph.replace(survivor).remove(leaf);
-            removeWayIds.push(leaf.id);
-            keepGoing = true;
-          }
+      }
+      for (i2 = 0; i2 < nodes.length; i2++) {
+        var cost = lengths[i2] / dist(graph, nodes[idxA], nodes[i2]);
+        if (cost > best) {
+          idxB = i2;
+          best = cost;
         }
-        parents = vgraph.parentWays(vertex);
-        if (parents.length < 2) {
-          if (vertexIds.indexOf(vertexId) !== -1) {
-            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
-          }
-          removeVertexIds.push(vertexId);
-          keepGoing = true;
+      }
+      return idxB;
+    }
+    function totalLengthBetweenNodes(graph, nodes) {
+      var totalLength = 0;
+      for (var i2 = 0; i2 < nodes.length - 1; i2++) {
+        totalLength += dist(graph, nodes[i2], nodes[i2 + 1]);
+      }
+      return totalLength;
+    }
+    function split(graph, nodeId, wayA, newWayId) {
+      var wayB = osmWay({ id: newWayId, tags: wayA.tags });
+      var origNodes = wayA.nodes.slice();
+      var nodesA;
+      var nodesB;
+      var isArea = wayA.isArea();
+      var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
+      if (wayA.isClosed()) {
+        var nodes = wayA.nodes.slice(0, -1);
+        var idxA = nodes.indexOf(nodeId);
+        var idxB = splitArea(nodes, idxA, graph);
+        if (idxB < idxA) {
+          nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
+          nodesB = nodes.slice(idxB, idxA + 1);
+        } else {
+          nodesA = nodes.slice(idxA, idxB + 1);
+          nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
         }
-        if (parents.length < 1) {
-          vgraph = vgraph.remove(vertex);
+      } else {
+        var idx = wayA.nodes.indexOf(nodeId, 1);
+        nodesA = wayA.nodes.slice(0, idx + 1);
+        nodesB = wayA.nodes.slice(idx);
+      }
+      var lengthA = totalLengthBetweenNodes(graph, nodesA);
+      var lengthB = totalLengthBetweenNodes(graph, nodesB);
+      if (_keepHistoryOn === "longest" && lengthB > lengthA) {
+        wayA = wayA.update({ nodes: nodesB });
+        wayB = wayB.update({ nodes: nodesA });
+        var temp = lengthA;
+        lengthA = lengthB;
+        lengthB = temp;
+      } else {
+        wayA = wayA.update({ nodes: nodesA });
+        wayB = wayB.update({ nodes: nodesB });
+      }
+      if (wayA.tags.step_count) {
+        var stepCount = Number(wayA.tags.step_count);
+        if (stepCount && // ensure a number
+        isFinite(stepCount) && // ensure positive
+        stepCount > 0 && // ensure integer
+        Math.round(stepCount) === stepCount) {
+          var tagsA = Object.assign({}, wayA.tags);
+          var tagsB = Object.assign({}, wayB.tags);
+          var ratioA = lengthA / (lengthA + lengthB);
+          var countA = Math.round(stepCount * ratioA);
+          tagsA.step_count = countA.toString();
+          tagsB.step_count = (stepCount - countA).toString();
+          wayA = wayA.update({ tags: tagsA });
+          wayB = wayB.update({ tags: tagsB });
         }
       }
-    } while (keepGoing);
-    vertices = vertices.filter(function(vertex2) {
-      return removeVertexIds.indexOf(vertex2.id) === -1;
-    }).map(function(vertex2) {
-      return vgraph.entity(vertex2.id);
-    });
-    ways = ways.filter(function(way2) {
-      return removeWayIds.indexOf(way2.id) === -1;
-    }).map(function(way2) {
-      return vgraph.entity(way2.id);
-    });
-    var intersection = {
-      graph: vgraph,
-      actions,
-      vertices,
-      ways
-    };
-    intersection.turns = function(fromWayId, maxViaWay) {
-      if (!fromWayId)
-        return [];
-      if (!maxViaWay)
-        maxViaWay = 0;
-      var vgraph2 = intersection.graph;
-      var keyVertexIds = intersection.vertices.map(function(v) {
-        return v.id;
-      });
-      var start2 = vgraph2.entity(fromWayId);
-      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;
-        currPath.push(entity.id);
-        currRestrictions = (currRestrictions || []).slice();
-        var i3, j3;
-        if (entity.type === "node") {
-          var parents2 = vgraph2.parentWays(entity);
-          var nextWays = [];
-          for (i3 = 0; i3 < parents2.length; i3++) {
-            var way2 = parents2[i3];
-            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];
-              var f2 = restriction.memberByRole("from");
-              var v = restriction.membersByRole("via");
-              var t = restriction.memberByRole("to");
-              var isOnly = /^only_/.test(restriction.tags.restriction);
-              var matchesFrom = f2.id === fromWayId;
-              var matchesViaTo = false;
-              var isAlongOnlyPath = false;
-              if (t.id === way2.id) {
-                if (v.length === 1 && v[0].type === "node") {
-                  matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
-                } else {
-                  var pathVias = [];
-                  for (k = 2; k < currPath.length; k += 2) {
-                    pathVias.push(currPath[k]);
-                  }
-                  var restrictionVias = [];
-                  for (k = 0; k < v.length; k++) {
-                    if (v[k].type === "way") {
-                      restrictionVias.push(v[k].id);
-                    }
-                  }
-                  var diff = utilArrayDifference(pathVias, restrictionVias);
-                  matchesViaTo = !diff.length;
-                }
-              } else if (isOnly) {
-                for (k = 0; k < v.length; k++) {
-                  if (v[k].type === "way" && v[k].id === way2.id) {
-                    isAlongOnlyPath = true;
+      graph = graph.replace(wayA);
+      graph = graph.replace(wayB);
+      graph.parentRelations(wayA).forEach(function(relation) {
+        var member;
+        if (relation.hasFromViaTo()) {
+          var f2 = relation.memberByRole("from");
+          var v = relation.membersByRole("via");
+          var t = relation.memberByRole("to");
+          var i2;
+          if (f2.id === wayA.id || t.id === wayA.id) {
+            var keepB = false;
+            if (v.length === 1 && v[0].type === "node") {
+              keepB = wayB.contains(v[0].id);
+            } else {
+              for (i2 = 0; i2 < v.length; i2++) {
+                if (v[i2].type === "way") {
+                  var wayVia = graph.hasEntity(v[i2].id);
+                  if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
+                    keepB = true;
                     break;
                   }
                 }
               }
-              if (matchesViaTo) {
-                if (isOnly) {
-                  restrict = { id: restriction.id, direct: matchesFrom, from: f2.id, only: true, end: true };
-                } else {
-                  restrict = { id: restriction.id, direct: matchesFrom, from: f2.id, no: true, end: true };
-                }
-              } else {
-                if (isAlongOnlyPath) {
-                  restrict = { id: restriction.id, direct: false, from: f2.id, only: true, end: false };
-                } else if (isOnly) {
-                  restrict = { id: restriction.id, direct: false, from: f2.id, no: true, end: true };
-                }
-              }
-              if (restrict && restrict.direct)
-                break;
             }
-            nextWays.push({ way: way2, restrict });
-          }
-          nextWays.forEach(function(nextWay) {
-            step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
-          });
-        } else {
-          if (currPath.length >= 3) {
-            var turnPath = currPath.slice();
-            if (matchedRestriction && matchedRestriction.direct === false) {
-              for (i3 = 0; i3 < turnPath.length; i3++) {
-                if (turnPath[i3] === matchedRestriction.from) {
-                  turnPath = turnPath.slice(i3);
-                  break;
-                }
-              }
+            if (keepB) {
+              relation = relation.replaceMember(wayA, wayB);
+              graph = graph.replace(relation);
             }
-            var turn = pathToTurn(turnPath);
-            if (turn) {
-              if (matchedRestriction) {
-                turn.restrictionID = matchedRestriction.id;
-                turn.no = matchedRestriction.no;
-                turn.only = matchedRestriction.only;
-                turn.direct = matchedRestriction.direct;
+          } else {
+            for (i2 = 0; i2 < v.length; i2++) {
+              if (v[i2].type === "way" && v[i2].id === wayA.id) {
+                member = {
+                  id: wayB.id,
+                  type: "way",
+                  role: "via"
+                };
+                graph = actionAddMember(relation.id, member, v[i2].index + 1)(graph);
+                break;
               }
-              turns.push(osmTurn(turn));
             }
-            if (currPath[0] === currPath[2])
-              return;
-          }
-          if (matchedRestriction && matchedRestriction.end)
-            return;
-          var n1 = vgraph2.entity(entity.first());
-          var n2 = vgraph2.entity(entity.last());
-          var dist = geoSphericalDistance(n1.loc, n2.loc);
-          var nextNodes = [];
-          if (currPath.length > 1) {
-            if (dist > maxDistance)
-              return;
-            if (!entity.__via)
-              return;
-          }
-          if (!entity.__oneWay && keyVertexIds.indexOf(n1.id) !== -1 && currPath.indexOf(n1.id) === -1) {
-            nextNodes.push(n1);
           }
-          if (keyVertexIds.indexOf(n2.id) !== -1 && currPath.indexOf(n2.id) === -1) {
-            nextNodes.push(n2);
-          }
-          nextNodes.forEach(function(nextNode) {
-            var fromRestrictions = vgraph2.parentRelations(entity).filter(function(r) {
-              if (!r.isRestriction())
-                return false;
-              var f3 = r.memberByRole("from");
-              if (!f3 || f3.id !== entity.id)
-                return false;
-              var isOnly2 = /^only_/.test(r.tags.restriction);
-              if (!isOnly2)
-                return true;
-              var isOnlyVia = false;
-              var v2 = r.membersByRole("via");
-              if (v2.length === 1 && v2[0].type === "node") {
-                isOnlyVia = v2[0].id === nextNode.id;
-              } else {
-                for (var i4 = 0; i4 < v2.length; i4++) {
-                  if (v2[i4].type !== "way")
-                    continue;
-                  var viaWay = vgraph2.entity(v2[i4].id);
-                  if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
-                    isOnlyVia = true;
-                    break;
-                  }
-                }
-              }
-              return isOnlyVia;
-            });
-            step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
-          });
-        }
-      }
-      function pathToTurn(path) {
-        if (path.length < 3)
-          return;
-        var fromWayId2, fromNodeId, fromVertexId;
-        var toWayId, toNodeId, toVertexId;
-        var viaWayIds, viaNodeId, isUturn;
-        fromWayId2 = path[0];
-        toWayId = path[path.length - 1];
-        if (path.length === 3 && fromWayId2 === toWayId) {
-          var way2 = vgraph2.entity(fromWayId2);
-          if (way2.__oneWay)
-            return null;
-          isUturn = true;
-          viaNodeId = fromVertexId = toVertexId = path[1];
-          fromNodeId = toNodeId = adjacentNode(fromWayId2, viaNodeId);
         } else {
-          isUturn = false;
-          fromVertexId = path[1];
-          fromNodeId = adjacentNode(fromWayId2, fromVertexId);
-          toVertexId = path[path.length - 2];
-          toNodeId = adjacentNode(toWayId, toVertexId);
-          if (path.length === 3) {
-            viaNodeId = path[1];
-          } else {
-            viaWayIds = path.filter(function(entityId) {
-              return entityId[0] === "w";
-            });
-            viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1);
+          if (relation === isOuter) {
+            graph = graph.replace(relation.mergeTags(wayA.tags));
+            graph = graph.replace(wayA.update({ tags: {} }));
+            graph = graph.replace(wayB.update({ tags: {} }));
           }
+          member = {
+            id: wayB.id,
+            type: "way",
+            role: relation.memberById(wayA.id).role
+          };
+          var insertPair = {
+            originalID: wayA.id,
+            insertedID: wayB.id,
+            nodes: origNodes
+          };
+          graph = actionAddMember(relation.id, member, void 0, insertPair)(graph);
         }
-        return {
-          key: path.join("_"),
-          path,
-          from: { node: fromNodeId, way: fromWayId2, vertex: fromVertexId },
-          via: { node: viaNodeId, ways: viaWayIds },
-          to: { node: toNodeId, way: toWayId, vertex: toVertexId },
-          u: isUturn
-        };
-        function adjacentNode(wayId, affixId) {
-          var nodes2 = vgraph2.entity(wayId).nodes;
-          return affixId === nodes2[0] ? nodes2[1] : nodes2[nodes2.length - 2];
-        }
-      }
-    };
-    return intersection;
-  }
-  function osmInferRestriction(graph, turn, projection2) {
-    var fromWay = graph.entity(turn.from.way);
-    var fromNode = graph.entity(turn.from.node);
-    var fromVertex = graph.entity(turn.from.vertex);
-    var toWay = graph.entity(turn.to.way);
-    var toNode = graph.entity(turn.to.node);
-    var toVertex = graph.entity(turn.to.vertex);
-    var fromOneWay = fromWay.tags.oneway === "yes";
-    var toOneWay = toWay.tags.oneway === "yes";
-    var angle2 = (geoAngle(fromVertex, fromNode, projection2) - geoAngle(toVertex, toNode, projection2)) * 180 / Math.PI;
-    while (angle2 < 0) {
-      angle2 += 360;
-    }
-    if (fromNode === toNode) {
-      return "no_u_turn";
-    }
-    if ((angle2 < 23 || angle2 > 336) && fromOneWay && toOneWay) {
-      return "no_u_turn";
-    }
-    if ((angle2 < 40 || angle2 > 319) && fromOneWay && toOneWay && turn.from.vertex !== turn.to.vertex) {
-      return "no_u_turn";
-    }
-    if (angle2 < 158) {
-      return "no_right_turn";
-    }
-    if (angle2 > 202) {
-      return "no_left_turn";
-    }
-    return "no_straight_on";
-  }
-
-  // modules/actions/merge_polygon.js
-  function actionMergePolygon(ids, newRelationId) {
-    function groupEntities(graph) {
-      var entities = ids.map(function(id2) {
-        return graph.entity(id2);
-      });
-      var geometryGroups = utilArrayGroupBy(entities, function(entity) {
-        if (entity.type === "way" && entity.isClosed()) {
-          return "closedWay";
-        } else if (entity.type === "relation" && entity.isMultipolygon()) {
-          return "multipolygon";
-        } else {
-          return "other";
-        }
-      });
-      return Object.assign(
-        { closedWay: [], multipolygon: [], other: [] },
-        geometryGroups
-      );
-    }
-    var action = function(graph) {
-      var entities = groupEntities(graph);
-      var polygons = entities.multipolygon.reduce(function(polygons2, m) {
-        return polygons2.concat(osmJoinWays(m.members, graph));
-      }, []).concat(entities.closedWay.map(function(d) {
-        var member = [{ id: d.id }];
-        member.nodes = graph.childNodes(d);
-        return member;
-      }));
-      var contained = polygons.map(function(w, i2) {
-        return polygons.map(function(d, n2) {
-          if (i2 === n2)
-            return null;
-          return geoPolygonContainsPolygon(
-            d.nodes.map(function(n3) {
-              return n3.loc;
-            }),
-            w.nodes.map(function(n3) {
-              return n3.loc;
-            })
-          );
-        });
       });
-      var members = [];
-      var outer = true;
-      while (polygons.length) {
-        extractUncontained(polygons);
-        polygons = polygons.filter(isContained);
-        contained = contained.filter(isContained).map(filterContained);
-      }
-      function isContained(d, i2) {
-        return contained[i2].some(function(val) {
-          return val;
+      if (!isOuter && isArea) {
+        var multipolygon = osmRelation({
+          tags: Object.assign({}, wayA.tags, { type: "multipolygon" }),
+          members: [
+            { id: wayA.id, role: "outer", type: "way" },
+            { id: wayB.id, role: "outer", type: "way" }
+          ]
         });
+        graph = graph.replace(multipolygon);
+        graph = graph.replace(wayA.update({ tags: {} }));
+        graph = graph.replace(wayB.update({ tags: {} }));
       }
-      function filterContained(d) {
-        return d.filter(isContained);
+      _createdWayIDs.push(wayB.id);
+      return graph;
+    }
+    var action = function(graph) {
+      _createdWayIDs = [];
+      var newWayIndex = 0;
+      for (var i2 = 0; i2 < nodeIds.length; i2++) {
+        var nodeId = nodeIds[i2];
+        var candidates = action.waysForNode(nodeId, graph);
+        for (var j2 = 0; j2 < candidates.length; j2++) {
+          graph = split(graph, nodeId, candidates[j2], newWayIds && newWayIds[newWayIndex]);
+          newWayIndex += 1;
+        }
       }
-      function extractUncontained(polygons2) {
-        polygons2.forEach(function(d, i2) {
-          if (!isContained(d, i2)) {
-            d.forEach(function(member) {
-              members.push({
-                type: "way",
-                id: member.id,
-                role: outer ? "outer" : "inner"
-              });
-            });
-          }
+      return graph;
+    };
+    action.getCreatedWayIDs = function() {
+      return _createdWayIDs;
+    };
+    action.waysForNode = function(nodeId, graph) {
+      var node = graph.entity(nodeId);
+      var splittableParents = graph.parentWays(node).filter(isSplittable);
+      if (!_wayIDs) {
+        var hasLine = splittableParents.some(function(parent) {
+          return parent.geometry(graph) === "line";
         });
-        outer = !outer;
-      }
-      var relation;
-      if (entities.multipolygon.length > 0) {
-        var oldestID = utilOldestID(entities.multipolygon.map((entity) => entity.id));
-        relation = entities.multipolygon.find((entity) => entity.id === oldestID);
-      } else {
-        relation = osmRelation({ id: newRelationId, tags: { type: "multipolygon" } });
-      }
-      entities.multipolygon.forEach(function(m) {
-        if (m.id !== relation.id) {
-          relation = relation.mergeTags(m.tags);
-          graph = graph.remove(m);
-        }
-      });
-      entities.closedWay.forEach(function(way) {
-        function isThisOuter(m) {
-          return m.id === way.id && m.role !== "inner";
+        if (hasLine) {
+          return splittableParents.filter(function(parent) {
+            return parent.geometry(graph) === "line";
+          });
         }
-        if (members.some(isThisOuter)) {
-          relation = relation.mergeTags(way.tags);
-          graph = graph.replace(way.update({ tags: {} }));
+      }
+      return splittableParents;
+      function isSplittable(parent) {
+        if (_wayIDs && _wayIDs.indexOf(parent.id) === -1)
+          return false;
+        if (parent.isClosed())
+          return true;
+        for (var i2 = 1; i2 < parent.nodes.length - 1; i2++) {
+          if (parent.nodes[i2] === nodeId)
+            return true;
         }
-      });
-      return graph.replace(relation.update({
-        members,
-        tags: utilObjectOmit(relation.tags, ["area"])
-      }));
+        return false;
+      }
+    };
+    action.ways = function(graph) {
+      return utilArrayUniq([].concat.apply([], nodeIds.map(function(nodeId) {
+        return action.waysForNode(nodeId, graph);
+      })));
     };
     action.disabled = function(graph) {
-      var entities = groupEntities(graph);
-      if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
-        return "not_eligible";
-      }
-      if (!entities.multipolygon.every(function(r) {
-        return r.isComplete(graph);
-      })) {
-        return "incomplete_relation";
-      }
-      if (!entities.multipolygon.length) {
-        var sharedMultipolygons = [];
-        entities.closedWay.forEach(function(way, i2) {
-          if (i2 === 0) {
-            sharedMultipolygons = graph.parentMultipolygons(way);
-          } else {
-            sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
-          }
-        });
-        sharedMultipolygons = sharedMultipolygons.filter(function(relation) {
-          return relation.members.length === entities.closedWay.length;
-        });
-        if (sharedMultipolygons.length) {
-          return "not_eligible";
-        }
-      } else if (entities.closedWay.some(function(way) {
-        return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
-      })) {
-        return "not_eligible";
+      for (var i2 = 0; i2 < nodeIds.length; i2++) {
+        var nodeId = nodeIds[i2];
+        var candidates = action.waysForNode(nodeId, graph);
+        if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
+          return "not_eligible";
+        }
       }
     };
+    action.limitWays = function(val) {
+      if (!arguments.length)
+        return _wayIDs;
+      _wayIDs = val;
+      return action;
+    };
+    action.keepHistoryOn = function(val) {
+      if (!arguments.length)
+        return _keepHistoryOn;
+      _keepHistoryOn = val;
+      return action;
+    };
     return action;
   }
 
-  // modules/actions/merge_remote_changes.js
-  var import_fast_deep_equal = __toESM(require_fast_deep_equal());
-
-  // node_modules/node-diff3/index.mjs
-  function LCS(buffer1, buffer2) {
-    let equivalenceClasses = {};
-    for (let j2 = 0; j2 < buffer2.length; j2++) {
-      const item = buffer2[j2];
-      if (equivalenceClasses[item]) {
-        equivalenceClasses[item].push(j2);
-      } else {
-        equivalenceClasses[item] = [j2];
-      }
-    }
-    const NULLRESULT = { buffer1index: -1, buffer2index: -1, chain: null };
-    let candidates = [NULLRESULT];
-    for (let i2 = 0; i2 < buffer1.length; i2++) {
-      const item = buffer1[i2];
-      const buffer2indices = equivalenceClasses[item] || [];
-      let r = 0;
-      let c = candidates[0];
-      for (let jx = 0; jx < buffer2indices.length; jx++) {
-        const j2 = buffer2indices[jx];
-        let s;
-        for (s = r; s < candidates.length; s++) {
-          if (candidates[s].buffer2index < j2 && (s === candidates.length - 1 || candidates[s + 1].buffer2index > j2)) {
-            break;
-          }
-        }
-        if (s < candidates.length) {
-          const newCandidate = { buffer1index: i2, buffer2index: j2, chain: candidates[s] };
-          if (r === candidates.length) {
-            candidates.push(c);
-          } else {
-            candidates[r] = c;
-          }
-          r = s + 1;
-          c = newCandidate;
-          if (r === candidates.length) {
-            break;
-          }
-        }
-      }
-      candidates[r] = c;
-    }
-    return candidates[candidates.length - 1];
-  }
-  function diffIndices(buffer1, buffer2) {
-    const lcs = LCS(buffer1, buffer2);
-    let result = [];
-    let tail1 = buffer1.length;
-    let tail2 = buffer2.length;
-    for (let candidate = lcs; candidate !== null; candidate = candidate.chain) {
-      const mismatchLength1 = tail1 - candidate.buffer1index - 1;
-      const mismatchLength2 = tail2 - candidate.buffer2index - 1;
-      tail1 = candidate.buffer1index;
-      tail2 = candidate.buffer2index;
-      if (mismatchLength1 || mismatchLength2) {
-        result.push({
-          buffer1: [tail1 + 1, mismatchLength1],
-          buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
-          buffer2: [tail2 + 1, mismatchLength2],
-          buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
-        });
-      }
-    }
-    result.reverse();
-    return result;
-  }
-  function diff3MergeRegions(a, o, b) {
-    let hunks = [];
-    function addHunk(h, ab) {
-      hunks.push({
-        ab,
-        oStart: h.buffer1[0],
-        oLength: h.buffer1[1],
-        abStart: h.buffer2[0],
-        abLength: h.buffer2[1]
-      });
-    }
-    diffIndices(o, a).forEach((item) => addHunk(item, "a"));
-    diffIndices(o, b).forEach((item) => addHunk(item, "b"));
-    hunks.sort((x, y) => x.oStart - y.oStart);
-    let results = [];
-    let currOffset = 0;
-    function advanceTo(endOffset) {
-      if (endOffset > currOffset) {
-        results.push({
-          stable: true,
-          buffer: "o",
-          bufferStart: currOffset,
-          bufferLength: endOffset - currOffset,
-          bufferContent: o.slice(currOffset, endOffset)
-        });
-        currOffset = endOffset;
-      }
-    }
-    while (hunks.length) {
-      let hunk = hunks.shift();
-      let regionStart = hunk.oStart;
-      let regionEnd = hunk.oStart + hunk.oLength;
-      let regionHunks = [hunk];
-      advanceTo(regionStart);
-      while (hunks.length) {
-        const nextHunk = hunks[0];
-        const nextHunkStart = nextHunk.oStart;
-        if (nextHunkStart > regionEnd)
-          break;
-        regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
-        regionHunks.push(hunks.shift());
-      }
-      if (regionHunks.length === 1) {
-        if (hunk.abLength > 0) {
-          const buffer = hunk.ab === "a" ? a : b;
-          results.push({
-            stable: true,
-            buffer: hunk.ab,
-            bufferStart: hunk.abStart,
-            bufferLength: hunk.abLength,
-            bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
-          });
-        }
-      } else {
-        let bounds = {
-          a: [a.length, -1, o.length, -1],
-          b: [b.length, -1, o.length, -1]
-        };
-        while (regionHunks.length) {
-          hunk = regionHunks.shift();
-          const oStart = hunk.oStart;
-          const oEnd = oStart + hunk.oLength;
-          const abStart = hunk.abStart;
-          const abEnd = abStart + hunk.abLength;
-          let b2 = bounds[hunk.ab];
-          b2[0] = Math.min(abStart, b2[0]);
-          b2[1] = Math.max(abEnd, b2[1]);
-          b2[2] = Math.min(oStart, b2[2]);
-          b2[3] = Math.max(oEnd, b2[3]);
-        }
-        const aStart = bounds.a[0] + (regionStart - bounds.a[2]);
-        const aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
-        const bStart = bounds.b[0] + (regionStart - bounds.b[2]);
-        const bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
-        let result = {
-          stable: false,
-          aStart,
-          aLength: aEnd - aStart,
-          aContent: a.slice(aStart, aEnd),
-          oStart: regionStart,
-          oLength: regionEnd - regionStart,
-          oContent: o.slice(regionStart, regionEnd),
-          bStart,
-          bLength: bEnd - bStart,
-          bContent: b.slice(bStart, bEnd)
-        };
-        results.push(result);
-      }
-      currOffset = regionEnd;
-    }
-    advanceTo(o.length);
-    return results;
-  }
-  function diff3Merge(a, o, b, options2) {
-    let defaults2 = {
-      excludeFalseConflicts: true,
-      stringSeparator: /\s+/
-    };
-    options2 = Object.assign(defaults2, options2);
-    if (typeof a === "string")
-      a = a.split(options2.stringSeparator);
-    if (typeof o === "string")
-      o = o.split(options2.stringSeparator);
-    if (typeof b === "string")
-      b = b.split(options2.stringSeparator);
-    let results = [];
-    const regions = diff3MergeRegions(a, o, b);
-    let okBuffer = [];
-    function flushOk() {
-      if (okBuffer.length) {
-        results.push({ ok: okBuffer });
-      }
-      okBuffer = [];
-    }
-    function isFalseConflict(a2, b2) {
-      if (a2.length !== b2.length)
-        return false;
-      for (let i2 = 0; i2 < a2.length; i2++) {
-        if (a2[i2] !== b2[i2])
-          return false;
-      }
-      return true;
+  // modules/core/graph.js
+  function 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);
+      this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
+      this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
+    } else {
+      this.entities = /* @__PURE__ */ Object.create({});
+      this._parentWays = /* @__PURE__ */ Object.create({});
+      this._parentRels = /* @__PURE__ */ Object.create({});
+      this.rebase(other || [], [this]);
     }
-    regions.forEach((region) => {
-      if (region.stable) {
-        okBuffer.push(...region.bufferContent);
-      } else {
-        if (options2.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
-          okBuffer.push(...region.aContent);
-        } else {
-          flushOk();
-          results.push({
-            conflict: {
-              a: region.aContent,
-              aIndex: region.aStart,
-              o: region.oContent,
-              oIndex: region.oStart,
-              b: region.bContent,
-              bIndex: region.bStart
-            }
-          });
-        }
-      }
-    });
-    flushOk();
-    return results;
+    this.transients = {};
+    this._childNodes = {};
+    this.frozen = !mutable;
   }
-
-  // modules/actions/merge_remote_changes.js
-  var import_lodash = __toESM(require_lodash());
-  function actionMergeRemoteChanges(id2, localGraph, remoteGraph, discardTags, formatUser) {
-    discardTags = discardTags || {};
-    var _option = "safe";
-    var _conflicts = [];
-    function user(d) {
-      return typeof formatUser === "function" ? formatUser(d) : (0, import_lodash.escape)(d);
-    }
-    function mergeLocation(remote, target) {
-      function pointEqual(a, b) {
-        var epsilon3 = 1e-6;
-        return Math.abs(a[0] - b[0]) < epsilon3 && Math.abs(a[1] - b[1]) < epsilon3;
+  coreGraph.prototype = {
+    hasEntity: function(id2) {
+      return this.entities[id2];
+    },
+    entity: function(id2) {
+      var entity = this.entities[id2];
+      if (!entity) {
+        entity = this.entities.__proto__[id2];
       }
-      if (_option === "force_local" || pointEqual(target.loc, remote.loc)) {
-        return target;
+      if (!entity) {
+        throw new Error("entity " + id2 + " not found");
       }
-      if (_option === "force_remote") {
-        return target.update({ loc: remote.loc });
+      return entity;
+    },
+    geometry: function(id2) {
+      return this.entity(id2).geometry(this);
+    },
+    transient: function(entity, key, fn) {
+      var id2 = entity.id;
+      var transients = this.transients[id2] || (this.transients[id2] = {});
+      if (transients[key] !== void 0) {
+        return transients[key];
       }
-      _conflicts.push(_t.html("merge_remote_changes.conflict.location", { user: { html: user(remote.user) } }));
-      return target;
-    }
-    function mergeNodes(base, remote, target) {
-      if (_option === "force_local" || (0, import_fast_deep_equal.default)(target.nodes, remote.nodes)) {
-        return target;
+      transients[key] = fn.call(entity);
+      return transients[key];
+    },
+    parentWays: function(entity) {
+      var parents = this._parentWays[entity.id];
+      var result = [];
+      if (parents) {
+        parents.forEach(function(id2) {
+          result.push(this.entity(id2));
+        }, this);
       }
-      if (_option === "force_remote") {
-        return target.update({ nodes: remote.nodes });
+      return result;
+    },
+    isPoi: function(entity) {
+      var parents = this._parentWays[entity.id];
+      return !parents || parents.size === 0;
+    },
+    isShared: function(entity) {
+      var parents = this._parentWays[entity.id];
+      return parents && parents.size > 1;
+    },
+    parentRelations: function(entity) {
+      var parents = this._parentRels[entity.id];
+      var result = [];
+      if (parents) {
+        parents.forEach(function(id2) {
+          result.push(this.entity(id2));
+        }, this);
       }
-      var ccount = _conflicts.length;
-      var o = base.nodes || [];
-      var a = target.nodes || [];
-      var b = remote.nodes || [];
+      return result;
+    },
+    parentMultipolygons: function(entity) {
+      return this.parentRelations(entity).filter(function(relation) {
+        return relation.isMultipolygon();
+      });
+    },
+    childNodes: function(entity) {
+      if (this._childNodes[entity.id])
+        return this._childNodes[entity.id];
+      if (!entity.nodes)
+        return [];
       var nodes = [];
-      var hunks = diff3Merge(a, o, b, { excludeFalseConflicts: true });
-      for (var i2 = 0; i2 < hunks.length; i2++) {
-        var hunk = hunks[i2];
-        if (hunk.ok) {
-          nodes.push.apply(nodes, hunk.ok);
-        } else {
-          var c = hunk.conflict;
-          if ((0, import_fast_deep_equal.default)(c.o, c.a)) {
-            nodes.push.apply(nodes, c.b);
-          } else if ((0, import_fast_deep_equal.default)(c.o, c.b)) {
-            nodes.push.apply(nodes, c.a);
-          } else {
-            _conflicts.push(_t.html("merge_remote_changes.conflict.nodelist", { user: { html: user(remote.user) } }));
-            break;
-          }
-        }
-      }
-      return _conflicts.length === ccount ? target.update({ nodes }) : target;
-    }
-    function mergeChildren(targetWay, children2, updates, graph) {
-      function isUsed(node2, targetWay2) {
-        var hasInterestingParent = graph.parentWays(node2).some(function(way) {
-          return way.id !== targetWay2.id;
-        });
-        return node2.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node2).length > 0;
+      for (var i2 = 0; i2 < entity.nodes.length; i2++) {
+        nodes[i2] = this.entity(entity.nodes[i2]);
       }
-      var ccount = _conflicts.length;
-      for (var i2 = 0; i2 < children2.length; i2++) {
-        var id3 = children2[i2];
-        var node = graph.hasEntity(id3);
-        if (targetWay.nodes.indexOf(id3) === -1) {
-          if (node && !isUsed(node, targetWay)) {
-            updates.removeIds.push(id3);
-          }
+      if (debug)
+        Object.freeze(nodes);
+      this._childNodes[entity.id] = nodes;
+      return this._childNodes[entity.id];
+    },
+    base: function() {
+      return {
+        "entities": Object.getPrototypeOf(this.entities),
+        "parentWays": Object.getPrototypeOf(this._parentWays),
+        "parentRels": Object.getPrototypeOf(this._parentRels)
+      };
+    },
+    // Unlike other graph methods, rebase mutates in place. This is because it
+    // is used only during the history operation that merges newly downloaded
+    // data into each state. To external consumers, it should appear as if the
+    // graph always contained the newly downloaded data.
+    rebase: function(entities, stack, force) {
+      var base = this.base();
+      var i2, j2, k, id2;
+      for (i2 = 0; i2 < entities.length; i2++) {
+        var entity = entities[i2];
+        if (!entity.visible || !force && base.entities[entity.id])
           continue;
-        }
-        var local = localGraph.hasEntity(id3);
-        var remote = remoteGraph.hasEntity(id3);
-        var target;
-        if (_option === "force_remote" && remote && remote.visible) {
-          updates.replacements.push(remote);
-        } else if (_option === "force_local" && local) {
-          target = osmEntity(local);
-          if (remote) {
-            target = target.update({ version: remote.version });
-          }
-          updates.replacements.push(target);
-        } else if (_option === "safe" && local && remote && local.version !== remote.version) {
-          target = osmEntity(local, { version: remote.version });
-          if (remote.visible) {
-            target = mergeLocation(remote, target);
-          } else {
-            _conflicts.push(_t.html("merge_remote_changes.conflict.deleted", { user: { html: user(remote.user) } }));
+        base.entities[entity.id] = entity;
+        this._updateCalculated(void 0, entity, base.parentWays, base.parentRels);
+        if (entity.type === "way") {
+          for (j2 = 0; j2 < entity.nodes.length; j2++) {
+            id2 = entity.nodes[j2];
+            for (k = 1; k < stack.length; k++) {
+              var ents = stack[k].entities;
+              if (ents.hasOwnProperty(id2) && ents[id2] === void 0) {
+                delete ents[id2];
+              }
+            }
           }
-          if (_conflicts.length !== ccount)
-            break;
-          updates.replacements.push(target);
         }
       }
-      return targetWay;
-    }
-    function updateChildren(updates, graph) {
-      for (var i2 = 0; i2 < updates.replacements.length; i2++) {
-        graph = graph.replace(updates.replacements[i2]);
-      }
-      if (updates.removeIds.length) {
-        graph = actionDeleteMultiple(updates.removeIds)(graph);
-      }
-      return graph;
-    }
-    function mergeMembers(remote, target) {
-      if (_option === "force_local" || (0, import_fast_deep_equal.default)(target.members, remote.members)) {
-        return target;
-      }
-      if (_option === "force_remote") {
-        return target.update({ members: remote.members });
-      }
-      _conflicts.push(_t.html("merge_remote_changes.conflict.memberlist", { user: { html: user(remote.user) } }));
-      return target;
-    }
-    function mergeTags(base, remote, target) {
-      if (_option === "force_local" || (0, import_fast_deep_equal.default)(target.tags, remote.tags)) {
-        return target;
-      }
-      if (_option === "force_remote") {
-        return target.update({ tags: remote.tags });
+      for (i2 = 0; i2 < stack.length; i2++) {
+        stack[i2]._updateRebased();
       }
-      var ccount = _conflicts.length;
-      var o = base.tags || {};
-      var a = target.tags || {};
-      var b = remote.tags || {};
-      var keys = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function(k2) {
-        return !discardTags[k2];
-      });
-      var tags = Object.assign({}, a);
-      var changed = false;
-      for (var i2 = 0; i2 < keys.length; i2++) {
-        var k = keys[i2];
-        if (o[k] !== b[k] && a[k] !== b[k]) {
-          if (o[k] !== a[k]) {
-            _conflicts.push(_t.html(
-              "merge_remote_changes.conflict.tags",
-              { tag: k, local: a[k], remote: b[k], user: { html: user(remote.user) } }
-            ));
-          } else {
-            if (b.hasOwnProperty(k)) {
-              tags[k] = b[k];
-            } else {
-              delete tags[k];
+    },
+    _updateRebased: function() {
+      var base = this.base();
+      Object.keys(this._parentWays).forEach(function(child) {
+        if (base.parentWays[child]) {
+          base.parentWays[child].forEach(function(id2) {
+            if (!this.entities.hasOwnProperty(id2)) {
+              this._parentWays[child].add(id2);
             }
-            changed = true;
-          }
+          }, this);
         }
-      }
-      return changed && _conflicts.length === ccount ? target.update({ tags }) : target;
-    }
-    var action = function(graph) {
-      var updates = { replacements: [], removeIds: [] };
-      var base = graph.base().entities[id2];
-      var local = localGraph.entity(id2);
-      var remote = remoteGraph.entity(id2);
-      var target = osmEntity(local, { version: remote.version });
-      if (!remote.visible) {
-        if (_option === "force_remote") {
-          return actionDeleteMultiple([id2])(graph);
-        } else if (_option === "force_local") {
-          if (target.type === "way") {
-            target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
-            graph = updateChildren(updates, graph);
-          }
-          return graph.replace(target);
-        } else {
-          _conflicts.push(_t.html("merge_remote_changes.conflict.deleted", { user: { html: user(remote.user) } }));
-          return graph;
+      }, this);
+      Object.keys(this._parentRels).forEach(function(child) {
+        if (base.parentRels[child]) {
+          base.parentRels[child].forEach(function(id2) {
+            if (!this.entities.hasOwnProperty(id2)) {
+              this._parentRels[child].add(id2);
+            }
+          }, this);
+        }
+      }, this);
+      this.transients = {};
+    },
+    // Updates calculated properties (parentWays, parentRels) for the specified change
+    _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
+      parentWays = parentWays || this._parentWays;
+      parentRels = parentRels || this._parentRels;
+      var type2 = entity && entity.type || oldentity && oldentity.type;
+      var removed, added, i2;
+      if (type2 === "way") {
+        if (oldentity && entity) {
+          removed = utilArrayDifference(oldentity.nodes, entity.nodes);
+          added = utilArrayDifference(entity.nodes, oldentity.nodes);
+        } else if (oldentity) {
+          removed = oldentity.nodes;
+          added = [];
+        } else if (entity) {
+          removed = [];
+          added = entity.nodes;
+        }
+        for (i2 = 0; i2 < removed.length; i2++) {
+          parentWays[removed[i2]] = new Set(parentWays[removed[i2]]);
+          parentWays[removed[i2]].delete(oldentity.id);
+        }
+        for (i2 = 0; i2 < added.length; i2++) {
+          parentWays[added[i2]] = new Set(parentWays[added[i2]]);
+          parentWays[added[i2]].add(entity.id);
+        }
+      } else if (type2 === "relation") {
+        var oldentityMemberIDs = oldentity ? oldentity.members.map(function(m) {
+          return m.id;
+        }) : [];
+        var entityMemberIDs = entity ? entity.members.map(function(m) {
+          return m.id;
+        }) : [];
+        if (oldentity && entity) {
+          removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
+          added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
+        } else if (oldentity) {
+          removed = oldentityMemberIDs;
+          added = [];
+        } else if (entity) {
+          removed = [];
+          added = entityMemberIDs;
+        }
+        for (i2 = 0; i2 < removed.length; i2++) {
+          parentRels[removed[i2]] = new Set(parentRels[removed[i2]]);
+          parentRels[removed[i2]].delete(oldentity.id);
+        }
+        for (i2 = 0; i2 < added.length; i2++) {
+          parentRels[added[i2]] = new Set(parentRels[added[i2]]);
+          parentRels[added[i2]].add(entity.id);
         }
       }
-      if (target.type === "node") {
-        target = mergeLocation(remote, target);
-      } else if (target.type === "way") {
-        graph.rebase(remoteGraph.childNodes(remote), [graph], false);
-        target = mergeNodes(base, remote, target);
-        target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
-      } else if (target.type === "relation") {
-        target = mergeMembers(remote, target);
-      }
-      target = mergeTags(base, remote, target);
-      if (!_conflicts.length) {
-        graph = updateChildren(updates, graph).replace(target);
+    },
+    replace: function(entity) {
+      if (this.entities[entity.id] === entity)
+        return this;
+      return this.update(function() {
+        this._updateCalculated(this.entities[entity.id], entity);
+        this.entities[entity.id] = entity;
+      });
+    },
+    remove: function(entity) {
+      return this.update(function() {
+        this._updateCalculated(entity, void 0);
+        this.entities[entity.id] = void 0;
+      });
+    },
+    revert: function(id2) {
+      var baseEntity = this.base().entities[id2];
+      var headEntity = this.entities[id2];
+      if (headEntity === baseEntity)
+        return this;
+      return this.update(function() {
+        this._updateCalculated(headEntity, baseEntity);
+        delete this.entities[id2];
+      });
+    },
+    update: function() {
+      var graph = this.frozen ? coreGraph(this, true) : this;
+      for (var i2 = 0; i2 < arguments.length; i2++) {
+        arguments[i2].call(graph, graph);
       }
+      if (this.frozen)
+        graph.frozen = true;
       return graph;
-    };
-    action.withOption = function(opt) {
-      _option = opt;
-      return action;
-    };
-    action.conflicts = function() {
-      return _conflicts;
-    };
-    return action;
-  }
-
-  // modules/actions/move.js
-  function actionMove(moveIDs, tryDelta, projection2, cache) {
-    var _delta = tryDelta;
-    function setupCache(graph) {
-      function canMove(nodeID) {
-        if (moveIDs.indexOf(nodeID) !== -1)
-          return true;
-        var parents = graph.parentWays(graph.entity(nodeID));
-        if (parents.length < 3)
-          return true;
-        var parentsMoving = parents.every(function(way) {
-          return cache.moving[way.id];
-        });
-        if (!parentsMoving)
-          delete cache.moving[nodeID];
-        return parentsMoving;
+    },
+    // Obliterates any existing entities
+    load: function(entities) {
+      var base = this.base();
+      this.entities = Object.create(base.entities);
+      for (var i2 in entities) {
+        this.entities[i2] = entities[i2];
+        this._updateCalculated(base.entities[i2], this.entities[i2]);
       }
-      function cacheEntities(ids) {
-        for (var i2 = 0; i2 < ids.length; i2++) {
-          var id2 = ids[i2];
-          if (cache.moving[id2])
+      return this;
+    }
+  };
+
+  // modules/osm/intersection.js
+  function osmTurn(turn) {
+    if (!(this instanceof osmTurn)) {
+      return new osmTurn(turn);
+    }
+    Object.assign(this, turn);
+  }
+  function osmIntersection(graph, startVertexId, maxDistance) {
+    maxDistance = maxDistance || 30;
+    var vgraph = coreGraph();
+    var i2, j2, k;
+    function memberOfRestriction(entity) {
+      return graph.parentRelations(entity).some(function(r) {
+        return r.isRestriction();
+      });
+    }
+    function isRoad(way2) {
+      if (way2.isArea() || way2.isDegenerate())
+        return false;
+      var 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,
+        "service": true,
+        "road": true,
+        "track": true
+      };
+      return roads[way2.tags.highway];
+    }
+    var startNode = graph.entity(startVertexId);
+    var checkVertices = [startNode];
+    var checkWays;
+    var vertices = [];
+    var vertexIds = [];
+    var vertex;
+    var ways = [];
+    var wayIds = [];
+    var way;
+    var nodes = [];
+    var node;
+    var parents = [];
+    var parent;
+    var actions = [];
+    while (checkVertices.length) {
+      vertex = checkVertices.pop();
+      checkWays = graph.parentWays(vertex);
+      var hasWays = false;
+      for (i2 = 0; i2 < checkWays.length; i2++) {
+        way = checkWays[i2];
+        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;
-          cache.moving[id2] = true;
-          var entity = graph.hasEntity(id2);
-          if (!entity)
+          if (vertices.indexOf(node) !== -1)
             continue;
-          if (entity.type === "node") {
-            cache.nodes.push(id2);
-            cache.startLoc[id2] = entity.loc;
-          } else if (entity.type === "way") {
-            cache.ways.push(id2);
-            cacheEntities(entity.nodes);
-          } else {
-            cacheEntities(entity.members.map(function(member) {
-              return member.id;
-            }));
-          }
-        }
-      }
-      function cacheIntersections(ids) {
-        function isEndpoint(way2, id3) {
-          return !way2.isClosed() && !!way2.affix(id3);
-        }
-        for (var i2 = 0; i2 < ids.length; i2++) {
-          var id2 = ids[i2];
-          var childNodes = graph.childNodes(graph.entity(id2));
-          for (var j2 = 0; j2 < childNodes.length; j2++) {
-            var node = childNodes[j2];
-            var parents = graph.parentWays(node);
-            if (parents.length !== 2)
-              continue;
-            var moved = graph.entity(id2);
-            var unmoved = null;
-            for (var k = 0; k < parents.length; k++) {
-              var way = parents[k];
-              if (!cache.moving[way.id]) {
-                unmoved = way;
-                break;
-              }
-            }
-            if (!unmoved)
+          if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance)
+            continue;
+          var hasParents = false;
+          parents = graph.parentWays(node);
+          for (k = 0; k < parents.length; k++) {
+            parent = parents[k];
+            if (parent === way)
               continue;
-            if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2)
+            if (ways.indexOf(parent) !== -1)
               continue;
-            if (moved.isArea() || unmoved.isArea())
+            if (!isRoad(parent))
               continue;
-            cache.intersections.push({
-              nodeId: node.id,
-              movedId: moved.id,
-              unmovedId: unmoved.id,
-              movedIsEP: isEndpoint(moved, node.id),
-              unmovedIsEP: isEndpoint(unmoved, node.id)
-            });
+            hasParents = true;
+            break;
+          }
+          if (hasParents) {
+            checkVertices.push(node);
           }
         }
       }
-      if (!cache) {
-        cache = {};
-      }
-      if (!cache.ok) {
-        cache.moving = {};
-        cache.intersections = [];
-        cache.replacedVertex = {};
-        cache.startLoc = {};
-        cache.nodes = [];
-        cache.ways = [];
-        cacheEntities(moveIDs);
-        cacheIntersections(cache.ways);
-        cache.nodes = cache.nodes.filter(canMove);
-        cache.ok = true;
-      }
-    }
-    function replaceMovedVertex(nodeId, wayId, graph, delta) {
-      var way = graph.entity(wayId);
-      var moved = graph.entity(nodeId);
-      var movedIndex = way.nodes.indexOf(nodeId);
-      var len, prevIndex, nextIndex;
-      if (way.isClosed()) {
-        len = way.nodes.length - 1;
-        prevIndex = (movedIndex + len - 1) % len;
-        nextIndex = (movedIndex + len + 1) % len;
-      } else {
-        len = way.nodes.length;
-        prevIndex = movedIndex - 1;
-        nextIndex = movedIndex + 1;
-      }
-      var prev = graph.hasEntity(way.nodes[prevIndex]);
-      var next = graph.hasEntity(way.nodes[nextIndex]);
-      if (!prev || !next)
-        return graph;
-      var key = wayId + "_" + nodeId;
-      var orig = cache.replacedVertex[key];
-      if (!orig) {
-        orig = osmNode();
-        cache.replacedVertex[key] = orig;
-        cache.startLoc[orig.id] = cache.startLoc[nodeId];
-      }
-      var start2, end;
-      if (delta) {
-        start2 = projection2(cache.startLoc[nodeId]);
-        end = projection2.invert(geoVecAdd(start2, delta));
-      } else {
-        end = cache.startLoc[nodeId];
+      if (hasWays) {
+        vertices.push(vertex);
       }
-      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;
-      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;
-      way = way.addNode(orig.id, insertAt);
-      return graph.replace(orig).replace(way);
     }
-    function removeDuplicateVertices(wayId, graph) {
-      var way = graph.entity(wayId);
-      var epsilon3 = 1e-6;
-      var prev, curr;
-      function isInteresting(node, graph2) {
-        return graph2.parentWays(node).length > 1 || graph2.parentRelations(node).length || node.hasInterestingTags();
-      }
-      for (var i2 = 0; i2 < way.nodes.length; i2++) {
-        curr = graph.entity(way.nodes[i2]);
-        if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon3)) {
-          if (!isInteresting(prev, graph)) {
-            way = way.removeNode(prev.id);
-            graph = graph.replace(way).remove(prev);
-          } else if (!isInteresting(curr, graph)) {
-            way = way.removeNode(curr.id);
-            graph = graph.replace(way).remove(curr);
+    vertices = utilArrayUniq(vertices);
+    ways = utilArrayUniq(ways);
+    ways.forEach(function(way2) {
+      graph.childNodes(way2).forEach(function(node2) {
+        vgraph = vgraph.replace(node2);
+      });
+      vgraph = vgraph.replace(way2);
+      graph.parentRelations(way2).forEach(function(relation) {
+        if (relation.isRestriction()) {
+          if (relation.isValidRestriction(graph)) {
+            vgraph = vgraph.replace(relation);
+          } else if (relation.isComplete(graph)) {
+            actions.push(actionDeleteRelation(relation.id));
           }
         }
-        prev = curr;
-      }
-      return graph;
-    }
-    function unZorroIntersection(intersection, graph) {
-      var vertex = graph.entity(intersection.nodeId);
-      var way1 = graph.entity(intersection.movedId);
-      var way2 = graph.entity(intersection.unmovedId);
-      var isEP1 = intersection.movedIsEP;
-      var isEP2 = intersection.unmovedIsEP;
-      if (isEP1 && isEP2)
-        return graph;
-      var nodes1 = graph.childNodes(way1).filter(function(n2) {
-        return n2 !== vertex;
-      });
-      var nodes2 = graph.childNodes(way2).filter(function(n2) {
-        return n2 !== vertex;
       });
-      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;
-      if (!isEP1 && !isEP2) {
-        var epsilon3 = 1e-6, maxIter = 10;
-        for (var i2 = 0; i2 < maxIter; i2++) {
-          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;
-        }
-      } else if (!isEP1) {
-        loc = edge1.loc;
-      } else {
-        loc = edge2.loc;
-      }
-      graph = graph.replace(vertex.move(loc));
-      if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
-        way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
-        graph = graph.replace(way1);
-      }
-      if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
-        way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
-        graph = graph.replace(way2);
-      }
-      return graph;
-    }
-    function cleanupIntersections(graph) {
-      for (var i2 = 0; i2 < cache.intersections.length; i2++) {
-        var obj = cache.intersections[i2];
-        graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
-        graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
-        graph = unZorroIntersection(obj, graph);
-        graph = removeDuplicateVertices(obj.movedId, graph);
-        graph = removeDuplicateVertices(obj.unmovedId, graph);
-      }
-      return graph;
-    }
-    function limitDelta(graph) {
-      function moveNode(loc) {
-        return geoVecAdd(projection2(loc), _delta);
+    });
+    ways.forEach(function(w) {
+      var way2 = vgraph.entity(w.id);
+      if (way2.tags.oneway === "-1") {
+        var action = actionReverse(way2.id, { reverseOneway: true });
+        actions.push(action);
+        vgraph = action(vgraph);
       }
-      for (var i2 = 0; i2 < cache.intersections.length; i2++) {
-        var obj = cache.intersections[i2];
-        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 movedNodes = graph.childNodes(graph.entity(obj.movedId));
-        var movedPath = movedNodes.map(function(n2) {
-          return moveNode(n2.loc);
-        });
-        var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
-        var unmovedPath = unmovedNodes.map(function(n2) {
-          return projection2(n2.loc);
+    });
+    var origCount = osmEntity.id.next.way;
+    vertices.forEach(function(v) {
+      var splitAll = actionSplit([v.id]).keepHistoryOn("first");
+      if (!splitAll.disabled(vgraph)) {
+        splitAll.ways(vgraph).forEach(function(way2) {
+          var splitOne = actionSplit([v.id]).limitWays([way2.id]).keepHistoryOn("first");
+          actions.push(splitOne);
+          vgraph = splitOne(vgraph);
         });
-        var hits = geoPathIntersections(movedPath, unmovedPath);
-        for (var j2 = 0; i2 < hits.length; i2++) {
-          if (geoVecEqual(hits[j2], end))
-            continue;
-          var edge = geoChooseEdge(unmovedNodes, end, projection2);
-          _delta = geoVecSubtract(projection2(edge.loc), start2);
-        }
       }
+    });
+    osmEntity.id.next.way = origCount;
+    vertexIds = vertices.map(function(v) {
+      return v.id;
+    });
+    vertices = [];
+    ways = [];
+    vertexIds.forEach(function(id2) {
+      var vertex2 = vgraph.entity(id2);
+      var parents2 = vgraph.parentWays(vertex2);
+      vertices.push(vertex2);
+      ways = ways.concat(parents2);
+    });
+    vertices = utilArrayUniq(vertices);
+    ways = utilArrayUniq(ways);
+    vertexIds = vertices.map(function(v) {
+      return v.id;
+    });
+    wayIds = ways.map(function(w) {
+      return w.id;
+    });
+    function withMetadata(way2, vertexIds2) {
+      var __oneWay = way2.isOneWay();
+      var __first = vertexIds2.indexOf(way2.first()) !== -1;
+      var __last = vertexIds2.indexOf(way2.last()) !== -1;
+      var __via = __first && __last;
+      var __from = __first && !__oneWay || __last;
+      var __to = __first || __last && !__oneWay;
+      return way2.update({
+        __first,
+        __last,
+        __from,
+        __via,
+        __to,
+        __oneWay
+      });
     }
-    var action = function(graph) {
-      if (_delta[0] === 0 && _delta[1] === 0)
-        return graph;
-      setupCache(graph);
-      if (cache.intersections.length) {
-        limitDelta(graph);
-      }
-      for (var i2 = 0; i2 < cache.nodes.length; i2++) {
-        var node = graph.entity(cache.nodes[i2]);
-        var start2 = projection2(node.loc);
-        var end = geoVecAdd(start2, _delta);
-        graph = graph.replace(node.move(projection2.invert(end)));
-      }
-      if (cache.intersections.length) {
-        graph = cleanupIntersections(graph);
-      }
-      return graph;
-    };
-    action.delta = function() {
-      return _delta;
-    };
-    return action;
-  }
-
-  // modules/actions/move_member.js
-  function actionMoveMember(relationId, fromIndex, toIndex) {
-    return function(graph) {
-      return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
-    };
-  }
-
-  // modules/actions/move_node.js
-  function actionMoveNode(nodeID, toLoc) {
-    var action = function(graph, t) {
-      if (t === null || !isFinite(t))
-        t = 1;
-      t = Math.min(Math.max(+t, 0), 1);
-      var node = graph.entity(nodeID);
-      return graph.replace(
-        node.move(geoVecInterp(node.loc, toLoc, t))
-      );
-    };
-    action.transitionable = true;
-    return action;
-  }
-
-  // modules/actions/noop.js
-  function actionNoop() {
-    return function(graph) {
-      return graph;
-    };
-  }
-
-  // modules/actions/orthogonalize.js
-  function actionOrthogonalize(wayID, projection2, vertexID, degThresh, ep) {
-    var epsilon3 = ep || 1e-4;
-    var threshold = degThresh || 13;
-    var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
-    var upperThreshold = Math.cos(threshold * Math.PI / 180);
-    var action = function(graph, t) {
-      if (t === null || !isFinite(t))
-        t = 1;
-      t = Math.min(Math.max(+t, 0), 1);
-      var way = graph.entity(wayID);
-      way = way.removeNode("");
-      if (way.tags.nonsquare) {
-        var tags = Object.assign({}, way.tags);
-        delete tags.nonsquare;
-        way = way.update({ tags });
-      }
-      graph = graph.replace(way);
-      var isClosed = way.isClosed();
-      var nodes = graph.childNodes(way).slice();
-      if (isClosed)
-        nodes.pop();
-      if (vertexID !== void 0) {
-        nodes = nodeSubset(nodes, vertexID, isClosed);
-        if (nodes.length !== 3)
-          return graph;
-      }
-      var nodeCount = {};
-      var points = [];
-      var corner = { i: 0, dotp: 1 };
-      var node, point, loc, score, motions, i2, j2;
-      for (i2 = 0; i2 < nodes.length; i2++) {
-        node = nodes[i2];
-        nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
-        points.push({ id: node.id, coord: projection2(node.loc) });
-      }
-      if (points.length === 3) {
-        for (i2 = 0; i2 < 1e3; i2++) {
-          motions = points.map(calcMotion);
-          points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
-          score = corner.dotp;
-          if (score < epsilon3) {
-            break;
+    ways = [];
+    wayIds.forEach(function(id2) {
+      var way2 = withMetadata(vgraph.entity(id2), vertexIds);
+      vgraph = vgraph.replace(way2);
+      ways.push(way2);
+    });
+    var keepGoing;
+    var removeWayIds = [];
+    var removeVertexIds = [];
+    do {
+      keepGoing = false;
+      checkVertices = vertexIds.slice();
+      for (i2 = 0; i2 < checkVertices.length; i2++) {
+        var vertexId = checkVertices[i2];
+        vertex = vgraph.hasEntity(vertexId);
+        if (!vertex) {
+          if (vertexIds.indexOf(vertexId) !== -1) {
+            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
           }
+          removeVertexIds.push(vertexId);
+          continue;
         }
-        node = graph.entity(nodes[corner.i].id);
-        loc = projection2.invert(points[corner.i].coord);
-        graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
-      } else {
-        var straights = [];
-        var simplified = [];
-        for (i2 = 0; i2 < points.length; i2++) {
-          point = points[i2];
-          var dotp = 0;
-          if (isClosed || i2 > 0 && i2 < points.length - 1) {
-            var a = points[(i2 - 1 + points.length) % points.length];
-            var b = points[(i2 + 1) % points.length];
-            dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point.coord));
-          }
-          if (dotp > upperThreshold) {
-            straights.push(point);
-          } else {
-            simplified.push(point);
+        parents = vgraph.parentWays(vertex);
+        if (parents.length < 3) {
+          if (vertexIds.indexOf(vertexId) !== -1) {
+            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
           }
         }
-        var bestPoints = clonePoints(simplified);
-        var originalPoints = clonePoints(simplified);
-        score = Infinity;
-        for (i2 = 0; i2 < 1e3; i2++) {
-          motions = simplified.map(calcMotion);
-          for (j2 = 0; j2 < motions.length; j2++) {
-            simplified[j2].coord = geoVecAdd(simplified[j2].coord, motions[j2]);
-          }
-          var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon3, threshold);
-          if (newScore < score) {
-            bestPoints = clonePoints(simplified);
-            score = newScore;
+        if (parents.length === 2) {
+          var a = parents[0];
+          var b = parents[1];
+          var aIsLeaf = a && !a.__via;
+          var bIsLeaf = b && !b.__via;
+          var leaf, survivor;
+          if (aIsLeaf && !bIsLeaf) {
+            leaf = a;
+            survivor = b;
+          } else if (!aIsLeaf && bIsLeaf) {
+            leaf = b;
+            survivor = a;
           }
-          if (score < epsilon3) {
-            break;
+          if (leaf && survivor) {
+            survivor = withMetadata(survivor, vertexIds);
+            vgraph = vgraph.replace(survivor).remove(leaf);
+            removeWayIds.push(leaf.id);
+            keepGoing = true;
           }
         }
-        var bestCoords = bestPoints.map(function(p) {
-          return p.coord;
-        });
-        if (isClosed)
-          bestCoords.push(bestCoords[0]);
-        for (i2 = 0; i2 < bestPoints.length; i2++) {
-          point = bestPoints[i2];
-          if (!geoVecEqual(originalPoints[i2].coord, point.coord)) {
-            node = graph.entity(point.id);
-            loc = projection2.invert(point.coord);
-            graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
+        parents = vgraph.parentWays(vertex);
+        if (parents.length < 2) {
+          if (vertexIds.indexOf(vertexId) !== -1) {
+            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
           }
+          removeVertexIds.push(vertexId);
+          keepGoing = true;
         }
-        for (i2 = 0; i2 < straights.length; i2++) {
-          point = straights[i2];
-          if (nodeCount[point.id] > 1)
+        if (parents.length < 1) {
+          vgraph = vgraph.remove(vertex);
+        }
+      }
+    } while (keepGoing);
+    vertices = vertices.filter(function(vertex2) {
+      return removeVertexIds.indexOf(vertex2.id) === -1;
+    }).map(function(vertex2) {
+      return vgraph.entity(vertex2.id);
+    });
+    ways = ways.filter(function(way2) {
+      return removeWayIds.indexOf(way2.id) === -1;
+    }).map(function(way2) {
+      return vgraph.entity(way2.id);
+    });
+    var intersection = {
+      graph: vgraph,
+      actions,
+      vertices,
+      ways
+    };
+    intersection.turns = function(fromWayId, maxViaWay) {
+      if (!fromWayId)
+        return [];
+      if (!maxViaWay)
+        maxViaWay = 0;
+      var vgraph2 = intersection.graph;
+      var keyVertexIds = intersection.vertices.map(function(v) {
+        return v.id;
+      });
+      var start2 = vgraph2.entity(fromWayId);
+      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;
+        currPath.push(entity.id);
+        currRestrictions = (currRestrictions || []).slice();
+        if (entity.type === "node") {
+          stepNode(entity, currPath, currRestrictions);
+        } else {
+          stepWay(entity, currPath, currRestrictions, matchedRestriction);
+        }
+      }
+      function stepNode(entity, currPath, currRestrictions) {
+        var i3, j3;
+        var parents2 = vgraph2.parentWays(entity);
+        var nextWays = [];
+        for (i3 = 0; i3 < parents2.length; i3++) {
+          var way2 = parents2[i3];
+          if (way2.__oneWay && way2.nodes[0] !== entity.id)
             continue;
-          node = graph.entity(point.id);
-          if (t === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
-            graph = actionDeleteNode(node.id)(graph);
-          } else {
-            var choice = geoVecProject(point.coord, bestCoords);
-            if (choice) {
-              loc = projection2.invert(choice.target);
-              graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
+          if (currPath.indexOf(way2.id) !== -1 && currPath.length >= 3)
+            continue;
+          var restrict = null;
+          for (j3 = 0; j3 < currRestrictions.length; j3++) {
+            var restriction = currRestrictions[j3];
+            var f2 = restriction.memberByRole("from");
+            var v = restriction.membersByRole("via");
+            var t = restriction.memberByRole("to");
+            var isNo = /^no_/.test(restriction.tags.restriction);
+            var isOnly = /^only_/.test(restriction.tags.restriction);
+            if (!(isNo || isOnly)) {
+              continue;
+            }
+            var matchesFrom = f2.id === fromWayId;
+            var matchesViaTo = false;
+            var isAlongOnlyPath = false;
+            if (t.id === way2.id) {
+              if (v.length === 1 && v[0].type === "node") {
+                matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
+              } else {
+                var pathVias = [];
+                for (k = 2; k < currPath.length; k += 2) {
+                  pathVias.push(currPath[k]);
+                }
+                var restrictionVias = [];
+                for (k = 0; k < v.length; k++) {
+                  if (v[k].type === "way") {
+                    restrictionVias.push(v[k].id);
+                  }
+                }
+                var diff = utilArrayDifference(pathVias, restrictionVias);
+                matchesViaTo = !diff.length;
+              }
+            } else if (isOnly) {
+              for (k = 0; k < v.length; k++) {
+                if (v[k].type === "way" && v[k].id === way2.id) {
+                  isAlongOnlyPath = true;
+                  break;
+                }
+              }
+            }
+            if (matchesViaTo) {
+              if (isOnly) {
+                restrict = { id: restriction.id, direct: matchesFrom, from: f2.id, only: true, end: true };
+              } else {
+                restrict = { id: restriction.id, direct: matchesFrom, from: f2.id, no: true, end: true };
+              }
+            } else {
+              if (isAlongOnlyPath) {
+                restrict = { id: restriction.id, direct: false, from: f2.id, only: true, end: false };
+              } else if (isOnly) {
+                restrict = { id: restriction.id, direct: false, from: f2.id, no: true, end: true };
+              }
             }
+            if (restrict && restrict.direct)
+              break;
           }
+          nextWays.push({ way: way2, restrict });
         }
-      }
-      return graph;
-      function clonePoints(array2) {
-        return array2.map(function(p) {
-          return { id: p.id, coord: [p.coord[0], p.coord[1]] };
+        nextWays.forEach(function(nextWay) {
+          step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
         });
       }
-      function calcMotion(point2, i3, array2) {
-        if (!isClosed && (i3 === 0 || i3 === array2.length - 1))
-          return [0, 0];
-        if (nodeCount[array2[i3].id] > 1)
-          return [0, 0];
-        var a2 = array2[(i3 - 1 + array2.length) % array2.length].coord;
-        var origin = point2.coord;
-        var b2 = array2[(i3 + 1) % array2.length].coord;
-        var p = geoVecSubtract(a2, origin);
-        var q = geoVecSubtract(b2, origin);
-        var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
-        p = geoVecNormalize(p);
-        q = geoVecNormalize(q);
-        var dotp2 = p[0] * q[0] + p[1] * q[1];
-        var val = Math.abs(dotp2);
-        if (val < lowerThreshold) {
-          corner.i = i3;
-          corner.dotp = val;
-          var vec = geoVecNormalize(geoVecAdd(p, q));
-          return geoVecScale(vec, 0.1 * dotp2 * scale);
+      function stepWay(entity, currPath, currRestrictions, matchedRestriction) {
+        var i3;
+        if (currPath.length >= 3) {
+          var turnPath = currPath.slice();
+          if (matchedRestriction && matchedRestriction.direct === false) {
+            for (i3 = 0; i3 < turnPath.length; i3++) {
+              if (turnPath[i3] === matchedRestriction.from) {
+                turnPath = turnPath.slice(i3);
+                break;
+              }
+            }
+          }
+          var turn = pathToTurn(turnPath);
+          if (turn) {
+            if (matchedRestriction) {
+              turn.restrictionID = matchedRestriction.id;
+              turn.no = matchedRestriction.no;
+              turn.only = matchedRestriction.only;
+              turn.direct = matchedRestriction.direct;
+            }
+            turns.push(osmTurn(turn));
+          }
+          if (currPath[0] === currPath[2])
+            return;
         }
-        return [0, 0];
-      }
-    };
-    function nodeSubset(nodes, vertexID2, isClosed) {
-      var first = isClosed ? 0 : 1;
-      var last = isClosed ? nodes.length : nodes.length - 1;
-      for (var i2 = first; i2 < last; i2++) {
-        if (nodes[i2].id === vertexID2) {
-          return [
-            nodes[(i2 - 1 + nodes.length) % nodes.length],
-            nodes[i2],
-            nodes[(i2 + 1) % nodes.length]
-          ];
+        if (matchedRestriction && matchedRestriction.end)
+          return;
+        var n1 = vgraph2.entity(entity.first());
+        var n2 = vgraph2.entity(entity.last());
+        var dist = geoSphericalDistance(n1.loc, n2.loc);
+        var nextNodes = [];
+        if (currPath.length > 1) {
+          if (dist > maxDistance)
+            return;
+          if (!entity.__via)
+            return;
         }
+        if (!entity.__oneWay && // bidirectional..
+        keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
+        currPath.indexOf(n1.id) === -1) {
+          nextNodes.push(n1);
+        }
+        if (keyVertexIds.indexOf(n2.id) !== -1 && // key vertex..
+        currPath.indexOf(n2.id) === -1) {
+          nextNodes.push(n2);
+        }
+        nextNodes.forEach(function(nextNode) {
+          var fromRestrictions = vgraph2.parentRelations(entity).filter(function(r) {
+            if (!r.isRestriction())
+              return false;
+            var f2 = r.memberByRole("from");
+            if (!f2 || f2.id !== entity.id)
+              return false;
+            var isOnly = /^only_/.test(r.tags.restriction);
+            if (!isOnly)
+              return true;
+            var isOnlyVia = false;
+            var v = r.membersByRole("via");
+            if (v.length === 1 && v[0].type === "node") {
+              isOnlyVia = v[0].id === nextNode.id;
+            } else {
+              for (var i4 = 0; i4 < v.length; i4++) {
+                if (v[i4].type !== "way")
+                  continue;
+                var viaWay = vgraph2.entity(v[i4].id);
+                if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
+                  isOnlyVia = true;
+                  break;
+                }
+              }
+            }
+            return isOnlyVia;
+          });
+          step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
+        });
       }
-      return [];
-    }
-    action.disabled = function(graph) {
-      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();
-      var allowStraightAngles = false;
-      if (vertexID !== void 0) {
-        allowStraightAngles = true;
-        nodes = nodeSubset(nodes, vertexID, isClosed);
-        if (nodes.length !== 3)
-          return "end_vertex";
-      }
-      var coords = nodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon3, threshold, allowStraightAngles);
-      if (score === null) {
-        return "not_squarish";
-      } else if (score === 0) {
-        return "square_enough";
-      } else {
-        return false;
+      function pathToTurn(path) {
+        if (path.length < 3)
+          return;
+        var fromWayId2, fromNodeId, fromVertexId;
+        var toWayId, toNodeId, toVertexId;
+        var viaWayIds, viaNodeId, isUturn;
+        fromWayId2 = path[0];
+        toWayId = path[path.length - 1];
+        if (path.length === 3 && fromWayId2 === toWayId) {
+          var way2 = vgraph2.entity(fromWayId2);
+          if (way2.__oneWay)
+            return null;
+          isUturn = true;
+          viaNodeId = fromVertexId = toVertexId = path[1];
+          fromNodeId = toNodeId = adjacentNode(fromWayId2, viaNodeId);
+        } else {
+          isUturn = false;
+          fromVertexId = path[1];
+          fromNodeId = adjacentNode(fromWayId2, fromVertexId);
+          toVertexId = path[path.length - 2];
+          toNodeId = adjacentNode(toWayId, toVertexId);
+          if (path.length === 3) {
+            viaNodeId = path[1];
+          } else {
+            viaWayIds = path.filter(function(entityId) {
+              return entityId[0] === "w";
+            });
+            viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1);
+          }
+        }
+        return {
+          key: path.join("_"),
+          path,
+          from: { node: fromNodeId, way: fromWayId2, vertex: fromVertexId },
+          via: { node: viaNodeId, ways: viaWayIds },
+          to: { node: toNodeId, way: toWayId, vertex: toVertexId },
+          u: isUturn
+        };
+        function adjacentNode(wayId, affixId) {
+          var nodes2 = vgraph2.entity(wayId).nodes;
+          return affixId === nodes2[0] ? nodes2[1] : nodes2[nodes2.length - 2];
+        }
       }
     };
-    action.transitionable = true;
-    return action;
+    return intersection;
+  }
+  function osmInferRestriction(graph, turn, projection2) {
+    var fromWay = graph.entity(turn.from.way);
+    var fromNode = graph.entity(turn.from.node);
+    var fromVertex = graph.entity(turn.from.vertex);
+    var toWay = graph.entity(turn.to.way);
+    var toNode = graph.entity(turn.to.node);
+    var toVertex = graph.entity(turn.to.vertex);
+    var fromOneWay = fromWay.tags.oneway === "yes";
+    var toOneWay = toWay.tags.oneway === "yes";
+    var angle2 = (geoAngle(fromVertex, fromNode, projection2) - geoAngle(toVertex, toNode, projection2)) * 180 / Math.PI;
+    while (angle2 < 0) {
+      angle2 += 360;
+    }
+    if (fromNode === toNode) {
+      return "no_u_turn";
+    }
+    if ((angle2 < 23 || angle2 > 336) && fromOneWay && toOneWay) {
+      return "no_u_turn";
+    }
+    if ((angle2 < 40 || angle2 > 319) && fromOneWay && toOneWay && turn.from.vertex !== turn.to.vertex) {
+      return "no_u_turn";
+    }
+    if (angle2 < 158) {
+      return "no_right_turn";
+    }
+    if (angle2 > 202) {
+      return "no_left_turn";
+    }
+    return "no_straight_on";
   }
 
-  // modules/actions/restrict_turn.js
-  function actionRestrictTurn(turn, restrictionType, restrictionID) {
-    return function(graph) {
-      var fromWay = graph.entity(turn.from.way);
-      var toWay = graph.entity(turn.to.way);
-      var viaNode = turn.via.node && graph.entity(turn.via.node);
-      var viaWays = turn.via.ways && turn.via.ways.map(function(id2) {
+  // modules/actions/merge_polygon.js
+  function actionMergePolygon(ids, newRelationId) {
+    function groupEntities(graph) {
+      var entities = ids.map(function(id2) {
         return graph.entity(id2);
       });
+      var geometryGroups = utilArrayGroupBy(entities, function(entity) {
+        if (entity.type === "way" && entity.isClosed()) {
+          return "closedWay";
+        } else if (entity.type === "relation" && entity.isMultipolygon()) {
+          return "multipolygon";
+        } else {
+          return "other";
+        }
+      });
+      return Object.assign(
+        { closedWay: [], multipolygon: [], other: [] },
+        geometryGroups
+      );
+    }
+    var action = function(graph) {
+      var entities = groupEntities(graph);
+      var polygons = entities.multipolygon.reduce(function(polygons2, m) {
+        return polygons2.concat(osmJoinWays(m.members, graph));
+      }, []).concat(entities.closedWay.map(function(d) {
+        var member = [{ id: d.id }];
+        member.nodes = graph.childNodes(d);
+        return member;
+      }));
+      var contained = polygons.map(function(w, i2) {
+        return polygons.map(function(d, n2) {
+          if (i2 === n2)
+            return null;
+          return geoPolygonContainsPolygon(
+            d.nodes.map(function(n3) {
+              return n3.loc;
+            }),
+            w.nodes.map(function(n3) {
+              return n3.loc;
+            })
+          );
+        });
+      });
       var members = [];
-      members.push({ id: fromWay.id, type: "way", role: "from" });
-      if (viaNode) {
-        members.push({ id: viaNode.id, type: "node", role: "via" });
-      } else if (viaWays) {
-        viaWays.forEach(function(viaWay) {
-          members.push({ id: viaWay.id, type: "way", role: "via" });
+      var outer = true;
+      while (polygons.length) {
+        extractUncontained(polygons);
+        polygons = polygons.filter(isContained);
+        contained = contained.filter(isContained).map(filterContained);
+      }
+      function isContained(d, i2) {
+        return contained[i2].some(function(val) {
+          return val;
         });
       }
-      members.push({ id: toWay.id, type: "way", role: "to" });
-      return graph.replace(osmRelation({
-        id: restrictionID,
-        tags: {
-          type: "restriction",
-          restriction: restrictionType
-        },
-        members
-      }));
-    };
-  }
-
-  // modules/actions/revert.js
-  function actionRevert(id2) {
-    var action = function(graph) {
-      var entity = graph.hasEntity(id2), base = graph.base().entities[id2];
-      if (entity && !base) {
-        if (entity.type === "node") {
-          graph.parentWays(entity).forEach(function(parent) {
-            parent = parent.removeNode(id2);
-            graph = graph.replace(parent);
-            if (parent.isDegenerate()) {
-              graph = actionDeleteWay(parent.id)(graph);
-            }
-          });
-        }
-        graph.parentRelations(entity).forEach(function(parent) {
-          parent = parent.removeMembersWithID(id2);
-          graph = graph.replace(parent);
-          if (parent.isDegenerate()) {
-            graph = actionDeleteRelation(parent.id)(graph);
+      function filterContained(d) {
+        return d.filter(isContained);
+      }
+      function extractUncontained(polygons2) {
+        polygons2.forEach(function(d, i2) {
+          if (!isContained(d, i2)) {
+            d.forEach(function(member) {
+              members.push({
+                type: "way",
+                id: member.id,
+                role: outer ? "outer" : "inner"
+              });
+            });
           }
         });
+        outer = !outer;
       }
-      return graph.revert(id2);
-    };
-    return action;
-  }
-
-  // modules/actions/rotate.js
-  function actionRotate(rotateIds, pivot, angle2, projection2) {
-    var action = function(graph) {
-      return graph.update(function(graph2) {
-        utilGetAllNodes(rotateIds, graph2).forEach(function(node) {
-          var point = geoRotate([projection2(node.loc)], angle2, pivot)[0];
-          graph2 = graph2.replace(node.move(projection2.invert(point)));
-        });
-      });
-    };
-    return action;
-  }
-
-  // modules/actions/scale.js
-  function actionScale(ids, pivotLoc, scaleFactor, projection2) {
-    return function(graph) {
-      return graph.update(function(graph2) {
-        let point, radial;
-        utilGetAllNodes(ids, graph2).forEach(function(node) {
-          point = projection2(node.loc);
-          radial = [
-            point[0] - pivotLoc[0],
-            point[1] - pivotLoc[1]
-          ];
-          point = [
-            pivotLoc[0] + scaleFactor * radial[0],
-            pivotLoc[1] + scaleFactor * radial[1]
-          ];
-          graph2 = graph2.replace(node.move(projection2.invert(point)));
-        });
-      });
-    };
-  }
-
-  // modules/actions/straighten_nodes.js
-  function actionStraightenNodes(nodeIDs, projection2) {
-    function positionAlongWay(a, o, b) {
-      return geoVecDot(a, b, o) / geoVecDot(b, b, o);
-    }
-    function getEndpoints(points) {
-      var ssr = geoGetSmallestSurroundingRectangle(points);
-      var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
-      var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
-      var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
-      var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
-      var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
-      if (isLong) {
-        return [p1, q1];
-      }
-      return [p2, q2];
-    }
-    var action = function(graph, t) {
-      if (t === null || !isFinite(t))
-        t = 1;
-      t = Math.min(Math.max(+t, 0), 1);
-      var nodes = nodeIDs.map(function(id2) {
-        return graph.entity(id2);
-      });
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var endpoints = getEndpoints(points);
-      var startPoint = endpoints[0];
-      var endPoint = endpoints[1];
-      for (var i2 = 0; i2 < points.length; i2++) {
-        var node = nodes[i2];
-        var point = points[i2];
-        var u = positionAlongWay(point, startPoint, endPoint);
-        var point2 = geoVecInterp(startPoint, endPoint, u);
-        var loc2 = projection2.invert(point2);
-        graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
+      var relation;
+      if (entities.multipolygon.length > 0) {
+        var oldestID = utilOldestID(entities.multipolygon.map((entity) => entity.id));
+        relation = entities.multipolygon.find((entity) => entity.id === oldestID);
+      } else {
+        relation = osmRelation({ id: newRelationId, tags: { type: "multipolygon" } });
       }
-      return graph;
-    };
-    action.disabled = function(graph) {
-      var nodes = nodeIDs.map(function(id2) {
-        return graph.entity(id2);
-      });
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var endpoints = getEndpoints(points);
-      var startPoint = endpoints[0];
-      var endPoint = endpoints[1];
-      var maxDistance = 0;
-      for (var i2 = 0; i2 < points.length; i2++) {
-        var point = points[i2];
-        var u = positionAlongWay(point, startPoint, endPoint);
-        var p = geoVecInterp(startPoint, endPoint, u);
-        var dist = geoVecLength(p, point);
-        if (!isNaN(dist) && dist > maxDistance) {
-          maxDistance = dist;
+      entities.multipolygon.forEach(function(m) {
+        if (m.id !== relation.id) {
+          relation = relation.mergeTags(m.tags);
+          graph = graph.remove(m);
         }
-      }
-      if (maxDistance < 1e-4) {
-        return "straight_enough";
-      }
-    };
-    action.transitionable = true;
-    return action;
-  }
-
-  // modules/actions/straighten_way.js
-  function actionStraightenWay(selectedIDs, projection2) {
-    function positionAlongWay(a, o, b) {
-      return geoVecDot(a, b, o) / geoVecDot(b, b, o);
-    }
-    function allNodes(graph) {
-      var nodes = [];
-      var startNodes = [];
-      var endNodes = [];
-      var remainingWays = [];
-      var selectedWays = selectedIDs.filter(function(w) {
-        return graph.entity(w).type === "way";
-      });
-      var selectedNodes = selectedIDs.filter(function(n2) {
-        return graph.entity(n2).type === "node";
-      });
-      for (var i2 = 0; i2 < selectedWays.length; i2++) {
-        var way = graph.entity(selectedWays[i2]);
-        nodes = way.nodes.slice(0);
-        remainingWays.push(nodes);
-        startNodes.push(nodes[0]);
-        endNodes.push(nodes[nodes.length - 1]);
-      }
-      startNodes = startNodes.filter(function(n2) {
-        return startNodes.indexOf(n2) === startNodes.lastIndexOf(n2);
       });
-      endNodes = endNodes.filter(function(n2) {
-        return endNodes.indexOf(n2) === endNodes.lastIndexOf(n2);
-      });
-      var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
-      var nextWay = [];
-      nodes = [];
-      var getNextWay = function(currNode2, remainingWays2) {
-        return remainingWays2.filter(function(way2) {
-          return way2[0] === currNode2 || way2[way2.length - 1] === currNode2;
-        })[0];
-      };
-      while (remainingWays.length) {
-        nextWay = getNextWay(currNode, remainingWays);
-        remainingWays = utilArrayDifference(remainingWays, [nextWay]);
-        if (nextWay[0] !== currNode) {
-          nextWay.reverse();
+      entities.closedWay.forEach(function(way) {
+        function isThisOuter(m) {
+          return m.id === way.id && m.role !== "inner";
         }
-        nodes = nodes.concat(nextWay);
-        currNode = nodes[nodes.length - 1];
-      }
-      if (selectedNodes.length === 2) {
-        var startNodeIdx = nodes.indexOf(selectedNodes[0]);
-        var endNodeIdx = nodes.indexOf(selectedNodes[1]);
-        var sortedStartEnd = [startNodeIdx, endNodeIdx];
-        sortedStartEnd.sort(function(a, b) {
-          return a - b;
-        });
-        nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
-      }
-      return nodes.map(function(n2) {
-        return graph.entity(n2);
-      });
-    }
-    function shouldKeepNode(node, graph) {
-      return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
-    }
-    var action = function(graph, t) {
-      if (t === null || !isFinite(t))
-        t = 1;
-      t = Math.min(Math.max(+t, 0), 1);
-      var nodes = allNodes(graph);
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var startPoint = points[0];
-      var endPoint = points[points.length - 1];
-      var toDelete = [];
-      var i2;
-      for (i2 = 1; i2 < points.length - 1; i2++) {
-        var node = nodes[i2];
-        var point = points[i2];
-        if (t < 1 || shouldKeepNode(node, graph)) {
-          var u = positionAlongWay(point, startPoint, endPoint);
-          var p = geoVecInterp(startPoint, endPoint, u);
-          var loc2 = projection2.invert(p);
-          graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
-        } else {
-          if (toDelete.indexOf(node) === -1) {
-            toDelete.push(node);
-          }
+        if (members.some(isThisOuter)) {
+          relation = relation.mergeTags(way.tags);
+          graph = graph.replace(way.update({ tags: {} }));
         }
-      }
-      for (i2 = 0; i2 < toDelete.length; i2++) {
-        graph = actionDeleteNode(toDelete[i2].id)(graph);
-      }
-      return graph;
+      });
+      return graph.replace(relation.update({
+        members,
+        tags: utilObjectOmit(relation.tags, ["area"])
+      }));
     };
     action.disabled = function(graph) {
-      var nodes = allNodes(graph);
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var startPoint = points[0];
-      var endPoint = points[points.length - 1];
-      var threshold = 0.2 * geoVecLength(startPoint, endPoint);
-      var i2;
-      if (threshold === 0) {
-        return "too_bendy";
+      var entities = groupEntities(graph);
+      if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
+        return "not_eligible";
       }
-      var maxDistance = 0;
-      for (i2 = 1; i2 < points.length - 1; i2++) {
-        var point = points[i2];
-        var u = positionAlongWay(point, startPoint, endPoint);
-        var p = geoVecInterp(startPoint, endPoint, u);
-        var dist = geoVecLength(p, point);
-        if (isNaN(dist) || dist > threshold) {
-          return "too_bendy";
-        } else if (dist > maxDistance) {
-          maxDistance = dist;
-        }
+      if (!entities.multipolygon.every(function(r) {
+        return r.isComplete(graph);
+      })) {
+        return "incomplete_relation";
       }
-      var keepingAllNodes = nodes.every(function(node, i3) {
-        return i3 === 0 || i3 === nodes.length - 1 || shouldKeepNode(node, graph);
-      });
-      if (maxDistance < 1e-4 && keepingAllNodes) {
-        return "straight_enough";
+      if (!entities.multipolygon.length) {
+        var sharedMultipolygons = [];
+        entities.closedWay.forEach(function(way, i2) {
+          if (i2 === 0) {
+            sharedMultipolygons = graph.parentMultipolygons(way);
+          } else {
+            sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
+          }
+        });
+        sharedMultipolygons = sharedMultipolygons.filter(function(relation) {
+          return relation.members.length === entities.closedWay.length;
+        });
+        if (sharedMultipolygons.length) {
+          return "not_eligible";
+        }
+      } else if (entities.closedWay.some(function(way) {
+        return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
+      })) {
+        return "not_eligible";
       }
     };
-    action.transitionable = true;
     return action;
   }
 
-  // modules/actions/unrestrict_turn.js
-  function actionUnrestrictTurn(turn) {
-    return function(graph) {
-      return actionDeleteRelation(turn.restrictionID)(graph);
-    };
-  }
+  // modules/actions/merge_remote_changes.js
+  var import_fast_deep_equal = __toESM(require_fast_deep_equal());
 
-  // modules/actions/reflect.js
-  function actionReflect(reflectIds, projection2) {
-    var _useLongAxis = true;
-    var action = function(graph, t) {
-      if (t === null || !isFinite(t))
-        t = 1;
-      t = Math.min(Math.max(+t, 0), 1);
-      var nodes = utilGetAllNodes(reflectIds, graph);
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
-      });
-      var ssr = geoGetSmallestSurroundingRectangle(points);
-      var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
-      var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
-      var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
-      var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
-      var p, q;
-      var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
-      if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
-        p = p1;
-        q = q1;
+  // node_modules/node-diff3/index.mjs
+  function LCS(buffer1, buffer2) {
+    let equivalenceClasses = {};
+    for (let j2 = 0; j2 < buffer2.length; j2++) {
+      const item = buffer2[j2];
+      if (equivalenceClasses[item]) {
+        equivalenceClasses[item].push(j2);
       } else {
-        p = p2;
-        q = q2;
-      }
-      var dx = q[0] - p[0];
-      var dy = q[1] - p[1];
-      var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
-      var b = 2 * dx * dy / (dx * dx + dy * dy);
-      for (var i2 = 0; i2 < nodes.length; i2++) {
-        var node = nodes[i2];
-        var c = projection2(node.loc);
-        var c2 = [
-          a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
-          b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
-        ];
-        var loc2 = projection2.invert(c2);
-        node = node.move(geoVecInterp(node.loc, loc2, t));
-        graph = graph.replace(node);
+        equivalenceClasses[item] = [j2];
       }
-      return graph;
-    };
-    action.useLongAxis = function(val) {
-      if (!arguments.length)
-        return _useLongAxis;
-      _useLongAxis = val;
-      return action;
-    };
-    action.transitionable = true;
-    return action;
-  }
-
-  // modules/actions/upgrade_tags.js
-  function actionUpgradeTags(entityId, oldTags, replaceTags) {
-    return function(graph) {
-      var entity = graph.entity(entityId);
-      var tags = Object.assign({}, entity.tags);
-      var transferValue;
-      var semiIndex;
-      for (var oldTagKey in oldTags) {
-        if (!(oldTagKey in tags))
-          continue;
-        if (oldTags[oldTagKey] === "*") {
-          transferValue = tags[oldTagKey];
-          delete tags[oldTagKey];
-        } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
-          delete tags[oldTagKey];
-        } else {
-          var vals = tags[oldTagKey].split(";").filter(Boolean);
-          var oldIndex = vals.indexOf(oldTags[oldTagKey]);
-          if (vals.length === 1 || oldIndex === -1) {
-            delete tags[oldTagKey];
-          } else {
-            if (replaceTags && replaceTags[oldTagKey]) {
-              semiIndex = oldIndex;
-            }
-            vals.splice(oldIndex, 1);
-            tags[oldTagKey] = vals.join(";");
+    }
+    const NULLRESULT = { buffer1index: -1, buffer2index: -1, chain: null };
+    let candidates = [NULLRESULT];
+    for (let i2 = 0; i2 < buffer1.length; i2++) {
+      const item = buffer1[i2];
+      const buffer2indices = equivalenceClasses[item] || [];
+      let r = 0;
+      let c = candidates[0];
+      for (let jx = 0; jx < buffer2indices.length; jx++) {
+        const j2 = buffer2indices[jx];
+        let s;
+        for (s = r; s < candidates.length; s++) {
+          if (candidates[s].buffer2index < j2 && (s === candidates.length - 1 || candidates[s + 1].buffer2index > j2)) {
+            break;
           }
         }
-      }
-      if (replaceTags) {
-        for (var replaceKey in replaceTags) {
-          var replaceValue = replaceTags[replaceKey];
-          if (replaceValue === "*") {
-            if (tags[replaceKey] && tags[replaceKey] !== "no") {
-              continue;
-            } else {
-              tags[replaceKey] = "yes";
-            }
-          } else if (replaceValue === "$1") {
-            tags[replaceKey] = transferValue;
+        if (s < candidates.length) {
+          const newCandidate = { buffer1index: i2, buffer2index: j2, chain: candidates[s] };
+          if (r === candidates.length) {
+            candidates.push(c);
           } else {
-            if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== void 0) {
-              var existingVals = tags[replaceKey].split(";").filter(Boolean);
-              if (existingVals.indexOf(replaceValue) === -1) {
-                existingVals.splice(semiIndex, 0, replaceValue);
-                tags[replaceKey] = existingVals.join(";");
-              }
-            } else {
-              tags[replaceKey] = replaceValue;
-            }
+            candidates[r] = c;
+          }
+          r = s + 1;
+          c = newCandidate;
+          if (r === candidates.length) {
+            break;
           }
         }
       }
-      return graph.replace(entity.update({ tags }));
-    };
-  }
-
-  // modules/behavior/edit.js
-  function behaviorEdit(context) {
-    function behavior() {
-      context.map().minzoom(context.minEditableZoom());
+      candidates[r] = c;
     }
-    behavior.off = function() {
-      context.map().minzoom(0);
-    };
-    return behavior;
+    return candidates[candidates.length - 1];
   }
-
-  // modules/behavior/hover.js
-  function behaviorHover(context) {
-    var dispatch10 = dispatch_default("hover");
-    var _selection = select_default2(null);
-    var _newNodeId = null;
-    var _initialNodeID = null;
-    var _altDisables;
-    var _ignoreVertex;
-    var _targets = [];
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    function keydown(d3_event) {
-      if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
-        _selection.selectAll(".hover").classed("hover-suppressed", true).classed("hover", false);
-        _selection.classed("hover-disabled", true);
-        dispatch10.call("hover", this, null);
+  function diffIndices(buffer1, buffer2) {
+    const lcs = LCS(buffer1, buffer2);
+    let result = [];
+    let tail1 = buffer1.length;
+    let tail2 = buffer2.length;
+    for (let candidate = lcs; candidate !== null; candidate = candidate.chain) {
+      const mismatchLength1 = tail1 - candidate.buffer1index - 1;
+      const mismatchLength2 = tail2 - candidate.buffer2index - 1;
+      tail1 = candidate.buffer1index;
+      tail2 = candidate.buffer2index;
+      if (mismatchLength1 || mismatchLength2) {
+        result.push({
+          buffer1: [tail1 + 1, mismatchLength1],
+          buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
+          buffer2: [tail2 + 1, mismatchLength2],
+          buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
+        });
       }
     }
-    function keyup(d3_event) {
-      if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
-        _selection.selectAll(".hover-suppressed").classed("hover-suppressed", false).classed("hover", true);
-        _selection.classed("hover-disabled", false);
-        dispatch10.call("hover", this, _targets);
+    result.reverse();
+    return result;
+  }
+  function diff3MergeRegions(a, o, b) {
+    let hunks = [];
+    function addHunk(h, ab) {
+      hunks.push({
+        ab,
+        oStart: h.buffer1[0],
+        oLength: h.buffer1[1],
+        // length of o to remove
+        abStart: h.buffer2[0],
+        abLength: h.buffer2[1]
+        // length of a/b to insert
+        // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
+      });
+    }
+    diffIndices(o, a).forEach((item) => addHunk(item, "a"));
+    diffIndices(o, b).forEach((item) => addHunk(item, "b"));
+    hunks.sort((x, y) => x.oStart - y.oStart);
+    let results = [];
+    let currOffset = 0;
+    function advanceTo(endOffset) {
+      if (endOffset > currOffset) {
+        results.push({
+          stable: true,
+          buffer: "o",
+          bufferStart: currOffset,
+          bufferLength: endOffset - currOffset,
+          bufferContent: o.slice(currOffset, endOffset)
+        });
+        currOffset = endOffset;
       }
     }
-    function behavior(selection2) {
-      _selection = selection2;
-      _targets = [];
-      if (_initialNodeID) {
-        _newNodeId = _initialNodeID;
-        _initialNodeID = null;
-      } else {
-        _newNodeId = null;
+    while (hunks.length) {
+      let hunk = hunks.shift();
+      let regionStart = hunk.oStart;
+      let regionEnd = hunk.oStart + hunk.oLength;
+      let regionHunks = [hunk];
+      advanceTo(regionStart);
+      while (hunks.length) {
+        const nextHunk = hunks[0];
+        const nextHunkStart = nextHunk.oStart;
+        if (nextHunkStart > regionEnd)
+          break;
+        regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
+        regionHunks.push(hunks.shift());
       }
-      _selection.on(_pointerPrefix + "over.hover", pointerover).on(_pointerPrefix + "out.hover", pointerout).on(_pointerPrefix + "down.hover", pointerover);
-      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 (!(datum2 instanceof osmEntity) && datum2.properties && datum2.properties.entity instanceof osmEntity) {
-          return datum2.properties.entity;
+      if (regionHunks.length === 1) {
+        if (hunk.abLength > 0) {
+          const buffer = hunk.ab === "a" ? a : b;
+          results.push({
+            stable: true,
+            buffer: hunk.ab,
+            bufferStart: hunk.abStart,
+            bufferLength: hunk.abLength,
+            bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
+          });
         }
-        return datum2;
-      }
-      function pointerover(d3_event) {
-        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);
-          updateHover(d3_event, _targets);
-        }
-      }
-      function pointerout(d3_event) {
-        var target = eventTarget(d3_event);
-        var index = _targets.indexOf(target);
-        if (index !== -1) {
-          _targets.splice(index);
-          updateHover(d3_event, _targets);
+      } else {
+        let bounds = {
+          a: [a.length, -1, o.length, -1],
+          b: [b.length, -1, o.length, -1]
+        };
+        while (regionHunks.length) {
+          hunk = regionHunks.shift();
+          const oStart = hunk.oStart;
+          const oEnd = oStart + hunk.oLength;
+          const abStart = hunk.abStart;
+          const abEnd = abStart + hunk.abLength;
+          let b2 = bounds[hunk.ab];
+          b2[0] = Math.min(abStart, b2[0]);
+          b2[1] = Math.max(abEnd, b2[1]);
+          b2[2] = Math.min(oStart, b2[2]);
+          b2[3] = Math.max(oEnd, b2[3]);
         }
+        const aStart = bounds.a[0] + (regionStart - bounds.a[2]);
+        const aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
+        const bStart = bounds.b[0] + (regionStart - bounds.b[2]);
+        const bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
+        let result = {
+          stable: false,
+          aStart,
+          aLength: aEnd - aStart,
+          aContent: a.slice(aStart, aEnd),
+          oStart: regionStart,
+          oLength: regionEnd - regionStart,
+          oContent: o.slice(regionStart, regionEnd),
+          bStart,
+          bLength: bEnd - bStart,
+          bContent: b.slice(bStart, bEnd)
+        };
+        results.push(result);
       }
-      function allowsVertex(d) {
-        return d.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d, context.graph());
+      currOffset = regionEnd;
+    }
+    advanceTo(o.length);
+    return results;
+  }
+  function diff3Merge(a, o, b, options2) {
+    let defaults2 = {
+      excludeFalseConflicts: true,
+      stringSeparator: /\s+/
+    };
+    options2 = Object.assign(defaults2, options2);
+    if (typeof a === "string")
+      a = a.split(options2.stringSeparator);
+    if (typeof o === "string")
+      o = o.split(options2.stringSeparator);
+    if (typeof b === "string")
+      b = b.split(options2.stringSeparator);
+    let results = [];
+    const regions = diff3MergeRegions(a, o, b);
+    let okBuffer = [];
+    function flushOk() {
+      if (okBuffer.length) {
+        results.push({ ok: okBuffer });
       }
-      function modeAllowsHover(target) {
-        var mode = context.mode();
-        if (mode.id === "add-point") {
-          return mode.preset.matchGeometry("vertex") || target.type !== "way" && target.geometry(context.graph()) !== "vertex";
-        }
-        return true;
+      okBuffer = [];
+    }
+    function isFalseConflict(a2, b2) {
+      if (a2.length !== b2.length)
+        return false;
+      for (let i2 = 0; i2 < a2.length; i2++) {
+        if (a2[i2] !== b2[i2])
+          return false;
       }
-      function updateHover(d3_event, targets) {
-        _selection.selectAll(".hover").classed("hover", false);
-        _selection.selectAll(".hover-suppressed").classed("hover-suppressed", false);
-        var mode = context.mode();
-        if (!_newNodeId && (mode.id === "draw-line" || mode.id === "draw-area")) {
-          var node = targets.find(function(target) {
-            return target instanceof osmEntity && target.type === "node";
-          });
-          _newNodeId = node && node.id;
-        }
-        targets = targets.filter(function(datum3) {
-          if (datum3 instanceof osmEntity) {
-            return datum3.id !== _newNodeId && (datum3.type !== "node" || !_ignoreVertex || allowsVertex(datum3)) && modeAllowsHover(datum3);
-          }
-          return true;
-        });
-        var selector = "";
-        for (var i2 in targets) {
-          var datum2 = targets[i2];
-          if (datum2.__featurehash__) {
-            selector += ", .data" + datum2.__featurehash__;
-          } else if (datum2 instanceof QAItem) {
-            selector += ", ." + datum2.service + ".itemId-" + datum2.id;
-          } else if (datum2 instanceof osmNote) {
-            selector += ", .note-" + datum2.id;
-          } else if (datum2 instanceof osmEntity) {
-            selector += ", ." + datum2.id;
-            if (datum2.type === "relation") {
-              for (var j2 in datum2.members) {
-                selector += ", ." + datum2.members[j2].id;
-              }
+      return true;
+    }
+    regions.forEach((region) => {
+      if (region.stable) {
+        okBuffer.push(...region.bufferContent);
+      } else {
+        if (options2.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
+          okBuffer.push(...region.aContent);
+        } else {
+          flushOk();
+          results.push({
+            conflict: {
+              a: region.aContent,
+              aIndex: region.aStart,
+              o: region.oContent,
+              oIndex: region.oStart,
+              b: region.bContent,
+              bIndex: region.bStart
             }
-          }
-        }
-        var suppressed = _altDisables && d3_event && d3_event.altKey;
-        if (selector.trim().length) {
-          selector = selector.slice(1);
-          _selection.selectAll(selector).classed(suppressed ? "hover-suppressed" : "hover", true);
+          });
         }
-        dispatch10.call("hover", this, !suppressed && targets);
       }
-    }
-    behavior.off = function(selection2) {
-      selection2.selectAll(".hover").classed("hover", false);
-      selection2.selectAll(".hover-suppressed").classed("hover-suppressed", false);
-      selection2.classed("hover-disabled", false);
-      selection2.on(_pointerPrefix + "over.hover", null).on(_pointerPrefix + "out.hover", null).on(_pointerPrefix + "down.hover", null);
-      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;
-      _altDisables = val;
-      return behavior;
-    };
-    behavior.ignoreVertex = function(val) {
-      if (!arguments.length)
-        return _ignoreVertex;
-      _ignoreVertex = val;
-      return behavior;
-    };
-    behavior.initialNodeID = function(nodeId) {
-      _initialNodeID = nodeId;
-      return behavior;
-    };
-    return utilRebind(behavior, dispatch10, "on");
+    });
+    flushOk();
+    return results;
   }
 
-  // modules/behavior/draw.js
-  var _disableSpace = false;
-  var _lastSpace = null;
-  function behaviorDraw(context) {
-    var dispatch10 = dispatch_default(
-      "move",
-      "down",
-      "downcancel",
-      "click",
-      "clickWay",
-      "clickNode",
-      "undo",
-      "cancel",
-      "finish"
-    );
-    var keybinding = utilKeybinding("draw");
-    var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on("hover", context.ui().sidebar.hover);
-    var _edit = behaviorEdit(context);
-    var _closeTolerance = 4;
-    var _tolerance = 12;
-    var _mouseLeave = false;
-    var _lastMouse = null;
-    var _lastPointerUpEvent;
-    var _downPointer;
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    function datum2(d3_event) {
-      var mode = context.mode();
-      var isNote = mode && mode.id.indexOf("note") !== -1;
-      if (d3_event.altKey || isNote)
-        return {};
-      var element;
-      if (d3_event.type === "keydown") {
-        element = _lastMouse && _lastMouse.target;
-      } else {
-        element = d3_event.target;
-      }
-      var d = element.__data__;
-      return d && d.properties && d.properties.target ? d : {};
-    }
-    function pointerdown(d3_event) {
-      if (_downPointer)
-        return;
-      var pointerLocGetter = utilFastMouse(this);
-      _downPointer = {
-        id: d3_event.pointerId || "mouse",
-        pointerLocGetter,
-        downTime: +new Date(),
-        downLoc: pointerLocGetter(d3_event)
-      };
-      dispatch10.call("down", this, d3_event, datum2(d3_event));
+  // modules/actions/merge_remote_changes.js
+  var import_lodash2 = __toESM(require_lodash());
+  function actionMergeRemoteChanges(id2, localGraph, remoteGraph, discardTags, formatUser) {
+    discardTags = discardTags || {};
+    var _option = "safe";
+    var _conflicts = [];
+    function user(d) {
+      return typeof formatUser === "function" ? formatUser(d) : (0, import_lodash2.escape)(d);
     }
-    function pointerup(d3_event) {
-      if (!_downPointer || _downPointer.id !== (d3_event.pointerId || "mouse"))
-        return;
-      var downPointer = _downPointer;
-      _downPointer = null;
-      _lastPointerUpEvent = d3_event;
-      if (downPointer.isCancelled)
-        return;
-      var t2 = +new Date();
-      var p2 = downPointer.pointerLocGetter(d3_event);
-      var dist = geoVecLength(downPointer.downLoc, p2);
-      if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
-        select_default2(window).on("click.draw-block", function() {
-          d3_event.stopPropagation();
-        }, true);
-        context.map().dblclickZoomEnable(false);
-        window.setTimeout(function() {
-          context.map().dblclickZoomEnable(true);
-          select_default2(window).on("click.draw-block", null);
-        }, 500);
-        click(d3_event, p2);
+    function mergeLocation(remote, target) {
+      function pointEqual(a, b) {
+        var epsilon3 = 1e-6;
+        return Math.abs(a[0] - b[0]) < epsilon3 && Math.abs(a[1] - b[1]) < epsilon3;
+      }
+      if (_option === "force_local" || pointEqual(target.loc, remote.loc)) {
+        return target;
       }
+      if (_option === "force_remote") {
+        return target.update({ loc: remote.loc });
+      }
+      _conflicts.push(_t.html("merge_remote_changes.conflict.location", { user: { html: user(remote.user) } }));
+      return target;
     }
-    function pointermove(d3_event) {
-      if (_downPointer && _downPointer.id === (d3_event.pointerId || "mouse") && !_downPointer.isCancelled) {
-        var p2 = _downPointer.pointerLocGetter(d3_event);
-        var dist = geoVecLength(_downPointer.downLoc, p2);
-        if (dist >= _closeTolerance) {
-          _downPointer.isCancelled = true;
-          dispatch10.call("downcancel", this);
+    function mergeNodes(base, remote, target) {
+      if (_option === "force_local" || (0, import_fast_deep_equal.default)(target.nodes, remote.nodes)) {
+        return target;
+      }
+      if (_option === "force_remote") {
+        return target.update({ nodes: remote.nodes });
+      }
+      var ccount = _conflicts.length;
+      var o = base.nodes || [];
+      var a = target.nodes || [];
+      var b = remote.nodes || [];
+      var nodes = [];
+      var hunks = diff3Merge(a, o, b, { excludeFalseConflicts: true });
+      for (var i2 = 0; i2 < hunks.length; i2++) {
+        var hunk = hunks[i2];
+        if (hunk.ok) {
+          nodes.push.apply(nodes, hunk.ok);
+        } else {
+          var c = hunk.conflict;
+          if ((0, import_fast_deep_equal.default)(c.o, c.a)) {
+            nodes.push.apply(nodes, c.b);
+          } else if ((0, import_fast_deep_equal.default)(c.o, c.b)) {
+            nodes.push.apply(nodes, c.a);
+          } else {
+            _conflicts.push(_t.html("merge_remote_changes.conflict.nodelist", { user: { html: user(remote.user) } }));
+            break;
+          }
         }
       }
-      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;
-      dispatch10.call("move", this, d3_event, datum2(d3_event));
+      return _conflicts.length === ccount ? target.update({ nodes }) : target;
     }
-    function pointercancel(d3_event) {
-      if (_downPointer && _downPointer.id === (d3_event.pointerId || "mouse")) {
-        if (!_downPointer.isCancelled) {
-          dispatch10.call("downcancel", this);
+    function mergeChildren(targetWay, children2, updates, graph) {
+      function isUsed(node2, targetWay2) {
+        var hasInterestingParent = graph.parentWays(node2).some(function(way) {
+          return way.id !== targetWay2.id;
+        });
+        return node2.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node2).length > 0;
+      }
+      var ccount = _conflicts.length;
+      for (var i2 = 0; i2 < children2.length; i2++) {
+        var id3 = children2[i2];
+        var node = graph.hasEntity(id3);
+        if (targetWay.nodes.indexOf(id3) === -1) {
+          if (node && !isUsed(node, targetWay)) {
+            updates.removeIds.push(id3);
+          }
+          continue;
+        }
+        var local = localGraph.hasEntity(id3);
+        var remote = remoteGraph.hasEntity(id3);
+        var target;
+        if (_option === "force_remote" && remote && remote.visible) {
+          updates.replacements.push(remote);
+        } else if (_option === "force_local" && local) {
+          target = osmEntity(local);
+          if (remote) {
+            target = target.update({ version: remote.version });
+          }
+          updates.replacements.push(target);
+        } else if (_option === "safe" && local && remote && local.version !== remote.version) {
+          target = osmEntity(local, { version: remote.version });
+          if (remote.visible) {
+            target = mergeLocation(remote, target);
+          } else {
+            _conflicts.push(_t.html("merge_remote_changes.conflict.deleted", { user: { html: user(remote.user) } }));
+          }
+          if (_conflicts.length !== ccount)
+            break;
+          updates.replacements.push(target);
         }
-        _downPointer = null;
       }
+      return targetWay;
     }
-    function mouseenter() {
-      _mouseLeave = false;
-    }
-    function mouseleave() {
-      _mouseLeave = true;
+    function updateChildren(updates, graph) {
+      for (var i2 = 0; i2 < updates.replacements.length; i2++) {
+        graph = graph.replace(updates.replacements[i2]);
+      }
+      if (updates.removeIds.length) {
+        graph = actionDeleteMultiple(updates.removeIds)(graph);
+      }
+      return graph;
     }
-    function allowsVertex(d) {
-      return d.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d, context.graph());
+    function mergeMembers(remote, target) {
+      if (_option === "force_local" || (0, import_fast_deep_equal.default)(target.members, remote.members)) {
+        return target;
+      }
+      if (_option === "force_remote") {
+        return target.update({ members: remote.members });
+      }
+      _conflicts.push(_t.html("merge_remote_changes.conflict.memberlist", { user: { html: user(remote.user) } }));
+      return target;
     }
-    function click(d3_event, loc) {
-      var d = datum2(d3_event);
-      var target = d && d.properties && d.properties.entity;
-      var mode = context.mode();
-      if (target && target.type === "node" && allowsVertex(target)) {
-        dispatch10.call("clickNode", this, target, d);
-        return;
-      } else if (target && target.type === "way" && (mode.id !== "add-point" || mode.preset.matchGeometry("vertex"))) {
-        var choice = geoChooseEdge(
-          context.graph().childNodes(target),
-          loc,
-          context.projection,
-          context.activeID()
-        );
-        if (choice) {
-          var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
-          dispatch10.call("clickWay", this, choice.loc, edge, d);
-          return;
+    function mergeTags(base, remote, target) {
+      if (_option === "force_local" || (0, import_fast_deep_equal.default)(target.tags, remote.tags)) {
+        return target;
+      }
+      if (_option === "force_remote") {
+        return target.update({ tags: remote.tags });
+      }
+      var ccount = _conflicts.length;
+      var o = base.tags || {};
+      var a = target.tags || {};
+      var b = remote.tags || {};
+      var keys2 = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function(k2) {
+        return !discardTags[k2];
+      });
+      var tags = Object.assign({}, a);
+      var changed = false;
+      for (var i2 = 0; i2 < keys2.length; i2++) {
+        var k = keys2[i2];
+        if (o[k] !== b[k] && a[k] !== b[k]) {
+          if (o[k] !== a[k]) {
+            _conflicts.push(_t.html(
+              "merge_remote_changes.conflict.tags",
+              { tag: k, local: a[k], remote: b[k], user: { html: user(remote.user) } }
+            ));
+          } else {
+            if (b.hasOwnProperty(k)) {
+              tags[k] = b[k];
+            } else {
+              delete tags[k];
+            }
+            changed = true;
+          }
         }
-      } else if (mode.id !== "add-point" || mode.preset.matchGeometry("point")) {
-        var locLatLng = context.projection.invert(loc);
-        dispatch10.call("click", this, locLatLng, d);
       }
+      return changed && _conflicts.length === ccount ? target.update({ tags }) : target;
     }
-    function space(d3_event) {
-      d3_event.preventDefault();
-      d3_event.stopPropagation();
-      var currSpace = context.map().mouse();
-      if (_disableSpace && _lastSpace) {
-        var dist = geoVecLength(_lastSpace, currSpace);
-        if (dist > _tolerance) {
-          _disableSpace = false;
+    var action = function(graph) {
+      var updates = { replacements: [], removeIds: [] };
+      var base = graph.base().entities[id2];
+      var local = localGraph.entity(id2);
+      var remote = remoteGraph.entity(id2);
+      var target = osmEntity(local, { version: remote.version });
+      if (!remote.visible) {
+        if (_option === "force_remote") {
+          return actionDeleteMultiple([id2])(graph);
+        } else if (_option === "force_local") {
+          if (target.type === "way") {
+            target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
+            graph = updateChildren(updates, graph);
+          }
+          return graph.replace(target);
+        } else {
+          _conflicts.push(_t.html("merge_remote_changes.conflict.deleted", { user: { html: user(remote.user) } }));
+          return graph;
         }
       }
-      if (_disableSpace || _mouseLeave || !_lastMouse)
-        return;
-      _lastSpace = currSpace;
-      _disableSpace = true;
-      select_default2(window).on("keyup.space-block", function() {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        _disableSpace = false;
-        select_default2(window).on("keyup.space-block", null);
-      });
-      var loc = context.map().mouse() || context.projection(context.map().center());
-      click(d3_event, loc);
-    }
-    function backspace(d3_event) {
-      d3_event.preventDefault();
-      dispatch10.call("undo");
-    }
-    function del(d3_event) {
-      d3_event.preventDefault();
-      dispatch10.call("cancel");
-    }
-    function ret(d3_event) {
-      d3_event.preventDefault();
-      dispatch10.call("finish");
-    }
-    function behavior(selection2) {
-      context.install(_hover);
-      context.install(_edit);
-      _downPointer = null;
-      keybinding.on("\u232B", backspace).on("\u2326", del).on("\u238B", ret).on("\u21A9", ret).on("space", space).on("\u2325space", space);
-      selection2.on("mouseenter.draw", mouseenter).on("mouseleave.draw", mouseleave).on(_pointerPrefix + "down.draw", pointerdown).on(_pointerPrefix + "move.draw", pointermove);
-      select_default2(window).on(_pointerPrefix + "up.draw", pointerup, true).on("pointercancel.draw", pointercancel, true);
-      select_default2(document).call(keybinding);
-      return behavior;
-    }
-    behavior.off = function(selection2) {
-      context.ui().sidebar.hover.cancel();
-      context.uninstall(_hover);
-      context.uninstall(_edit);
-      selection2.on("mouseenter.draw", null).on("mouseleave.draw", null).on(_pointerPrefix + "down.draw", null).on(_pointerPrefix + "move.draw", null);
-      select_default2(window).on(_pointerPrefix + "up.draw", null).on("pointercancel.draw", null);
-      select_default2(document).call(keybinding.unbind);
+      if (target.type === "node") {
+        target = mergeLocation(remote, target);
+      } else if (target.type === "way") {
+        graph.rebase(remoteGraph.childNodes(remote), [graph], false);
+        target = mergeNodes(base, remote, target);
+        target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
+      } else if (target.type === "relation") {
+        target = mergeMembers(remote, target);
+      }
+      target = mergeTags(base, remote, target);
+      if (!_conflicts.length) {
+        graph = updateChildren(updates, graph).replace(target);
+      }
+      return graph;
     };
-    behavior.hover = function() {
-      return _hover;
+    action.withOption = function(opt) {
+      _option = opt;
+      return action;
     };
-    return utilRebind(behavior, dispatch10, "on");
+    action.conflicts = function() {
+      return _conflicts;
+    };
+    return action;
   }
 
-  // modules/behavior/breathe.js
-  var import_fast_deep_equal2 = __toESM(require_fast_deep_equal());
-
-  // node_modules/d3-scale/src/init.js
-  function initRange(domain2, range3) {
-    switch (arguments.length) {
-      case 0:
-        break;
-      case 1:
-        this.range(domain2);
-        break;
-      default:
-        this.range(range3).domain(domain2);
-        break;
+  // modules/actions/move.js
+  function actionMove(moveIDs, tryDelta, projection2, cache) {
+    var _delta = tryDelta;
+    function setupCache(graph) {
+      function canMove(nodeID) {
+        if (moveIDs.indexOf(nodeID) !== -1)
+          return true;
+        var parents = graph.parentWays(graph.entity(nodeID));
+        if (parents.length < 3)
+          return true;
+        var parentsMoving = parents.every(function(way) {
+          return cache.moving[way.id];
+        });
+        if (!parentsMoving)
+          delete cache.moving[nodeID];
+        return parentsMoving;
+      }
+      function cacheEntities(ids) {
+        for (var i2 = 0; i2 < ids.length; i2++) {
+          var id2 = ids[i2];
+          if (cache.moving[id2])
+            continue;
+          cache.moving[id2] = true;
+          var entity = graph.hasEntity(id2);
+          if (!entity)
+            continue;
+          if (entity.type === "node") {
+            cache.nodes.push(id2);
+            cache.startLoc[id2] = entity.loc;
+          } else if (entity.type === "way") {
+            cache.ways.push(id2);
+            cacheEntities(entity.nodes);
+          } else {
+            cacheEntities(entity.members.map(function(member) {
+              return member.id;
+            }));
+          }
+        }
+      }
+      function cacheIntersections(ids) {
+        function isEndpoint(way2, id3) {
+          return !way2.isClosed() && !!way2.affix(id3);
+        }
+        for (var i2 = 0; i2 < ids.length; i2++) {
+          var id2 = ids[i2];
+          var childNodes = graph.childNodes(graph.entity(id2));
+          for (var j2 = 0; j2 < childNodes.length; j2++) {
+            var node = childNodes[j2];
+            var parents = graph.parentWays(node);
+            if (parents.length !== 2)
+              continue;
+            var moved = graph.entity(id2);
+            var unmoved = null;
+            for (var k = 0; k < parents.length; k++) {
+              var way = parents[k];
+              if (!cache.moving[way.id]) {
+                unmoved = way;
+                break;
+              }
+            }
+            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,
+              unmovedId: unmoved.id,
+              movedIsEP: isEndpoint(moved, node.id),
+              unmovedIsEP: isEndpoint(unmoved, node.id)
+            });
+          }
+        }
+      }
+      if (!cache) {
+        cache = {};
+      }
+      if (!cache.ok) {
+        cache.moving = {};
+        cache.intersections = [];
+        cache.replacedVertex = {};
+        cache.startLoc = {};
+        cache.nodes = [];
+        cache.ways = [];
+        cacheEntities(moveIDs);
+        cacheIntersections(cache.ways);
+        cache.nodes = cache.nodes.filter(canMove);
+        cache.ok = true;
+      }
     }
-    return this;
-  }
-
-  // node_modules/d3-scale/src/constant.js
-  function constants(x) {
-    return function() {
-      return x;
-    };
-  }
-
-  // node_modules/d3-scale/src/number.js
-  function number2(x) {
-    return +x;
-  }
-
-  // node_modules/d3-scale/src/continuous.js
-  var unit = [0, 1];
-  function identity3(x) {
-    return x;
-  }
-  function normalize(a, b) {
-    return (b -= a = +a) ? function(x) {
-      return (x - a) / b;
-    } : constants(isNaN(b) ? NaN : 0.5);
-  }
-  function clamper(a, b) {
-    var t;
-    if (a > b)
-      t = a, a = b, b = t;
-    return function(x) {
-      return Math.max(a, Math.min(b, x));
-    };
-  }
-  function bimap(domain2, range3, interpolate) {
-    var d0 = domain2[0], d1 = domain2[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);
-    return function(x) {
-      return r0(d0(x));
-    };
-  }
-  function polymap(domain2, range3, interpolate) {
-    var j2 = Math.min(domain2.length, range3.length) - 1, d = new Array(j2), r = new Array(j2), i2 = -1;
-    if (domain2[j2] < domain2[0]) {
-      domain2 = domain2.slice().reverse();
-      range3 = range3.slice().reverse();
+    function replaceMovedVertex(nodeId, wayId, graph, delta) {
+      var way = graph.entity(wayId);
+      var moved = graph.entity(nodeId);
+      var movedIndex = way.nodes.indexOf(nodeId);
+      var len, prevIndex, nextIndex;
+      if (way.isClosed()) {
+        len = way.nodes.length - 1;
+        prevIndex = (movedIndex + len - 1) % len;
+        nextIndex = (movedIndex + len + 1) % len;
+      } else {
+        len = way.nodes.length;
+        prevIndex = movedIndex - 1;
+        nextIndex = movedIndex + 1;
+      }
+      var prev = graph.hasEntity(way.nodes[prevIndex]);
+      var next = graph.hasEntity(way.nodes[nextIndex]);
+      if (!prev || !next)
+        return graph;
+      var key = wayId + "_" + nodeId;
+      var orig = cache.replacedVertex[key];
+      if (!orig) {
+        orig = osmNode();
+        cache.replacedVertex[key] = orig;
+        cache.startLoc[orig.id] = cache.startLoc[nodeId];
+      }
+      var start2, end;
+      if (delta) {
+        start2 = projection2(cache.startLoc[nodeId]);
+        end = projection2.invert(geoVecAdd(start2, delta));
+      } else {
+        end = cache.startLoc[nodeId];
+      }
+      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;
+      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;
+      way = way.addNode(orig.id, insertAt);
+      return graph.replace(orig).replace(way);
     }
-    while (++i2 < j2) {
-      d[i2] = normalize(domain2[i2], domain2[i2 + 1]);
-      r[i2] = interpolate(range3[i2], range3[i2 + 1]);
+    function removeDuplicateVertices(wayId, graph) {
+      var way = graph.entity(wayId);
+      var epsilon3 = 1e-6;
+      var prev, curr;
+      function isInteresting(node, graph2) {
+        return graph2.parentWays(node).length > 1 || graph2.parentRelations(node).length || node.hasInterestingTags();
+      }
+      for (var i2 = 0; i2 < way.nodes.length; i2++) {
+        curr = graph.entity(way.nodes[i2]);
+        if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon3)) {
+          if (!isInteresting(prev, graph)) {
+            way = way.removeNode(prev.id);
+            graph = graph.replace(way).remove(prev);
+          } else if (!isInteresting(curr, graph)) {
+            way = way.removeNode(curr.id);
+            graph = graph.replace(way).remove(curr);
+          }
+        }
+        prev = curr;
+      }
+      return graph;
     }
-    return function(x) {
-      var i3 = bisect_default(domain2, x, 1, j2) - 1;
-      return r[i3](d[i3](x));
-    };
-  }
-  function copy(source, target) {
-    return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
-  }
-  function transformer2() {
-    var domain2 = unit, range3 = unit, interpolate = value_default, transform2, untransform, unknown, clamp3 = identity3, piecewise, output, input;
-    function rescale() {
-      var n2 = Math.min(domain2.length, range3.length);
-      if (clamp3 !== identity3)
-        clamp3 = clamper(domain2[0], domain2[n2 - 1]);
-      piecewise = n2 > 2 ? polymap : bimap;
-      output = input = null;
-      return scale;
+    function unZorroIntersection(intersection, graph) {
+      var vertex = graph.entity(intersection.nodeId);
+      var way1 = graph.entity(intersection.movedId);
+      var way2 = graph.entity(intersection.unmovedId);
+      var isEP1 = intersection.movedIsEP;
+      var isEP2 = intersection.unmovedIsEP;
+      if (isEP1 && isEP2)
+        return graph;
+      var nodes1 = graph.childNodes(way1).filter(function(n2) {
+        return n2 !== vertex;
+      });
+      var nodes2 = graph.childNodes(way2).filter(function(n2) {
+        return n2 !== vertex;
+      });
+      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;
+      if (!isEP1 && !isEP2) {
+        var epsilon3 = 1e-6, maxIter = 10;
+        for (var i2 = 0; i2 < maxIter; i2++) {
+          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;
+        }
+      } else if (!isEP1) {
+        loc = edge1.loc;
+      } else {
+        loc = edge2.loc;
+      }
+      graph = graph.replace(vertex.move(loc));
+      if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
+        way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
+        graph = graph.replace(way1);
+      }
+      if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
+        way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
+        graph = graph.replace(way2);
+      }
+      return graph;
     }
-    function scale(x) {
-      return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain2.map(transform2), range3, interpolate)))(transform2(clamp3(x)));
+    function cleanupIntersections(graph) {
+      for (var i2 = 0; i2 < cache.intersections.length; i2++) {
+        var obj = cache.intersections[i2];
+        graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
+        graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
+        graph = unZorroIntersection(obj, graph);
+        graph = removeDuplicateVertices(obj.movedId, graph);
+        graph = removeDuplicateVertices(obj.unmovedId, graph);
+      }
+      return graph;
     }
-    scale.invert = function(y) {
-      return clamp3(untransform((input || (input = piecewise(range3, domain2.map(transform2), number_default)))(y)));
-    };
-    scale.domain = function(_) {
-      return arguments.length ? (domain2 = Array.from(_, number2), rescale()) : domain2.slice();
-    };
-    scale.range = function(_) {
-      return arguments.length ? (range3 = Array.from(_), rescale()) : range3.slice();
-    };
-    scale.rangeRound = function(_) {
-      return range3 = Array.from(_), interpolate = round_default, rescale();
-    };
-    scale.clamp = function(_) {
-      return arguments.length ? (clamp3 = _ ? true : identity3, rescale()) : clamp3 !== identity3;
-    };
-    scale.interpolate = function(_) {
-      return arguments.length ? (interpolate = _, rescale()) : interpolate;
-    };
-    scale.unknown = function(_) {
-      return arguments.length ? (unknown = _, scale) : unknown;
+    function limitDelta(graph) {
+      function moveNode(loc) {
+        return geoVecAdd(projection2(loc), _delta);
+      }
+      for (var i2 = 0; i2 < cache.intersections.length; i2++) {
+        var obj = cache.intersections[i2];
+        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 movedNodes = graph.childNodes(graph.entity(obj.movedId));
+        var movedPath = movedNodes.map(function(n2) {
+          return moveNode(n2.loc);
+        });
+        var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
+        var unmovedPath = unmovedNodes.map(function(n2) {
+          return projection2(n2.loc);
+        });
+        var hits = geoPathIntersections(movedPath, unmovedPath);
+        for (var j2 = 0; i2 < hits.length; i2++) {
+          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;
+      setupCache(graph);
+      if (cache.intersections.length) {
+        limitDelta(graph);
+      }
+      for (var i2 = 0; i2 < cache.nodes.length; i2++) {
+        var node = graph.entity(cache.nodes[i2]);
+        var start2 = projection2(node.loc);
+        var end = geoVecAdd(start2, _delta);
+        graph = graph.replace(node.move(projection2.invert(end)));
+      }
+      if (cache.intersections.length) {
+        graph = cleanupIntersections(graph);
+      }
+      return graph;
     };
-    return function(t, u) {
-      transform2 = t, untransform = u;
-      return rescale();
+    action.delta = function() {
+      return _delta;
     };
-  }
-  function continuous() {
-    return transformer2()(identity3, identity3);
-  }
-
-  // node_modules/d3-format/src/formatDecimal.js
-  function formatDecimal_default(x) {
-    return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
-  }
-  function formatDecimalParts(x, p) {
-    if ((i2 = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0)
-      return null;
-    var i2, coefficient = x.slice(0, i2);
-    return [
-      coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
-      +x.slice(i2 + 1)
-    ];
-  }
-
-  // node_modules/d3-format/src/exponent.js
-  function exponent_default(x) {
-    return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
+    return action;
   }
 
-  // node_modules/d3-format/src/formatGroup.js
-  function formatGroup_default(grouping, thousands) {
-    return function(value, width) {
-      var i2 = value.length, t = [], j2 = 0, g = grouping[0], length = 0;
-      while (i2 > 0 && g > 0) {
-        if (length + g + 1 > width)
-          g = Math.max(1, width - length);
-        t.push(value.substring(i2 -= g, i2 + g));
-        if ((length += g + 1) > width)
-          break;
-        g = grouping[j2 = (j2 + 1) % grouping.length];
-      }
-      return t.reverse().join(thousands);
+  // modules/actions/move_member.js
+  function actionMoveMember(relationId, fromIndex, toIndex) {
+    return function(graph) {
+      return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
     };
   }
 
-  // node_modules/d3-format/src/formatNumerals.js
-  function formatNumerals_default(numerals) {
-    return function(value) {
-      return value.replace(/[0-9]/g, function(i2) {
-        return numerals[+i2];
-      });
+  // modules/actions/move_node.js
+  function actionMoveNode(nodeID, toLoc) {
+    var action = function(graph, t) {
+      if (t === null || !isFinite(t))
+        t = 1;
+      t = Math.min(Math.max(+t, 0), 1);
+      var node = graph.entity(nodeID);
+      return graph.replace(
+        node.move(geoVecInterp(node.loc, toLoc, t))
+      );
     };
+    action.transitionable = true;
+    return action;
   }
 
-  // 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);
-    var match;
-    return new FormatSpecifier({
-      fill: match[1],
-      align: match[2],
-      sign: match[3],
-      symbol: match[4],
-      zero: match[5],
-      width: match[6],
-      comma: match[7],
-      precision: match[8] && match[8].slice(1),
-      trim: match[9],
-      type: match[10]
-    });
-  }
-  formatSpecifier.prototype = FormatSpecifier.prototype;
-  function FormatSpecifier(specifier) {
-    this.fill = specifier.fill === void 0 ? " " : specifier.fill + "";
-    this.align = specifier.align === void 0 ? ">" : specifier.align + "";
-    this.sign = specifier.sign === void 0 ? "-" : specifier.sign + "";
-    this.symbol = specifier.symbol === void 0 ? "" : specifier.symbol + "";
-    this.zero = !!specifier.zero;
-    this.width = specifier.width === void 0 ? void 0 : +specifier.width;
-    this.comma = !!specifier.comma;
-    this.precision = specifier.precision === void 0 ? void 0 : +specifier.precision;
-    this.trim = !!specifier.trim;
-    this.type = specifier.type === void 0 ? "" : specifier.type + "";
+  // modules/actions/noop.js
+  function actionNoop() {
+    return function(graph) {
+      return graph;
+    };
   }
-  FormatSpecifier.prototype.toString = function() {
-    return this.fill + this.align + this.sign + this.symbol + (this.zero ? "0" : "") + (this.width === void 0 ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") + (this.precision === void 0 ? "" : "." + Math.max(0, this.precision | 0)) + (this.trim ? "~" : "") + this.type;
-  };
 
-  // node_modules/d3-format/src/formatTrim.js
-  function formatTrim_default(s) {
-    out:
-      for (var n2 = s.length, i2 = 1, i0 = -1, i1; i2 < n2; ++i2) {
-        switch (s[i2]) {
-          case ".":
-            i0 = i1 = i2;
-            break;
-          case "0":
-            if (i0 === 0)
-              i0 = i2;
-            i1 = i2;
-            break;
-          default:
-            if (!+s[i2])
-              break out;
-            if (i0 > 0)
-              i0 = 0;
-            break;
-        }
+  // modules/actions/orthogonalize.js
+  function actionOrthogonalize(wayID, projection2, vertexID, degThresh, ep) {
+    var epsilon3 = ep || 1e-4;
+    var threshold = degThresh || 13;
+    var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
+    var upperThreshold = Math.cos(threshold * Math.PI / 180);
+    var action = function(graph, t) {
+      if (t === null || !isFinite(t))
+        t = 1;
+      t = Math.min(Math.max(+t, 0), 1);
+      var way = graph.entity(wayID);
+      way = way.removeNode("");
+      if (way.tags.nonsquare) {
+        var tags = Object.assign({}, way.tags);
+        delete tags.nonsquare;
+        way = way.update({ tags });
       }
-    return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
-  }
-
-  // node_modules/d3-format/src/formatPrefixAuto.js
-  var prefixExponent;
-  function formatPrefixAuto_default(x, p) {
-    var d = formatDecimalParts(x, p);
-    if (!d)
-      return x + "";
-    var coefficient = d[0], exponent = d[1], i2 = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1, n2 = coefficient.length;
-    return i2 === n2 ? coefficient : i2 > n2 ? coefficient + new Array(i2 - n2 + 1).join("0") : i2 > 0 ? coefficient.slice(0, i2) + "." + coefficient.slice(i2) : "0." + new Array(1 - i2).join("0") + formatDecimalParts(x, Math.max(0, p + i2 - 1))[0];
-  }
-
-  // node_modules/d3-format/src/formatRounded.js
-  function formatRounded_default(x, p) {
-    var d = formatDecimalParts(x, p);
-    if (!d)
-      return x + "";
-    var coefficient = d[0], exponent = d[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");
-  }
-
-  // node_modules/d3-format/src/formatTypes.js
-  var formatTypes_default = {
-    "%": (x, p) => (x * 100).toFixed(p),
-    "b": (x) => Math.round(x).toString(2),
-    "c": (x) => x + "",
-    "d": formatDecimal_default,
-    "e": (x, p) => x.toExponential(p),
-    "f": (x, p) => x.toFixed(p),
-    "g": (x, p) => x.toPrecision(p),
-    "o": (x) => Math.round(x).toString(8),
-    "p": (x, p) => formatRounded_default(x * 100, p),
-    "r": formatRounded_default,
-    "s": formatPrefixAuto_default,
-    "X": (x) => Math.round(x).toString(16).toUpperCase(),
-    "x": (x) => Math.round(x).toString(16)
-  };
-
-  // node_modules/d3-format/src/identity.js
-  function identity_default3(x) {
-    return x;
-  }
-
-  // node_modules/d3-format/src/locale.js
-  var map = Array.prototype.map;
-  var prefixes = ["y", "z", "a", "f", "p", "n", "\xB5", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
-  function locale_default(locale2) {
-    var group = locale2.grouping === void 0 || locale2.thousands === void 0 ? identity_default3 : formatGroup_default(map.call(locale2.grouping, Number), locale2.thousands + ""), currencyPrefix = locale2.currency === void 0 ? "" : locale2.currency[0] + "", currencySuffix = locale2.currency === void 0 ? "" : locale2.currency[1] + "", decimal = locale2.decimal === void 0 ? "." : locale2.decimal + "", numerals = locale2.numerals === void 0 ? identity_default3 : formatNumerals_default(map.call(locale2.numerals, String)), percent = locale2.percent === void 0 ? "%" : locale2.percent + "", minus = locale2.minus === void 0 ? "\u2212" : locale2.minus + "", nan = locale2.nan === void 0 ? "NaN" : locale2.nan + "";
-    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, precision2 = specifier.precision, trim = specifier.trim, type3 = specifier.type;
-      if (type3 === "n")
-        comma = true, type3 = "g";
-      else if (!formatTypes_default[type3])
-        precision2 === void 0 && (precision2 = 12), trim = true, type3 = "g";
-      if (zero3 || fill === "0" && align === "=")
-        zero3 = true, fill = "0", align = "=";
-      var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type3) ? "0" + type3.toLowerCase() : "", suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type3) ? percent : "";
-      var formatType = formatTypes_default[type3], maybeSuffix = /[defgprs%]/.test(type3);
-      precision2 = precision2 === void 0 ? 6 : /[gprs]/.test(type3) ? Math.max(1, Math.min(21, precision2)) : Math.max(0, Math.min(20, precision2));
-      function format2(value) {
-        var valuePrefix = prefix, valueSuffix = suffix, i2, n2, c;
-        if (type3 === "c") {
-          valueSuffix = formatType(value) + valueSuffix;
-          value = "";
-        } else {
-          value = +value;
-          var valueNegative = value < 0 || 1 / value < 0;
-          value = isNaN(value) ? nan : formatType(Math.abs(value), precision2);
-          if (trim)
-            value = formatTrim_default(value);
-          if (valueNegative && +value === 0 && sign2 !== "+")
-            valueNegative = false;
-          valuePrefix = (valueNegative ? sign2 === "(" ? sign2 : minus : sign2 === "-" || sign2 === "(" ? "" : sign2) + valuePrefix;
-          valueSuffix = (type3 === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign2 === "(" ? ")" : "");
-          if (maybeSuffix) {
-            i2 = -1, n2 = value.length;
-            while (++i2 < n2) {
-              if (c = value.charCodeAt(i2), 48 > c || c > 57) {
-                valueSuffix = (c === 46 ? decimal + value.slice(i2 + 1) : value.slice(i2)) + valueSuffix;
-                value = value.slice(0, i2);
-                break;
-              }
-            }
+      graph = graph.replace(way);
+      var isClosed = way.isClosed();
+      var nodes = graph.childNodes(way).slice();
+      if (isClosed)
+        nodes.pop();
+      if (vertexID !== void 0) {
+        nodes = nodeSubset(nodes, vertexID, isClosed);
+        if (nodes.length !== 3)
+          return graph;
+      }
+      var nodeCount = {};
+      var points = [];
+      var corner = { i: 0, dotp: 1 };
+      var node, point2, loc, score, motions, i2, j2;
+      for (i2 = 0; i2 < nodes.length; i2++) {
+        node = nodes[i2];
+        nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
+        points.push({ id: node.id, coord: projection2(node.loc) });
+      }
+      if (points.length === 3) {
+        for (i2 = 0; i2 < 1e3; i2++) {
+          motions = points.map(calcMotion);
+          points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
+          score = corner.dotp;
+          if (score < epsilon3) {
+            break;
           }
         }
-        if (comma && !zero3)
-          value = group(value, Infinity);
-        var length = valuePrefix.length + value.length + valueSuffix.length, padding = length < width ? new Array(width - length + 1).join(fill) : "";
-        if (comma && zero3)
-          value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
-        switch (align) {
-          case "<":
-            value = valuePrefix + value + valueSuffix + padding;
-            break;
-          case "=":
-            value = valuePrefix + padding + value + valueSuffix;
-            break;
-          case "^":
-            value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
-            break;
-          default:
-            value = padding + valuePrefix + value + valueSuffix;
+        node = graph.entity(nodes[corner.i].id);
+        loc = projection2.invert(points[corner.i].coord);
+        graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
+      } else {
+        var straights = [];
+        var simplified = [];
+        for (i2 = 0; i2 < points.length; i2++) {
+          point2 = points[i2];
+          var dotp = 0;
+          if (isClosed || i2 > 0 && i2 < points.length - 1) {
+            var a = points[(i2 - 1 + points.length) % points.length];
+            var b = points[(i2 + 1) % points.length];
+            dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point2.coord));
+          }
+          if (dotp > upperThreshold) {
+            straights.push(point2);
+          } else {
+            simplified.push(point2);
+          }
+        }
+        var bestPoints = clonePoints(simplified);
+        var originalPoints = clonePoints(simplified);
+        score = Infinity;
+        for (i2 = 0; i2 < 1e3; i2++) {
+          motions = simplified.map(calcMotion);
+          for (j2 = 0; j2 < motions.length; j2++) {
+            simplified[j2].coord = geoVecAdd(simplified[j2].coord, motions[j2]);
+          }
+          var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon3, threshold);
+          if (newScore < score) {
+            bestPoints = clonePoints(simplified);
+            score = newScore;
+          }
+          if (score < epsilon3) {
             break;
+          }
+        }
+        var bestCoords = bestPoints.map(function(p) {
+          return p.coord;
+        });
+        if (isClosed)
+          bestCoords.push(bestCoords[0]);
+        for (i2 = 0; i2 < bestPoints.length; i2++) {
+          point2 = bestPoints[i2];
+          if (!geoVecEqual(originalPoints[i2].coord, point2.coord)) {
+            node = graph.entity(point2.id);
+            loc = projection2.invert(point2.coord);
+            graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
+          }
+        }
+        for (i2 = 0; i2 < straights.length; i2++) {
+          point2 = straights[i2];
+          if (nodeCount[point2.id] > 1)
+            continue;
+          node = graph.entity(point2.id);
+          if (t === 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);
+            if (choice) {
+              loc = projection2.invert(choice.target);
+              graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
+            }
+          }
         }
-        return numerals(value);
       }
-      format2.toString = function() {
-        return specifier + "";
-      };
-      return format2;
-    }
-    function formatPrefix2(specifier, value) {
-      var f2 = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)), e = Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3, k = Math.pow(10, -e), prefix = prefixes[8 + e / 3];
-      return function(value2) {
-        return f2(k * value2) + prefix;
-      };
+      return graph;
+      function clonePoints(array2) {
+        return array2.map(function(p) {
+          return { id: p.id, coord: [p.coord[0], p.coord[1]] };
+        });
+      }
+      function calcMotion(point3, i3, array2) {
+        if (!isClosed && (i3 === 0 || i3 === array2.length - 1))
+          return [0, 0];
+        if (nodeCount[array2[i3].id] > 1)
+          return [0, 0];
+        var a2 = array2[(i3 - 1 + array2.length) % array2.length].coord;
+        var origin = point3.coord;
+        var b2 = array2[(i3 + 1) % array2.length].coord;
+        var p = geoVecSubtract(a2, origin);
+        var q = geoVecSubtract(b2, origin);
+        var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
+        p = geoVecNormalize(p);
+        q = geoVecNormalize(q);
+        var dotp2 = p[0] * q[0] + p[1] * q[1];
+        var val = Math.abs(dotp2);
+        if (val < lowerThreshold) {
+          corner.i = i3;
+          corner.dotp = val;
+          var vec = geoVecNormalize(geoVecAdd(p, q));
+          return geoVecScale(vec, 0.1 * dotp2 * scale);
+        }
+        return [0, 0];
+      }
+    };
+    function nodeSubset(nodes, vertexID2, isClosed) {
+      var first = isClosed ? 0 : 1;
+      var last = isClosed ? nodes.length : nodes.length - 1;
+      for (var i2 = first; i2 < last; i2++) {
+        if (nodes[i2].id === vertexID2) {
+          return [
+            nodes[(i2 - 1 + nodes.length) % nodes.length],
+            nodes[i2],
+            nodes[(i2 + 1) % nodes.length]
+          ];
+        }
+      }
+      return [];
     }
-    return {
-      format: newFormat,
-      formatPrefix: formatPrefix2
+    action.disabled = function(graph) {
+      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();
+      var allowStraightAngles = false;
+      if (vertexID !== void 0) {
+        allowStraightAngles = true;
+        nodes = nodeSubset(nodes, vertexID, isClosed);
+        if (nodes.length !== 3)
+          return "end_vertex";
+      }
+      var coords = nodes.map(function(n2) {
+        return projection2(n2.loc);
+      });
+      var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon3, threshold, allowStraightAngles);
+      if (score === null) {
+        return "not_squarish";
+      } else if (score === 0) {
+        return "square_enough";
+      } else {
+        return false;
+      }
     };
+    action.transitionable = true;
+    return action;
   }
 
-  // node_modules/d3-format/src/defaultLocale.js
-  var locale;
-  var format;
-  var formatPrefix;
-  defaultLocale({
-    thousands: ",",
-    grouping: [3],
-    currency: ["$", ""]
-  });
-  function defaultLocale(definition) {
-    locale = locale_default(definition);
-    format = locale.format;
-    formatPrefix = locale.formatPrefix;
-    return locale;
+  // modules/actions/restrict_turn.js
+  function actionRestrictTurn(turn, restrictionType, restrictionID) {
+    return function(graph) {
+      var fromWay = graph.entity(turn.from.way);
+      var toWay = graph.entity(turn.to.way);
+      var viaNode = turn.via.node && graph.entity(turn.via.node);
+      var viaWays = turn.via.ways && turn.via.ways.map(function(id2) {
+        return graph.entity(id2);
+      });
+      var members = [];
+      members.push({ id: fromWay.id, type: "way", role: "from" });
+      if (viaNode) {
+        members.push({ id: viaNode.id, type: "node", role: "via" });
+      } else if (viaWays) {
+        viaWays.forEach(function(viaWay) {
+          members.push({ id: viaWay.id, type: "way", role: "via" });
+        });
+      }
+      members.push({ id: toWay.id, type: "way", role: "to" });
+      return graph.replace(osmRelation({
+        id: restrictionID,
+        tags: {
+          type: "restriction",
+          restriction: restrictionType
+        },
+        members
+      }));
+    };
   }
 
-  // node_modules/d3-format/src/precisionFixed.js
-  function precisionFixed_default(step) {
-    return Math.max(0, -exponent_default(Math.abs(step)));
+  // modules/actions/revert.js
+  function actionRevert(id2) {
+    var action = function(graph) {
+      var entity = graph.hasEntity(id2), base = graph.base().entities[id2];
+      if (entity && !base) {
+        if (entity.type === "node") {
+          graph.parentWays(entity).forEach(function(parent) {
+            parent = parent.removeNode(id2);
+            graph = graph.replace(parent);
+            if (parent.isDegenerate()) {
+              graph = actionDeleteWay(parent.id)(graph);
+            }
+          });
+        }
+        graph.parentRelations(entity).forEach(function(parent) {
+          parent = parent.removeMembersWithID(id2);
+          graph = graph.replace(parent);
+          if (parent.isDegenerate()) {
+            graph = actionDeleteRelation(parent.id)(graph);
+          }
+        });
+      }
+      return graph.revert(id2);
+    };
+    return action;
   }
 
-  // node_modules/d3-format/src/precisionPrefix.js
-  function precisionPrefix_default(step, value) {
-    return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3 - exponent_default(Math.abs(step)));
+  // modules/actions/rotate.js
+  function actionRotate(rotateIds, pivot, angle2, projection2) {
+    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)));
+        });
+      });
+    };
+    return action;
   }
 
-  // node_modules/d3-format/src/precisionRound.js
-  function precisionRound_default(step, max3) {
-    step = Math.abs(step), max3 = Math.abs(max3) - step;
-    return Math.max(0, exponent_default(max3) - exponent_default(step)) + 1;
+  // modules/actions/scale.js
+  function actionScale(ids, pivotLoc, scaleFactor, projection2) {
+    return function(graph) {
+      return graph.update(function(graph2) {
+        let point2, radial;
+        utilGetAllNodes(ids, graph2).forEach(function(node) {
+          point2 = projection2(node.loc);
+          radial = [
+            point2[0] - pivotLoc[0],
+            point2[1] - pivotLoc[1]
+          ];
+          point2 = [
+            pivotLoc[0] + scaleFactor * radial[0],
+            pivotLoc[1] + scaleFactor * radial[1]
+          ];
+          graph2 = graph2.replace(node.move(projection2.invert(point2)));
+        });
+      });
+    };
   }
 
-  // node_modules/d3-scale/src/tickFormat.js
-  function tickFormat(start2, stop, count, specifier) {
-    var step = tickStep(start2, stop, count), precision2;
-    specifier = formatSpecifier(specifier == null ? ",f" : specifier);
-    switch (specifier.type) {
-      case "s": {
-        var value = Math.max(Math.abs(start2), Math.abs(stop));
-        if (specifier.precision == null && !isNaN(precision2 = precisionPrefix_default(step, value)))
-          specifier.precision = precision2;
-        return formatPrefix(specifier, value);
-      }
-      case "":
-      case "e":
-      case "g":
-      case "p":
-      case "r": {
-        if (specifier.precision == null && !isNaN(precision2 = precisionRound_default(step, Math.max(Math.abs(start2), Math.abs(stop)))))
-          specifier.precision = precision2 - (specifier.type === "e");
-        break;
-      }
-      case "f":
-      case "%": {
-        if (specifier.precision == null && !isNaN(precision2 = precisionFixed_default(step)))
-          specifier.precision = precision2 - (specifier.type === "%") * 2;
-        break;
+  // modules/actions/straighten_nodes.js
+  function actionStraightenNodes(nodeIDs, projection2) {
+    function positionAlongWay(a, o, b) {
+      return geoVecDot(a, b, o) / geoVecDot(b, b, o);
+    }
+    function getEndpoints(points) {
+      var ssr = geoGetSmallestSurroundingRectangle(points);
+      var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
+      var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
+      var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
+      var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
+      var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
+      if (isLong) {
+        return [p1, q1];
       }
+      return [p2, q2];
     }
-    return format(specifier);
-  }
-
-  // node_modules/d3-scale/src/linear.js
-  function linearish(scale) {
-    var domain2 = scale.domain;
-    scale.ticks = function(count) {
-      var d = domain2();
-      return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
-    };
-    scale.tickFormat = function(count, specifier) {
-      var d = domain2();
-      return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
-    };
-    scale.nice = function(count) {
-      if (count == null)
-        count = 10;
-      var d = domain2();
-      var i0 = 0;
-      var i1 = d.length - 1;
-      var start2 = d[i0];
-      var stop = d[i1];
-      var prestep;
-      var step;
-      var maxIter = 10;
-      if (stop < start2) {
-        step = start2, start2 = stop, stop = step;
-        step = i0, i0 = i1, i1 = step;
+    var action = function(graph, t) {
+      if (t === null || !isFinite(t))
+        t = 1;
+      t = Math.min(Math.max(+t, 0), 1);
+      var nodes = nodeIDs.map(function(id2) {
+        return graph.entity(id2);
+      });
+      var points = nodes.map(function(n2) {
+        return projection2(n2.loc);
+      });
+      var endpoints = getEndpoints(points);
+      var startPoint = endpoints[0];
+      var endPoint = endpoints[1];
+      for (var i2 = 0; i2 < points.length; i2++) {
+        var node = nodes[i2];
+        var point2 = points[i2];
+        var u = positionAlongWay(point2, startPoint, endPoint);
+        var point22 = geoVecInterp(startPoint, endPoint, u);
+        var loc2 = projection2.invert(point22);
+        graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
       }
-      while (maxIter-- > 0) {
-        step = tickIncrement(start2, stop, count);
-        if (step === prestep) {
-          d[i0] = start2;
-          d[i1] = stop;
-          return domain2(d);
-        } else if (step > 0) {
-          start2 = Math.floor(start2 / step) * step;
-          stop = Math.ceil(stop / step) * step;
-        } else if (step < 0) {
-          start2 = Math.ceil(start2 * step) / step;
-          stop = Math.floor(stop * step) / step;
-        } else {
-          break;
+      return graph;
+    };
+    action.disabled = function(graph) {
+      var nodes = nodeIDs.map(function(id2) {
+        return graph.entity(id2);
+      });
+      var points = nodes.map(function(n2) {
+        return projection2(n2.loc);
+      });
+      var endpoints = getEndpoints(points);
+      var startPoint = endpoints[0];
+      var endPoint = endpoints[1];
+      var maxDistance = 0;
+      for (var i2 = 0; i2 < points.length; i2++) {
+        var point2 = points[i2];
+        var u = positionAlongWay(point2, startPoint, endPoint);
+        var p = geoVecInterp(startPoint, endPoint, u);
+        var dist = geoVecLength(p, point2);
+        if (!isNaN(dist) && dist > maxDistance) {
+          maxDistance = dist;
         }
-        prestep = step;
       }
-      return scale;
-    };
-    return scale;
-  }
-  function linear3() {
-    var scale = continuous();
-    scale.copy = function() {
-      return copy(scale, linear3());
+      if (maxDistance < 1e-4) {
+        return "straight_enough";
+      }
     };
-    initRange.apply(scale, arguments);
-    return linearish(scale);
+    action.transitionable = true;
+    return action;
   }
 
-  // node_modules/d3-scale/src/quantize.js
-  function quantize() {
-    var x05 = 0, x12 = 1, n2 = 1, domain2 = [0.5], range3 = [0, 1], unknown;
-    function scale(x) {
-      return x != null && x <= x ? range3[bisect_default(domain2, x, 0, n2)] : unknown;
-    }
-    function rescale() {
-      var i2 = -1;
-      domain2 = new Array(n2);
-      while (++i2 < n2)
-        domain2[i2] = ((i2 + 1) * x12 - (i2 - n2) * x05) / (n2 + 1);
-      return scale;
+  // modules/actions/straighten_way.js
+  function actionStraightenWay(selectedIDs, projection2) {
+    function positionAlongWay(a, o, b) {
+      return geoVecDot(a, b, o) / geoVecDot(b, b, o);
     }
-    scale.domain = function(_) {
-      return arguments.length ? ([x05, x12] = _, x05 = +x05, x12 = +x12, rescale()) : [x05, x12];
-    };
-    scale.range = function(_) {
-      return arguments.length ? (n2 = (range3 = Array.from(_)).length - 1, rescale()) : range3.slice();
-    };
-    scale.invertExtent = function(y) {
-      var i2 = range3.indexOf(y);
-      return i2 < 0 ? [NaN, NaN] : i2 < 1 ? [x05, domain2[0]] : i2 >= n2 ? [domain2[n2 - 1], x12] : [domain2[i2 - 1], domain2[i2]];
-    };
-    scale.unknown = function(_) {
-      return arguments.length ? (unknown = _, scale) : scale;
-    };
-    scale.thresholds = function() {
-      return domain2.slice();
-    };
-    scale.copy = function() {
-      return quantize().domain([x05, x12]).range(range3).unknown(unknown);
-    };
-    return initRange.apply(linearish(scale), arguments);
-  }
-
-  // modules/behavior/breathe.js
-  function behaviorBreathe() {
-    var duration = 800;
-    var steps = 4;
-    var selector = ".selected.shadow, .selected .shadow";
-    var _selected = select_default2(null);
-    var _classed = "";
-    var _params = {};
-    var _done = false;
-    var _timer;
-    function ratchetyInterpolator(a, b, steps2, units) {
-      a = parseFloat(a);
-      b = parseFloat(b);
-      var sample = quantize().domain([0, 1]).range(quantize_default(number_default(a, b), steps2));
-      return function(t) {
-        return String(sample(t)) + (units || "");
+    function allNodes(graph) {
+      var nodes = [];
+      var startNodes = [];
+      var endNodes = [];
+      var remainingWays = [];
+      var selectedWays = selectedIDs.filter(function(w) {
+        return graph.entity(w).type === "way";
+      });
+      var selectedNodes = selectedIDs.filter(function(n2) {
+        return graph.entity(n2).type === "node";
+      });
+      for (var i2 = 0; i2 < selectedWays.length; i2++) {
+        var way = graph.entity(selectedWays[i2]);
+        nodes = way.nodes.slice(0);
+        remainingWays.push(nodes);
+        startNodes.push(nodes[0]);
+        endNodes.push(nodes[nodes.length - 1]);
+      }
+      startNodes = startNodes.filter(function(n2) {
+        return startNodes.indexOf(n2) === startNodes.lastIndexOf(n2);
+      });
+      endNodes = endNodes.filter(function(n2) {
+        return endNodes.indexOf(n2) === endNodes.lastIndexOf(n2);
+      });
+      var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
+      var nextWay = [];
+      nodes = [];
+      var getNextWay = function(currNode2, remainingWays2) {
+        return remainingWays2.filter(function(way2) {
+          return way2[0] === currNode2 || way2[way2.length - 1] === currNode2;
+        })[0];
       };
+      while (remainingWays.length) {
+        nextWay = getNextWay(currNode, remainingWays);
+        remainingWays = utilArrayDifference(remainingWays, [nextWay]);
+        if (nextWay[0] !== currNode) {
+          nextWay.reverse();
+        }
+        nodes = nodes.concat(nextWay);
+        currNode = nodes[nodes.length - 1];
+      }
+      if (selectedNodes.length === 2) {
+        var startNodeIdx = nodes.indexOf(selectedNodes[0]);
+        var endNodeIdx = nodes.indexOf(selectedNodes[1]);
+        var sortedStartEnd = [startNodeIdx, endNodeIdx];
+        sortedStartEnd.sort(function(a, b) {
+          return a - b;
+        });
+        nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
+      }
+      return nodes.map(function(n2) {
+        return graph.entity(n2);
+      });
     }
-    function reset(selection2) {
-      selection2.style("stroke-opacity", null).style("stroke-width", null).style("fill-opacity", null).style("r", null);
+    function shouldKeepNode(node, graph) {
+      return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
     }
-    function setAnimationParams(transition2, fromTo) {
-      var toFrom = fromTo === "from" ? "to" : "from";
-      transition2.styleTween("stroke-opacity", function(d) {
-        return ratchetyInterpolator(
-          _params[d.id][toFrom].opacity,
-          _params[d.id][fromTo].opacity,
-          steps
-        );
-      }).styleTween("stroke-width", function(d) {
-        return ratchetyInterpolator(
-          _params[d.id][toFrom].width,
-          _params[d.id][fromTo].width,
-          steps,
-          "px"
-        );
-      }).styleTween("fill-opacity", function(d) {
-        return ratchetyInterpolator(
-          _params[d.id][toFrom].opacity,
-          _params[d.id][fromTo].opacity,
-          steps
-        );
-      }).styleTween("r", function(d) {
-        return ratchetyInterpolator(
-          _params[d.id][toFrom].width,
-          _params[d.id][fromTo].width,
-          steps,
-          "px"
-        );
+    var action = function(graph, t) {
+      if (t === null || !isFinite(t))
+        t = 1;
+      t = Math.min(Math.max(+t, 0), 1);
+      var nodes = allNodes(graph);
+      var points = nodes.map(function(n2) {
+        return projection2(n2.loc);
       });
-    }
-    function calcAnimationParams(selection2) {
-      selection2.call(reset).each(function(d) {
-        var s = select_default2(this);
-        var tag = s.node().tagName;
-        var p = { "from": {}, "to": {} };
-        var opacity;
-        var width;
-        if (tag === "circle") {
-          opacity = parseFloat(s.style("fill-opacity") || 0.5);
-          width = parseFloat(s.style("r") || 15.5);
+      var startPoint = points[0];
+      var endPoint = points[points.length - 1];
+      var toDelete = [];
+      var i2;
+      for (i2 = 1; i2 < points.length - 1; i2++) {
+        var node = nodes[i2];
+        var point2 = points[i2];
+        if (t < 1 || shouldKeepNode(node, graph)) {
+          var u = positionAlongWay(point2, startPoint, endPoint);
+          var p = geoVecInterp(startPoint, endPoint, u);
+          var loc2 = projection2.invert(p);
+          graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
         } else {
-          opacity = parseFloat(s.style("stroke-opacity") || 0.7);
-          width = parseFloat(s.style("stroke-width") || 10);
+          if (toDelete.indexOf(node) === -1) {
+            toDelete.push(node);
+          }
         }
-        p.tag = tag;
-        p.from.opacity = opacity * 0.6;
-        p.to.opacity = opacity * 1.25;
-        p.from.width = width * 0.7;
-        p.to.width = width * (tag === "circle" ? 1.5 : 1);
-        _params[d.id] = p;
-      });
-    }
-    function run(surface, fromTo) {
-      var toFrom = fromTo === "from" ? "to" : "from";
-      var currSelected = surface.selectAll(selector);
-      var currClassed = surface.attr("class");
-      if (_done || currSelected.empty()) {
-        _selected.call(reset);
-        _selected = select_default2(null);
-        return;
       }
-      if (!(0, import_fast_deep_equal2.default)(currSelected.data(), _selected.data()) || currClassed !== _classed) {
-        _selected.call(reset);
-        _classed = currClassed;
-        _selected = currSelected.call(calcAnimationParams);
+      for (i2 = 0; i2 < toDelete.length; i2++) {
+        graph = actionDeleteNode(toDelete[i2].id)(graph);
       }
-      var didCallNextRun = false;
-      _selected.transition().duration(duration).call(setAnimationParams, fromTo).on("end", function() {
-        if (!didCallNextRun) {
-          surface.call(run, toFrom);
-          didCallNextRun = true;
-        }
-        if (!select_default2(this).classed("selected")) {
-          reset(select_default2(this));
-        }
+      return graph;
+    };
+    action.disabled = function(graph) {
+      var nodes = allNodes(graph);
+      var points = nodes.map(function(n2) {
+        return projection2(n2.loc);
       });
-    }
-    function behavior(surface) {
-      _done = false;
-      _timer = timer(function() {
-        if (surface.selectAll(selector).empty()) {
-          return false;
-        }
-        surface.call(run, "from");
-        _timer.stop();
-        return true;
-      }, 20);
-    }
-    behavior.restartIfNeeded = function(surface) {
-      if (_selected.empty()) {
-        surface.call(run, "from");
-        if (_timer) {
-          _timer.stop();
+      var startPoint = points[0];
+      var endPoint = points[points.length - 1];
+      var threshold = 0.2 * geoVecLength(startPoint, endPoint);
+      var i2;
+      if (threshold === 0) {
+        return "too_bendy";
+      }
+      var maxDistance = 0;
+      for (i2 = 1; i2 < points.length - 1; i2++) {
+        var point2 = points[i2];
+        var u = positionAlongWay(point2, startPoint, endPoint);
+        var p = geoVecInterp(startPoint, endPoint, u);
+        var dist = geoVecLength(p, point2);
+        if (isNaN(dist) || dist > threshold) {
+          return "too_bendy";
+        } else if (dist > maxDistance) {
+          maxDistance = dist;
         }
       }
-    };
-    behavior.off = function() {
-      _done = true;
-      if (_timer) {
-        _timer.stop();
+      var keepingAllNodes = nodes.every(function(node, i3) {
+        return i3 === 0 || i3 === nodes.length - 1 || shouldKeepNode(node, graph);
+      });
+      if (maxDistance < 1e-4 && // Allow straightening even if already straight in order to remove extraneous nodes
+      keepingAllNodes) {
+        return "straight_enough";
       }
-      _selected.interrupt().call(reset);
     };
-    return behavior;
+    action.transitionable = true;
+    return action;
   }
 
-  // modules/behavior/operation.js
-  function behaviorOperation(context) {
-    var _operation;
-    function keypress(d3_event) {
-      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())();
+  // modules/actions/unrestrict_turn.js
+  function actionUnrestrictTurn(turn) {
+    return function(graph) {
+      return actionDeleteRelation(turn.restrictionID)(graph);
+    };
+  }
+
+  // modules/actions/reflect.js
+  function actionReflect(reflectIds, projection2) {
+    var _useLongAxis = true;
+    var action = function(graph, t) {
+      if (t === null || !isFinite(t))
+        t = 1;
+      t = Math.min(Math.max(+t, 0), 1);
+      var nodes = utilGetAllNodes(reflectIds, graph);
+      var points = nodes.map(function(n2) {
+        return projection2(n2.loc);
+      });
+      var ssr = geoGetSmallestSurroundingRectangle(points);
+      var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
+      var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
+      var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
+      var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
+      var p, q;
+      var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
+      if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
+        p = p1;
+        q = q1;
       } else {
-        context.ui().flash.duration(2e3).iconName("#iD-operation-" + _operation.id).iconClass("operation").label(_operation.annotation() || _operation.title)();
-        if (_operation.point)
-          _operation.point(null);
-        _operation();
+        p = p2;
+        q = q2;
       }
-    }
-    function behavior() {
-      if (_operation && _operation.available()) {
-        context.keybinding().on(_operation.keys, keypress);
+      var dx = q[0] - p[0];
+      var dy = q[1] - p[1];
+      var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
+      var b = 2 * dx * dy / (dx * dx + dy * dy);
+      for (var i2 = 0; i2 < nodes.length; i2++) {
+        var node = nodes[i2];
+        var c = projection2(node.loc);
+        var c2 = [
+          a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
+          b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
+        ];
+        var loc2 = projection2.invert(c2);
+        node = node.move(geoVecInterp(node.loc, loc2, t));
+        graph = graph.replace(node);
       }
-      return behavior;
-    }
-    behavior.off = function() {
-      context.keybinding().off(_operation.keys);
+      return graph;
     };
-    behavior.which = function(_) {
+    action.useLongAxis = function(val) {
       if (!arguments.length)
-        return _operation;
-      _operation = _;
-      return behavior;
+        return _useLongAxis;
+      _useLongAxis = val;
+      return action;
     };
-    return behavior;
+    action.transitionable = true;
+    return action;
   }
 
-  // modules/operations/circularize.js
-  function operationCircularize(context, selectedIDs) {
-    var _extent;
-    var _actions = selectedIDs.map(getAction).filter(Boolean);
-    var _amount = _actions.length === 1 ? "single" : "multiple";
-    var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function(n2) {
-      return n2.loc;
-    });
-    function getAction(entityID) {
-      var entity = context.entity(entityID);
-      if (entity.type !== "way" || new Set(entity.nodes).size <= 1)
-        return null;
-      if (!_extent) {
-        _extent = entity.extent(context.graph());
-      } else {
-        _extent = _extent.extend(entity.extent(context.graph()));
-      }
-      return actionCircularize(entityID, context.projection);
-    }
-    var operation = function() {
-      if (!_actions.length)
-        return;
-      var combinedAction = function(graph, t) {
-        _actions.forEach(function(action) {
-          if (!action.disabled(graph)) {
-            graph = action(graph, t);
+  // modules/actions/upgrade_tags.js
+  function actionUpgradeTags(entityId, oldTags, replaceTags) {
+    return function(graph) {
+      var entity = graph.entity(entityId);
+      var tags = Object.assign({}, entity.tags);
+      var transferValue;
+      var semiIndex;
+      for (var oldTagKey in oldTags) {
+        if (!(oldTagKey in tags))
+          continue;
+        if (oldTags[oldTagKey] === "*") {
+          transferValue = tags[oldTagKey];
+          delete tags[oldTagKey];
+        } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
+          delete tags[oldTagKey];
+        } else {
+          var vals = tags[oldTagKey].split(";").filter(Boolean);
+          var oldIndex = vals.indexOf(oldTags[oldTagKey]);
+          if (vals.length === 1 || oldIndex === -1) {
+            delete tags[oldTagKey];
+          } else {
+            if (replaceTags && replaceTags[oldTagKey]) {
+              semiIndex = oldIndex;
+            }
+            vals.splice(oldIndex, 1);
+            tags[oldTagKey] = vals.join(";");
           }
-        });
-        return graph;
-      };
-      combinedAction.transitionable = true;
-      context.perform(combinedAction, operation.annotation());
-      window.setTimeout(function() {
-        context.validator().validate();
-      }, 300);
-    };
-    operation.available = function() {
-      return _actions.length && selectedIDs.length === _actions.length;
-    };
-    operation.disabled = function() {
-      if (!_actions.length)
-        return "";
-      var actionDisableds = _actions.map(function(action) {
-        return action.disabled(context.graph());
-      }).filter(Boolean);
-      if (actionDisableds.length === _actions.length) {
-        if (new Set(actionDisableds).size > 1) {
-          return "multiple_blockers";
         }
-        return actionDisableds[0];
-      } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
-        return "too_large";
-      } else if (someMissing()) {
-        return "not_downloaded";
-      } else if (selectedIDs.some(context.hasHiddenConnections)) {
-        return "connected_to_hidden";
       }
-      return false;
-      function someMissing() {
-        if (context.inIntro())
-          return false;
-        var osm = context.connection();
-        if (osm) {
-          var missing = _coords.filter(function(loc) {
-            return !osm.isDataLoaded(loc);
-          });
-          if (missing.length) {
-            missing.forEach(function(loc) {
-              context.loadTileAtLoc(loc);
-            });
-            return true;
+      if (replaceTags) {
+        for (var replaceKey in replaceTags) {
+          var replaceValue = replaceTags[replaceKey];
+          if (replaceValue === "*") {
+            if (tags[replaceKey] && tags[replaceKey] !== "no") {
+              continue;
+            } else {
+              tags[replaceKey] = "yes";
+            }
+          } else if (replaceValue === "$1") {
+            tags[replaceKey] = transferValue;
+          } else {
+            if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== void 0) {
+              var existingVals = tags[replaceKey].split(";").filter(Boolean);
+              if (existingVals.indexOf(replaceValue) === -1) {
+                existingVals.splice(semiIndex, 0, replaceValue);
+                tags[replaceKey] = existingVals.join(";");
+              }
+            } else {
+              tags[replaceKey] = replaceValue;
+            }
           }
         }
-        return false;
       }
+      return graph.replace(entity.update({ tags }));
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
-      return disable ? _t.append("operations.circularize." + disable + "." + _amount) : _t.append("operations.circularize.description." + _amount);
-    };
-    operation.annotation = function() {
-      return _t("operations.circularize.annotation.feature", { n: _actions.length });
-    };
-    operation.id = "circularize";
-    operation.keys = [_t("operations.circularize.key")];
-    operation.title = _t.append("operations.circularize.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
   }
 
-  // modules/ui/cmd.js
-  var uiCmd = function(code) {
-    var detected = utilDetect();
-    if (detected.os === "mac") {
-      return code;
-    }
-    if (detected.os === "win") {
-      if (code === "\u2318\u21E7Z")
-        return "Ctrl+Y";
+  // modules/behavior/edit.js
+  function behaviorEdit(context) {
+    function behavior() {
+      context.map().minzoom(context.minEditableZoom());
     }
-    var result = "", replacements = {
-      "\u2318": "Ctrl",
-      "\u21E7": "Shift",
-      "\u2325": "Alt",
-      "\u232B": "Backspace",
-      "\u2326": "Delete"
+    behavior.off = function() {
+      context.map().minzoom(0);
     };
-    for (var i2 = 0; i2 < code.length; i2++) {
-      if (code[i2] in replacements) {
-        result += replacements[code[i2]] + (i2 < code.length - 1 ? "+" : "");
-      } else {
-        result += code[i2];
+    return behavior;
+  }
+
+  // modules/behavior/hover.js
+  function behaviorHover(context) {
+    var dispatch10 = dispatch_default("hover");
+    var _selection = select_default2(null);
+    var _newNodeId = null;
+    var _initialNodeID = null;
+    var _altDisables;
+    var _ignoreVertex;
+    var _targets = [];
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function keydown(d3_event) {
+      if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
+        _selection.selectAll(".hover").classed("hover-suppressed", true).classed("hover", false);
+        _selection.classed("hover-disabled", true);
+        dispatch10.call("hover", this, null);
       }
     }
-    return result;
-  };
-  uiCmd.display = function(code) {
-    if (code.length !== 1)
-      return code;
-    var detected = utilDetect();
-    var mac = detected.os === "mac";
-    var replacements = {
-      "\u2318": mac ? "\u2318 " + _t("shortcuts.key.cmd") : _t("shortcuts.key.ctrl"),
-      "\u21E7": mac ? "\u21E7 " + _t("shortcuts.key.shift") : _t("shortcuts.key.shift"),
-      "\u2325": mac ? "\u2325 " + _t("shortcuts.key.option") : _t("shortcuts.key.alt"),
-      "\u2303": mac ? "\u2303 " + _t("shortcuts.key.ctrl") : _t("shortcuts.key.ctrl"),
-      "\u232B": mac ? "\u232B " + _t("shortcuts.key.delete") : _t("shortcuts.key.backspace"),
-      "\u2326": mac ? "\u2326 " + _t("shortcuts.key.del") : _t("shortcuts.key.del"),
-      "\u2196": mac ? "\u2196 " + _t("shortcuts.key.pgup") : _t("shortcuts.key.pgup"),
-      "\u2198": mac ? "\u2198 " + _t("shortcuts.key.pgdn") : _t("shortcuts.key.pgdn"),
-      "\u21DE": mac ? "\u21DE " + _t("shortcuts.key.home") : _t("shortcuts.key.home"),
-      "\u21DF": mac ? "\u21DF " + _t("shortcuts.key.end") : _t("shortcuts.key.end"),
-      "\u21B5": mac ? "\u23CE " + _t("shortcuts.key.return") : _t("shortcuts.key.enter"),
-      "\u238B": mac ? "\u238B " + _t("shortcuts.key.esc") : _t("shortcuts.key.esc"),
-      "\u2630": mac ? "\u2630 " + _t("shortcuts.key.menu") : _t("shortcuts.key.menu")
-    };
-    return replacements[code] || code;
-  };
-
-  // modules/operations/delete.js
-  function operationDelete(context, selectedIDs) {
-    var multi = selectedIDs.length === 1 ? "single" : "multiple";
-    var action = actionDeleteMultiple(selectedIDs);
-    var nodes = utilGetAllNodes(selectedIDs, context.graph());
-    var coords = nodes.map(function(n2) {
-      return n2.loc;
-    });
-    var extent = utilTotalExtent(selectedIDs, context.graph());
-    var operation = function() {
-      var nextSelectedID;
-      var nextSelectedLoc;
-      if (selectedIDs.length === 1) {
-        var id2 = selectedIDs[0];
-        var entity = context.entity(id2);
-        var geometry = entity.geometry(context.graph());
-        var parents = context.graph().parentWays(entity);
-        var parent = parents[0];
-        if (geometry === "vertex") {
-          var nodes2 = parent.nodes;
-          var i2 = nodes2.indexOf(id2);
-          if (i2 === 0) {
-            i2++;
-          } else if (i2 === nodes2.length - 1) {
-            i2--;
-          } else {
-            var a = geoSphericalDistance(entity.loc, context.entity(nodes2[i2 - 1]).loc);
-            var b = geoSphericalDistance(entity.loc, context.entity(nodes2[i2 + 1]).loc);
-            i2 = a < b ? i2 - 1 : i2 + 1;
-          }
-          nextSelectedID = nodes2[i2];
-          nextSelectedLoc = context.entity(nextSelectedID).loc;
-        }
+    function keyup(d3_event) {
+      if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
+        _selection.selectAll(".hover-suppressed").classed("hover-suppressed", false).classed("hover", true);
+        _selection.classed("hover-disabled", false);
+        dispatch10.call("hover", this, _targets);
       }
-      context.perform(action, operation.annotation());
-      context.validator().validate();
-      if (nextSelectedID && nextSelectedLoc) {
-        if (context.hasEntity(nextSelectedID)) {
-          context.enter(modeSelect(context, [nextSelectedID]).follow(true));
-        } else {
-          context.map().centerEase(nextSelectedLoc);
-          context.enter(modeBrowse(context));
-        }
+    }
+    function behavior(selection2) {
+      _selection = selection2;
+      _targets = [];
+      if (_initialNodeID) {
+        _newNodeId = _initialNodeID;
+        _initialNodeID = null;
       } else {
-        context.enter(modeBrowse(context));
+        _newNodeId = null;
       }
-    };
-    operation.available = function() {
-      return true;
-    };
-    operation.disabled = function() {
-      if (extent.percentContainedIn(context.map().extent()) < 0.8) {
-        return "too_large";
-      } else if (someMissing()) {
-        return "not_downloaded";
-      } else if (selectedIDs.some(context.hasHiddenConnections)) {
-        return "connected_to_hidden";
-      } else if (selectedIDs.some(protectedMember)) {
-        return "part_of_relation";
-      } else if (selectedIDs.some(incompleteRelation)) {
-        return "incomplete_relation";
-      } else if (selectedIDs.some(hasWikidataTag)) {
-        return "has_wikidata_tag";
+      _selection.on(_pointerPrefix + "over.hover", pointerover).on(_pointerPrefix + "out.hover", pointerout).on(_pointerPrefix + "down.hover", pointerover);
+      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 (!(datum2 instanceof osmEntity) && datum2.properties && datum2.properties.entity instanceof osmEntity) {
+          return datum2.properties.entity;
+        }
+        return datum2;
       }
-      return false;
-      function someMissing() {
-        if (context.inIntro())
-          return false;
-        var osm = context.connection();
-        if (osm) {
-          var missing = coords.filter(function(loc) {
-            return !osm.isDataLoaded(loc);
-          });
-          if (missing.length) {
-            missing.forEach(function(loc) {
-              context.loadTileAtLoc(loc);
-            });
-            return true;
-          }
+      function pointerover(d3_event) {
+        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);
+          updateHover(d3_event, _targets);
         }
-        return false;
       }
-      function hasWikidataTag(id2) {
-        var entity = context.entity(id2);
-        return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
+      function pointerout(d3_event) {
+        var target = eventTarget(d3_event);
+        var index = _targets.indexOf(target);
+        if (index !== -1) {
+          _targets.splice(index);
+          updateHover(d3_event, _targets);
+        }
       }
-      function incompleteRelation(id2) {
-        var entity = context.entity(id2);
-        return entity.type === "relation" && !entity.isComplete(context.graph());
+      function allowsVertex(d) {
+        return d.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d, context.graph());
       }
-      function protectedMember(id2) {
-        var entity = context.entity(id2);
-        if (entity.type !== "way")
-          return false;
-        var parents = context.graph().parentRelations(entity);
-        for (var i2 = 0; i2 < parents.length; i2++) {
-          var parent = parents[i2];
-          var type3 = parent.tags.type;
-          var role = parent.memberById(id2).role || "outer";
-          if (type3 === "route" || type3 === "boundary" || type3 === "multipolygon" && role === "outer") {
-            return true;
+      function modeAllowsHover(target) {
+        var mode = context.mode();
+        if (mode.id === "add-point") {
+          return mode.preset.matchGeometry("vertex") || target.type !== "way" && target.geometry(context.graph()) !== "vertex";
+        }
+        return true;
+      }
+      function updateHover(d3_event, targets) {
+        _selection.selectAll(".hover").classed("hover", false);
+        _selection.selectAll(".hover-suppressed").classed("hover-suppressed", false);
+        var mode = context.mode();
+        if (!_newNodeId && (mode.id === "draw-line" || mode.id === "draw-area")) {
+          var node = targets.find(function(target) {
+            return target instanceof osmEntity && target.type === "node";
+          });
+          _newNodeId = node && node.id;
+        }
+        targets = targets.filter(function(datum3) {
+          if (datum3 instanceof osmEntity) {
+            return datum3.id !== _newNodeId && (datum3.type !== "node" || !_ignoreVertex || allowsVertex(datum3)) && modeAllowsHover(datum3);
+          }
+          return true;
+        });
+        var selector = "";
+        for (var i2 in targets) {
+          var datum2 = targets[i2];
+          if (datum2.__featurehash__) {
+            selector += ", .data" + datum2.__featurehash__;
+          } else if (datum2 instanceof QAItem) {
+            selector += ", ." + datum2.service + ".itemId-" + datum2.id;
+          } else if (datum2 instanceof osmNote) {
+            selector += ", .note-" + datum2.id;
+          } else if (datum2 instanceof osmEntity) {
+            selector += ", ." + datum2.id;
+            if (datum2.type === "relation") {
+              for (var j2 in datum2.members) {
+                selector += ", ." + datum2.members[j2].id;
+              }
+            }
           }
         }
-        return false;
+        var suppressed = _altDisables && d3_event && d3_event.altKey;
+        if (selector.trim().length) {
+          selector = selector.slice(1);
+          _selection.selectAll(selector).classed(suppressed ? "hover-suppressed" : "hover", true);
+        }
+        dispatch10.call("hover", this, !suppressed && targets);
       }
+    }
+    behavior.off = function(selection2) {
+      selection2.selectAll(".hover").classed("hover", false);
+      selection2.selectAll(".hover-suppressed").classed("hover-suppressed", false);
+      selection2.classed("hover-disabled", false);
+      selection2.on(_pointerPrefix + "over.hover", null).on(_pointerPrefix + "out.hover", null).on(_pointerPrefix + "down.hover", null);
+      select_default2(window).on(_pointerPrefix + "up.hover pointercancel.hover", null, true).on("keydown.hover", null).on("keyup.hover", null);
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
-      return disable ? _t.append("operations.delete." + disable + "." + multi) : _t.append("operations.delete.description." + multi);
+    behavior.altDisables = function(val) {
+      if (!arguments.length)
+        return _altDisables;
+      _altDisables = val;
+      return behavior;
     };
-    operation.annotation = function() {
-      return selectedIDs.length === 1 ? _t("operations.delete.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.delete.annotation.feature", { n: selectedIDs.length });
+    behavior.ignoreVertex = function(val) {
+      if (!arguments.length)
+        return _ignoreVertex;
+      _ignoreVertex = val;
+      return behavior;
     };
-    operation.id = "delete";
-    operation.keys = [uiCmd("\u2318\u232B"), uiCmd("\u2318\u2326"), uiCmd("\u2326")];
-    operation.title = _t.append("operations.delete.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    behavior.initialNodeID = function(nodeId) {
+      _initialNodeID = nodeId;
+      return behavior;
+    };
+    return utilRebind(behavior, dispatch10, "on");
   }
 
-  // modules/operations/orthogonalize.js
-  function operationOrthogonalize(context, selectedIDs) {
-    var _extent;
-    var _type;
-    var _actions = selectedIDs.map(chooseAction).filter(Boolean);
-    var _amount = _actions.length === 1 ? "single" : "multiple";
-    var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function(n2) {
-      return n2.loc;
-    });
-    function chooseAction(entityID) {
-      var entity = context.entity(entityID);
-      var geometry = entity.geometry(context.graph());
-      if (!_extent) {
-        _extent = entity.extent(context.graph());
+  // modules/behavior/draw.js
+  var _disableSpace = false;
+  var _lastSpace = null;
+  function behaviorDraw(context) {
+    var dispatch10 = dispatch_default(
+      "move",
+      "down",
+      "downcancel",
+      "click",
+      "clickWay",
+      "clickNode",
+      "undo",
+      "cancel",
+      "finish"
+    );
+    var keybinding = utilKeybinding("draw");
+    var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on("hover", context.ui().sidebar.hover);
+    var _edit = behaviorEdit(context);
+    var _closeTolerance = 4;
+    var _tolerance = 12;
+    var _mouseLeave = false;
+    var _lastMouse = null;
+    var _lastPointerUpEvent;
+    var _downPointer;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function datum2(d3_event) {
+      var mode = context.mode();
+      var isNote = mode && mode.id.indexOf("note") !== -1;
+      if (d3_event.altKey || isNote)
+        return {};
+      var element;
+      if (d3_event.type === "keydown") {
+        element = _lastMouse && _lastMouse.target;
       } else {
-        _extent = _extent.extend(entity.extent(context.graph()));
+        element = d3_event.target;
       }
-      if (entity.type === "way" && new Set(entity.nodes).size > 2) {
-        if (_type && _type !== "feature")
-          return null;
-        _type = "feature";
-        return actionOrthogonalize(entityID, context.projection);
-      } else if (geometry === "vertex") {
-        if (_type && _type !== "corner")
-          return null;
-        _type = "corner";
-        var graph = context.graph();
-        var parents = graph.parentWays(entity);
-        if (parents.length === 1) {
-          var way = parents[0];
-          if (way.nodes.indexOf(entityID) !== -1) {
-            return actionOrthogonalize(way.id, context.projection, entityID);
-          }
+      var d = element.__data__;
+      return d && d.properties && d.properties.target ? d : {};
+    }
+    function pointerdown(d3_event) {
+      if (_downPointer)
+        return;
+      var pointerLocGetter = utilFastMouse(this);
+      _downPointer = {
+        id: d3_event.pointerId || "mouse",
+        pointerLocGetter,
+        downTime: +/* @__PURE__ */ new Date(),
+        downLoc: pointerLocGetter(d3_event)
+      };
+      dispatch10.call("down", this, d3_event, datum2(d3_event));
+    }
+    function pointerup(d3_event) {
+      if (!_downPointer || _downPointer.id !== (d3_event.pointerId || "mouse"))
+        return;
+      var downPointer = _downPointer;
+      _downPointer = null;
+      _lastPointerUpEvent = d3_event;
+      if (downPointer.isCancelled)
+        return;
+      var t2 = +/* @__PURE__ */ new Date();
+      var p2 = downPointer.pointerLocGetter(d3_event);
+      var dist = geoVecLength(downPointer.downLoc, p2);
+      if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
+        select_default2(window).on("click.draw-block", function() {
+          d3_event.stopPropagation();
+        }, true);
+        context.map().dblclickZoomEnable(false);
+        window.setTimeout(function() {
+          context.map().dblclickZoomEnable(true);
+          select_default2(window).on("click.draw-block", null);
+        }, 500);
+        click(d3_event, p2);
+      }
+    }
+    function pointermove(d3_event) {
+      if (_downPointer && _downPointer.id === (d3_event.pointerId || "mouse") && !_downPointer.isCancelled) {
+        var p2 = _downPointer.pointerLocGetter(d3_event);
+        var dist = geoVecLength(_downPointer.downLoc, p2);
+        if (dist >= _closeTolerance) {
+          _downPointer.isCancelled = true;
+          dispatch10.call("downcancel", this);
         }
       }
-      return null;
+      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;
+      dispatch10.call("move", this, d3_event, datum2(d3_event));
     }
-    var operation = function() {
-      if (!_actions.length)
+    function pointercancel(d3_event) {
+      if (_downPointer && _downPointer.id === (d3_event.pointerId || "mouse")) {
+        if (!_downPointer.isCancelled) {
+          dispatch10.call("downcancel", this);
+        }
+        _downPointer = null;
+      }
+    }
+    function mouseenter() {
+      _mouseLeave = false;
+    }
+    function mouseleave() {
+      _mouseLeave = true;
+    }
+    function allowsVertex(d) {
+      return d.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d, context.graph());
+    }
+    function click(d3_event, loc) {
+      var d = datum2(d3_event);
+      var target = d && d.properties && d.properties.entity;
+      var mode = context.mode();
+      if (target && target.type === "node" && allowsVertex(target)) {
+        dispatch10.call("clickNode", this, target, d);
         return;
-      var combinedAction = function(graph, t) {
-        _actions.forEach(function(action) {
-          if (!action.disabled(graph)) {
-            graph = action(graph, t);
-          }
-        });
-        return graph;
-      };
-      combinedAction.transitionable = true;
-      context.perform(combinedAction, operation.annotation());
-      window.setTimeout(function() {
-        context.validator().validate();
-      }, 300);
-    };
-    operation.available = function() {
-      return _actions.length && selectedIDs.length === _actions.length;
-    };
-    operation.disabled = function() {
-      if (!_actions.length)
-        return "";
-      var actionDisableds = _actions.map(function(action) {
-        return action.disabled(context.graph());
-      }).filter(Boolean);
-      if (actionDisableds.length === _actions.length) {
-        if (new Set(actionDisableds).size > 1) {
-          return "multiple_blockers";
+      } else if (target && target.type === "way" && (mode.id !== "add-point" || mode.preset.matchGeometry("vertex"))) {
+        var choice = geoChooseEdge(
+          context.graph().childNodes(target),
+          loc,
+          context.projection,
+          context.activeID()
+        );
+        if (choice) {
+          var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
+          dispatch10.call("clickWay", this, choice.loc, edge, d);
+          return;
         }
-        return actionDisableds[0];
-      } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
-        return "too_large";
-      } else if (someMissing()) {
-        return "not_downloaded";
-      } else if (selectedIDs.some(context.hasHiddenConnections)) {
-        return "connected_to_hidden";
+      } else if (mode.id !== "add-point" || mode.preset.matchGeometry("point")) {
+        var locLatLng = context.projection.invert(loc);
+        dispatch10.call("click", this, locLatLng, d);
       }
-      return false;
-      function someMissing() {
-        if (context.inIntro())
-          return false;
-        var osm = context.connection();
-        if (osm) {
-          var missing = _coords.filter(function(loc) {
-            return !osm.isDataLoaded(loc);
-          });
-          if (missing.length) {
-            missing.forEach(function(loc) {
-              context.loadTileAtLoc(loc);
-            });
-            return true;
-          }
+    }
+    function space(d3_event) {
+      d3_event.preventDefault();
+      d3_event.stopPropagation();
+      var currSpace = context.map().mouse();
+      if (_disableSpace && _lastSpace) {
+        var dist = geoVecLength(_lastSpace, currSpace);
+        if (dist > _tolerance) {
+          _disableSpace = false;
         }
-        return false;
       }
+      if (_disableSpace || _mouseLeave || !_lastMouse)
+        return;
+      _lastSpace = currSpace;
+      _disableSpace = true;
+      select_default2(window).on("keyup.space-block", function() {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        _disableSpace = false;
+        select_default2(window).on("keyup.space-block", null);
+      });
+      var loc = context.map().mouse() || // or the map center if the mouse has never entered the map
+      context.projection(context.map().center());
+      click(d3_event, loc);
+    }
+    function backspace(d3_event) {
+      d3_event.preventDefault();
+      dispatch10.call("undo");
+    }
+    function del(d3_event) {
+      d3_event.preventDefault();
+      dispatch10.call("cancel");
+    }
+    function ret(d3_event) {
+      d3_event.preventDefault();
+      dispatch10.call("finish");
+    }
+    function behavior(selection2) {
+      context.install(_hover);
+      context.install(_edit);
+      _downPointer = null;
+      keybinding.on("\u232B", backspace).on("\u2326", del).on("\u238B", ret).on("\u21A9", ret).on("space", space).on("\u2325space", space);
+      selection2.on("mouseenter.draw", mouseenter).on("mouseleave.draw", mouseleave).on(_pointerPrefix + "down.draw", pointerdown).on(_pointerPrefix + "move.draw", pointermove);
+      select_default2(window).on(_pointerPrefix + "up.draw", pointerup, true).on("pointercancel.draw", pointercancel, true);
+      select_default2(document).call(keybinding);
+      return behavior;
+    }
+    behavior.off = function(selection2) {
+      context.ui().sidebar.hover.cancel();
+      context.uninstall(_hover);
+      context.uninstall(_edit);
+      selection2.on("mouseenter.draw", null).on("mouseleave.draw", null).on(_pointerPrefix + "down.draw", null).on(_pointerPrefix + "move.draw", null);
+      select_default2(window).on(_pointerPrefix + "up.draw", null).on("pointercancel.draw", null);
+      select_default2(document).call(keybinding.unbind);
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
-      return disable ? _t.append("operations.orthogonalize." + disable + "." + _amount) : _t.append("operations.orthogonalize.description." + _type + "." + _amount);
+    behavior.hover = function() {
+      return _hover;
     };
-    operation.annotation = function() {
-      return _t("operations.orthogonalize.annotation." + _type, { n: _actions.length });
+    return utilRebind(behavior, dispatch10, "on");
+  }
+
+  // modules/behavior/breathe.js
+  var import_fast_deep_equal2 = __toESM(require_fast_deep_equal());
+
+  // node_modules/d3-scale/src/init.js
+  function initRange(domain2, range3) {
+    switch (arguments.length) {
+      case 0:
+        break;
+      case 1:
+        this.range(domain2);
+        break;
+      default:
+        this.range(range3).domain(domain2);
+        break;
+    }
+    return this;
+  }
+
+  // node_modules/d3-scale/src/constant.js
+  function constants(x) {
+    return function() {
+      return x;
     };
-    operation.id = "orthogonalize";
-    operation.keys = [_t("operations.orthogonalize.key")];
-    operation.title = _t.append("operations.orthogonalize.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
   }
 
-  // modules/operations/reflect.js
-  function operationReflectShort(context, selectedIDs) {
-    return operationReflect(context, selectedIDs, "short");
+  // node_modules/d3-scale/src/number.js
+  function number2(x) {
+    return +x;
   }
-  function operationReflectLong(context, selectedIDs) {
-    return operationReflect(context, selectedIDs, "long");
+
+  // node_modules/d3-scale/src/continuous.js
+  var unit = [0, 1];
+  function identity3(x) {
+    return x;
   }
-  function operationReflect(context, selectedIDs, axis) {
-    axis = axis || "long";
-    var multi = selectedIDs.length === 1 ? "single" : "multiple";
-    var nodes = utilGetAllNodes(selectedIDs, context.graph());
-    var coords = nodes.map(function(n2) {
-      return n2.loc;
-    });
-    var extent = utilTotalExtent(selectedIDs, context.graph());
-    var operation = function() {
-      var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === "long"));
-      context.perform(action, operation.annotation());
-      window.setTimeout(function() {
-        context.validator().validate();
-      }, 300);
+  function normalize(a, b) {
+    return (b -= a = +a) ? function(x) {
+      return (x - a) / b;
+    } : constants(isNaN(b) ? NaN : 0.5);
+  }
+  function clamper(a, b) {
+    var t;
+    if (a > b)
+      t = a, a = b, b = t;
+    return function(x) {
+      return Math.max(a, Math.min(b, x));
     };
-    operation.available = function() {
-      return nodes.length >= 3;
+  }
+  function bimap(domain2, range3, interpolate) {
+    var d0 = domain2[0], d1 = domain2[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);
+    return function(x) {
+      return r0(d0(x));
     };
-    operation.disabled = function() {
-      if (extent.percentContainedIn(context.map().extent()) < 0.8) {
-        return "too_large";
-      } else if (someMissing()) {
-        return "not_downloaded";
-      } else if (selectedIDs.some(context.hasHiddenConnections)) {
-        return "connected_to_hidden";
-      } else if (selectedIDs.some(incompleteRelation)) {
-        return "incomplete_relation";
-      }
-      return false;
-      function someMissing() {
-        if (context.inIntro())
-          return false;
-        var osm = context.connection();
-        if (osm) {
-          var missing = coords.filter(function(loc) {
-            return !osm.isDataLoaded(loc);
-          });
-          if (missing.length) {
-            missing.forEach(function(loc) {
-              context.loadTileAtLoc(loc);
-            });
-            return true;
-          }
-        }
-        return false;
-      }
-      function incompleteRelation(id2) {
-        var entity = context.entity(id2);
-        return entity.type === "relation" && !entity.isComplete(context.graph());
-      }
-    };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
-      return disable ? _t.append("operations.reflect." + disable + "." + multi) : _t.append("operations.reflect.description." + axis + "." + multi);
-    };
-    operation.annotation = function() {
-      return _t("operations.reflect.annotation." + axis + ".feature", { n: selectedIDs.length });
-    };
-    operation.id = "reflect-" + axis;
-    operation.keys = [_t("operations.reflect.key." + axis)];
-    operation.title = _t.append("operations.reflect.title." + axis);
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
-  }
-
-  // modules/operations/move.js
-  function operationMove(context, selectedIDs) {
-    var multi = selectedIDs.length === 1 ? "single" : "multiple";
-    var nodes = utilGetAllNodes(selectedIDs, context.graph());
-    var coords = nodes.map(function(n2) {
-      return n2.loc;
-    });
-    var extent = utilTotalExtent(selectedIDs, context.graph());
-    var operation = function() {
-      context.enter(modeMove(context, selectedIDs));
-    };
-    operation.available = function() {
-      return selectedIDs.length > 0;
-    };
-    operation.disabled = function() {
-      if (extent.percentContainedIn(context.map().extent()) < 0.8) {
-        return "too_large";
-      } else if (someMissing()) {
-        return "not_downloaded";
-      } else if (selectedIDs.some(context.hasHiddenConnections)) {
-        return "connected_to_hidden";
-      } else if (selectedIDs.some(incompleteRelation)) {
-        return "incomplete_relation";
-      }
-      return false;
-      function someMissing() {
-        if (context.inIntro())
-          return false;
-        var osm = context.connection();
-        if (osm) {
-          var missing = coords.filter(function(loc) {
-            return !osm.isDataLoaded(loc);
-          });
-          if (missing.length) {
-            missing.forEach(function(loc) {
-              context.loadTileAtLoc(loc);
-            });
-            return true;
-          }
-        }
-        return false;
-      }
-      function incompleteRelation(id2) {
-        var entity = context.entity(id2);
-        return entity.type === "relation" && !entity.isComplete(context.graph());
-      }
-    };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
-      return disable ? _t.append("operations.move." + disable + "." + multi) : _t.append("operations.move.description." + multi);
-    };
-    operation.annotation = function() {
-      return selectedIDs.length === 1 ? _t("operations.move.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.move.annotation.feature", { n: selectedIDs.length });
-    };
-    operation.id = "move";
-    operation.keys = [_t("operations.move.key")];
-    operation.title = _t.append("operations.move.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    operation.mouseOnly = true;
-    return operation;
   }
-
-  // modules/modes/rotate.js
-  function modeRotate(context, entityIDs) {
-    var _tolerancePx = 4;
-    var mode = {
-      id: "rotate",
-      button: "browse"
-    };
-    var keybinding = utilKeybinding("rotate");
-    var behaviors = [
-      behaviorEdit(context),
-      operationCircularize(context, entityIDs).behavior,
-      operationDelete(context, entityIDs).behavior,
-      operationMove(context, entityIDs).behavior,
-      operationOrthogonalize(context, entityIDs).behavior,
-      operationReflectLong(context, entityIDs).behavior,
-      operationReflectShort(context, entityIDs).behavior
-    ];
-    var annotation = entityIDs.length === 1 ? _t("operations.rotate.annotation." + context.graph().geometry(entityIDs[0])) : _t("operations.rotate.annotation.feature", { n: entityIDs.length });
-    var _prevGraph;
-    var _prevAngle;
-    var _prevTransform;
-    var _pivot;
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    function doRotate(d3_event) {
-      var fn;
-      if (context.graph() !== _prevGraph) {
-        fn = context.perform;
-      } else {
-        fn = context.replace;
-      }
-      var projection2 = context.projection;
-      var currTransform = projection2.transform();
-      if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
-        var nodes = utilGetAllNodes(entityIDs, context.graph());
-        var points = nodes.map(function(n2) {
-          return projection2(n2.loc);
-        });
-        _pivot = getPivot(points);
-        _prevAngle = void 0;
-      }
-      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;
-      var delta = currAngle - _prevAngle;
-      fn(actionRotate(entityIDs, _pivot, delta, projection2));
-      _prevTransform = currTransform;
-      _prevAngle = currAngle;
-      _prevGraph = context.graph();
-    }
-    function getPivot(points) {
-      var _pivot2;
-      if (points.length === 1) {
-        _pivot2 = points[0];
-      } else if (points.length === 2) {
-        _pivot2 = geoVecInterp(points[0], points[1], 0.5);
-      } else {
-        var polygonHull = hull_default(points);
-        if (polygonHull.length === 2) {
-          _pivot2 = geoVecInterp(points[0], points[1], 0.5);
-        } else {
-          _pivot2 = centroid_default2(hull_default(points));
-        }
-      }
-      return _pivot2;
+  function polymap(domain2, range3, interpolate) {
+    var j2 = Math.min(domain2.length, range3.length) - 1, d = new Array(j2), r = new Array(j2), i2 = -1;
+    if (domain2[j2] < domain2[0]) {
+      domain2 = domain2.slice().reverse();
+      range3 = range3.slice().reverse();
     }
-    function finish(d3_event) {
-      d3_event.stopPropagation();
-      context.replace(actionNoop(), annotation);
-      context.enter(modeSelect(context, entityIDs));
+    while (++i2 < j2) {
+      d[i2] = normalize(domain2[i2], domain2[i2 + 1]);
+      r[i2] = interpolate(range3[i2], range3[i2 + 1]);
     }
-    function cancel() {
-      if (_prevGraph)
-        context.pop();
-      context.enter(modeSelect(context, entityIDs));
+    return function(x) {
+      var i3 = bisect_default(domain2, x, 1, j2) - 1;
+      return r[i3](d[i3](x));
+    };
+  }
+  function copy(source, target) {
+    return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
+  }
+  function transformer2() {
+    var domain2 = unit, range3 = unit, interpolate = value_default, transform2, untransform, unknown, clamp3 = identity3, piecewise, output, input;
+    function rescale() {
+      var n2 = Math.min(domain2.length, range3.length);
+      if (clamp3 !== identity3)
+        clamp3 = clamper(domain2[0], domain2[n2 - 1]);
+      piecewise = n2 > 2 ? polymap : bimap;
+      output = input = null;
+      return scale;
     }
-    function undone() {
-      context.enter(modeBrowse(context));
+    function scale(x) {
+      return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain2.map(transform2), range3, interpolate)))(transform2(clamp3(x)));
     }
-    mode.enter = function() {
-      _prevGraph = null;
-      context.features().forceVisible(entityIDs);
-      behaviors.forEach(context.install);
-      var downEvent;
-      context.surface().on(_pointerPrefix + "down.modeRotate", function(d3_event) {
-        downEvent = d3_event;
-      });
-      select_default2(window).on(_pointerPrefix + "move.modeRotate", doRotate, true).on(_pointerPrefix + "up.modeRotate", function(d3_event) {
-        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);
-        downEvent = null;
-      }, true);
-      context.history().on("undone.modeRotate", undone);
-      keybinding.on("\u238B", cancel).on("\u21A9", finish);
-      select_default2(document).call(keybinding);
+    scale.invert = function(y) {
+      return clamp3(untransform((input || (input = piecewise(range3, domain2.map(transform2), number_default)))(y)));
     };
-    mode.exit = function() {
-      behaviors.forEach(context.uninstall);
-      context.surface().on(_pointerPrefix + "down.modeRotate", null);
-      select_default2(window).on(_pointerPrefix + "move.modeRotate", null, true).on(_pointerPrefix + "up.modeRotate", null, true);
-      context.history().on("undone.modeRotate", null);
-      select_default2(document).call(keybinding.unbind);
-      context.features().forceVisible([]);
+    scale.domain = function(_) {
+      return arguments.length ? (domain2 = Array.from(_, number2), rescale()) : domain2.slice();
     };
-    mode.selectedIDs = function() {
-      if (!arguments.length)
-        return entityIDs;
-      return mode;
+    scale.range = function(_) {
+      return arguments.length ? (range3 = Array.from(_), rescale()) : range3.slice();
     };
-    return mode;
-  }
-
-  // modules/operations/rotate.js
-  function operationRotate(context, selectedIDs) {
-    var multi = selectedIDs.length === 1 ? "single" : "multiple";
-    var nodes = utilGetAllNodes(selectedIDs, context.graph());
-    var coords = nodes.map(function(n2) {
-      return n2.loc;
-    });
-    var extent = utilTotalExtent(selectedIDs, context.graph());
-    var operation = function() {
-      context.enter(modeRotate(context, selectedIDs));
+    scale.rangeRound = function(_) {
+      return range3 = Array.from(_), interpolate = round_default, rescale();
     };
-    operation.available = function() {
-      return nodes.length >= 2;
+    scale.clamp = function(_) {
+      return arguments.length ? (clamp3 = _ ? true : identity3, rescale()) : clamp3 !== identity3;
     };
-    operation.disabled = function() {
-      if (extent.percentContainedIn(context.map().extent()) < 0.8) {
-        return "too_large";
-      } else if (someMissing()) {
-        return "not_downloaded";
-      } else if (selectedIDs.some(context.hasHiddenConnections)) {
-        return "connected_to_hidden";
-      } else if (selectedIDs.some(incompleteRelation)) {
-        return "incomplete_relation";
-      }
-      return false;
-      function someMissing() {
-        if (context.inIntro())
-          return false;
-        var osm = context.connection();
-        if (osm) {
-          var missing = coords.filter(function(loc) {
-            return !osm.isDataLoaded(loc);
-          });
-          if (missing.length) {
-            missing.forEach(function(loc) {
-              context.loadTileAtLoc(loc);
-            });
-            return true;
-          }
-        }
-        return false;
-      }
-      function incompleteRelation(id2) {
-        var entity = context.entity(id2);
-        return entity.type === "relation" && !entity.isComplete(context.graph());
-      }
+    scale.interpolate = function(_) {
+      return arguments.length ? (interpolate = _, rescale()) : interpolate;
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
-      return disable ? _t.append("operations.rotate." + disable + "." + multi) : _t.append("operations.rotate.description." + multi);
+    scale.unknown = function(_) {
+      return arguments.length ? (unknown = _, scale) : unknown;
     };
-    operation.annotation = function() {
-      return selectedIDs.length === 1 ? _t("operations.rotate.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.rotate.annotation.feature", { n: selectedIDs.length });
+    return function(t, u) {
+      transform2 = t, untransform = u;
+      return rescale();
     };
-    operation.id = "rotate";
-    operation.keys = [_t("operations.rotate.key")];
-    operation.title = _t.append("operations.rotate.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    operation.mouseOnly = true;
-    return operation;
+  }
+  function continuous() {
+    return transformer2()(identity3, identity3);
   }
 
-  // modules/modes/move.js
-  function modeMove(context, entityIDs, baseGraph) {
-    var _tolerancePx = 4;
-    var mode = {
-      id: "move",
-      button: "browse"
-    };
-    var keybinding = utilKeybinding("move");
-    var behaviors = [
-      behaviorEdit(context),
-      operationCircularize(context, entityIDs).behavior,
-      operationDelete(context, entityIDs).behavior,
-      operationOrthogonalize(context, entityIDs).behavior,
-      operationReflectLong(context, entityIDs).behavior,
-      operationReflectShort(context, entityIDs).behavior,
-      operationRotate(context, entityIDs).behavior
+  // node_modules/d3-format/src/formatDecimal.js
+  function formatDecimal_default(x) {
+    return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
+  }
+  function formatDecimalParts(x, p) {
+    if ((i2 = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0)
+      return null;
+    var i2, coefficient = x.slice(0, i2);
+    return [
+      coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
+      +x.slice(i2 + 1)
     ];
-    var annotation = entityIDs.length === 1 ? _t("operations.move.annotation." + context.graph().geometry(entityIDs[0])) : _t("operations.move.annotation.feature", { n: entityIDs.length });
-    var _prevGraph;
-    var _cache4;
-    var _origin;
-    var _nudgeInterval;
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    function doMove(nudge) {
-      nudge = nudge || [0, 0];
-      var fn;
-      if (_prevGraph !== context.graph()) {
-        _cache4 = {};
-        _origin = context.map().mouseCoordinates();
-        fn = context.perform;
-      } else {
-        fn = context.overwrite;
-      }
-      var currMouse = context.map().mouse();
-      var origMouse = context.projection(_origin);
-      var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
-      fn(actionMove(entityIDs, delta, context.projection, _cache4));
-      _prevGraph = context.graph();
-    }
-    function startNudge(nudge) {
-      if (_nudgeInterval)
-        window.clearInterval(_nudgeInterval);
-      _nudgeInterval = window.setInterval(function() {
-        context.map().pan(nudge);
-        doMove(nudge);
-      }, 50);
-    }
-    function stopNudge() {
-      if (_nudgeInterval) {
-        window.clearInterval(_nudgeInterval);
-        _nudgeInterval = null;
-      }
-    }
-    function move() {
-      doMove();
-      var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
-      if (nudge) {
-        startNudge(nudge);
-      } else {
-        stopNudge();
-      }
-    }
-    function finish(d3_event) {
-      d3_event.stopPropagation();
-      context.replace(actionNoop(), annotation);
-      context.enter(modeSelect(context, entityIDs));
-      stopNudge();
-    }
-    function cancel() {
-      if (baseGraph) {
-        while (context.graph() !== baseGraph)
-          context.pop();
-        context.enter(modeBrowse(context));
-      } else {
-        if (_prevGraph)
-          context.pop();
-        context.enter(modeSelect(context, entityIDs));
+  }
+
+  // node_modules/d3-format/src/exponent.js
+  function exponent_default(x) {
+    return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
+  }
+
+  // node_modules/d3-format/src/formatGroup.js
+  function formatGroup_default(grouping, thousands) {
+    return function(value, width) {
+      var i2 = value.length, t = [], j2 = 0, g = grouping[0], length = 0;
+      while (i2 > 0 && g > 0) {
+        if (length + g + 1 > width)
+          g = Math.max(1, width - length);
+        t.push(value.substring(i2 -= g, i2 + g));
+        if ((length += g + 1) > width)
+          break;
+        g = grouping[j2 = (j2 + 1) % grouping.length];
       }
-      stopNudge();
-    }
-    function undone() {
-      context.enter(modeBrowse(context));
-    }
-    mode.enter = function() {
-      _origin = context.map().mouseCoordinates();
-      _prevGraph = null;
-      _cache4 = {};
-      context.features().forceVisible(entityIDs);
-      behaviors.forEach(context.install);
-      var downEvent;
-      context.surface().on(_pointerPrefix + "down.modeMove", function(d3_event) {
-        downEvent = d3_event;
-      });
-      select_default2(window).on(_pointerPrefix + "move.modeMove", move, true).on(_pointerPrefix + "up.modeMove", function(d3_event) {
-        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);
-        downEvent = null;
-      }, true);
-      context.history().on("undone.modeMove", undone);
-      keybinding.on("\u238B", cancel).on("\u21A9", finish);
-      select_default2(document).call(keybinding);
+      return t.reverse().join(thousands);
     };
-    mode.exit = function() {
-      stopNudge();
-      behaviors.forEach(function(behavior) {
-        context.uninstall(behavior);
+  }
+
+  // node_modules/d3-format/src/formatNumerals.js
+  function formatNumerals_default(numerals) {
+    return function(value) {
+      return value.replace(/[0-9]/g, function(i2) {
+        return numerals[+i2];
       });
-      context.surface().on(_pointerPrefix + "down.modeMove", null);
-      select_default2(window).on(_pointerPrefix + "move.modeMove", null, true).on(_pointerPrefix + "up.modeMove", null, true);
-      context.history().on("undone.modeMove", null);
-      select_default2(document).call(keybinding.unbind);
-      context.features().forceVisible([]);
-    };
-    mode.selectedIDs = function() {
-      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;
-      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;
-      var oldIDs = context.copyIDs();
-      if (!oldIDs.length)
-        return;
-      var extent = geoExtent();
-      var oldGraph = context.copyGraph();
-      var newIDs = [];
-      var action = actionCopyEntities(oldIDs, oldGraph);
-      context.perform(action);
-      var copies = action.copies();
-      var originals = /* @__PURE__ */ new Set();
-      Object.values(copies).forEach(function(entity) {
-        originals.add(entity.id);
-      });
-      for (var id2 in copies) {
-        var oldEntity = oldGraph.entity(id2);
-        var newEntity = copies[id2];
-        extent._extend(oldEntity.extent(oldGraph));
-        var parents = context.graph().parentWays(newEntity);
-        var parentCopied = parents.some(function(parent) {
-          return originals.has(parent.id);
-        });
-        if (!parentCopied) {
-          newIDs.push(newEntity.id);
+  // 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);
+    var match;
+    return new FormatSpecifier({
+      fill: match[1],
+      align: match[2],
+      sign: match[3],
+      symbol: match[4],
+      zero: match[5],
+      width: match[6],
+      comma: match[7],
+      precision: match[8] && match[8].slice(1),
+      trim: match[9],
+      type: match[10]
+    });
+  }
+  formatSpecifier.prototype = FormatSpecifier.prototype;
+  function FormatSpecifier(specifier) {
+    this.fill = specifier.fill === void 0 ? " " : specifier.fill + "";
+    this.align = specifier.align === void 0 ? ">" : specifier.align + "";
+    this.sign = specifier.sign === void 0 ? "-" : specifier.sign + "";
+    this.symbol = specifier.symbol === void 0 ? "" : specifier.symbol + "";
+    this.zero = !!specifier.zero;
+    this.width = specifier.width === void 0 ? void 0 : +specifier.width;
+    this.comma = !!specifier.comma;
+    this.precision = specifier.precision === void 0 ? void 0 : +specifier.precision;
+    this.trim = !!specifier.trim;
+    this.type = specifier.type === void 0 ? "" : specifier.type + "";
+  }
+  FormatSpecifier.prototype.toString = function() {
+    return this.fill + this.align + this.sign + this.symbol + (this.zero ? "0" : "") + (this.width === void 0 ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") + (this.precision === void 0 ? "" : "." + Math.max(0, this.precision | 0)) + (this.trim ? "~" : "") + this.type;
+  };
+
+  // node_modules/d3-format/src/formatTrim.js
+  function formatTrim_default(s) {
+    out:
+      for (var n2 = s.length, i2 = 1, i0 = -1, i1; i2 < n2; ++i2) {
+        switch (s[i2]) {
+          case ".":
+            i0 = i1 = i2;
+            break;
+          case "0":
+            if (i0 === 0)
+              i0 = i2;
+            i1 = i2;
+            break;
+          default:
+            if (!+s[i2])
+              break out;
+            if (i0 > 0)
+              i0 = 0;
+            break;
         }
       }
-      var copyPoint = context.copyLonLat() && projection2(context.copyLonLat()) || projection2(extent.center());
-      var delta = geoVecSubtract(mouse, copyPoint);
-      context.perform(actionMove(newIDs, delta, projection2));
-      context.enter(modeMove(context, newIDs, baseGraph));
+    return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
+  }
+
+  // node_modules/d3-format/src/formatPrefixAuto.js
+  var prefixExponent;
+  function formatPrefixAuto_default(x, p) {
+    var d = formatDecimalParts(x, p);
+    if (!d)
+      return x + "";
+    var coefficient = d[0], exponent = d[1], i2 = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1, n2 = coefficient.length;
+    return i2 === n2 ? coefficient : i2 > n2 ? coefficient + new Array(i2 - n2 + 1).join("0") : i2 > 0 ? coefficient.slice(0, i2) + "." + coefficient.slice(i2) : "0." + new Array(1 - i2).join("0") + formatDecimalParts(x, Math.max(0, p + i2 - 1))[0];
+  }
+
+  // node_modules/d3-format/src/formatRounded.js
+  function formatRounded_default(x, p) {
+    var d = formatDecimalParts(x, p);
+    if (!d)
+      return x + "";
+    var coefficient = d[0], exponent = d[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");
+  }
+
+  // node_modules/d3-format/src/formatTypes.js
+  var formatTypes_default = {
+    "%": (x, p) => (x * 100).toFixed(p),
+    "b": (x) => Math.round(x).toString(2),
+    "c": (x) => x + "",
+    "d": formatDecimal_default,
+    "e": (x, p) => x.toExponential(p),
+    "f": (x, p) => x.toFixed(p),
+    "g": (x, p) => x.toPrecision(p),
+    "o": (x) => Math.round(x).toString(8),
+    "p": (x, p) => formatRounded_default(x * 100, p),
+    "r": formatRounded_default,
+    "s": formatPrefixAuto_default,
+    "X": (x) => Math.round(x).toString(16).toUpperCase(),
+    "x": (x) => Math.round(x).toString(16)
+  };
+
+  // node_modules/d3-format/src/identity.js
+  function identity_default3(x) {
+    return x;
+  }
+
+  // node_modules/d3-format/src/locale.js
+  var map = Array.prototype.map;
+  var prefixes = ["y", "z", "a", "f", "p", "n", "\xB5", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
+  function locale_default(locale2) {
+    var group = locale2.grouping === void 0 || locale2.thousands === void 0 ? identity_default3 : formatGroup_default(map.call(locale2.grouping, Number), locale2.thousands + ""), currencyPrefix = locale2.currency === void 0 ? "" : locale2.currency[0] + "", currencySuffix = locale2.currency === void 0 ? "" : locale2.currency[1] + "", decimal = locale2.decimal === void 0 ? "." : locale2.decimal + "", numerals = locale2.numerals === void 0 ? identity_default3 : formatNumerals_default(map.call(locale2.numerals, String)), percent = locale2.percent === void 0 ? "%" : locale2.percent + "", minus = locale2.minus === void 0 ? "\u2212" : locale2.minus + "", nan = locale2.nan === void 0 ? "NaN" : locale2.nan + "";
+    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, precision2 = specifier.precision, trim = specifier.trim, type2 = specifier.type;
+      if (type2 === "n")
+        comma = true, type2 = "g";
+      else if (!formatTypes_default[type2])
+        precision2 === void 0 && (precision2 = 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);
+      precision2 = precision2 === void 0 ? 6 : /[gprs]/.test(type2) ? Math.max(1, Math.min(21, precision2)) : Math.max(0, Math.min(20, precision2));
+      function format2(value) {
+        var valuePrefix = prefix, valueSuffix = suffix, i2, n2, c;
+        if (type2 === "c") {
+          valueSuffix = formatType(value) + valueSuffix;
+          value = "";
+        } else {
+          value = +value;
+          var valueNegative = value < 0 || 1 / value < 0;
+          value = isNaN(value) ? nan : formatType(Math.abs(value), precision2);
+          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) {
+            i2 = -1, n2 = value.length;
+            while (++i2 < n2) {
+              if (c = value.charCodeAt(i2), 48 > c || c > 57) {
+                valueSuffix = (c === 46 ? decimal + value.slice(i2 + 1) : value.slice(i2)) + valueSuffix;
+                value = value.slice(0, i2);
+                break;
+              }
+            }
+          }
+        }
+        if (comma && !zero3)
+          value = group(value, Infinity);
+        var length = valuePrefix.length + value.length + valueSuffix.length, padding = length < width ? new Array(width - length + 1).join(fill) : "";
+        if (comma && zero3)
+          value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
+        switch (align) {
+          case "<":
+            value = valuePrefix + value + valueSuffix + padding;
+            break;
+          case "=":
+            value = valuePrefix + padding + value + valueSuffix;
+            break;
+          case "^":
+            value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
+            break;
+          default:
+            value = padding + valuePrefix + value + valueSuffix;
+            break;
+        }
+        return numerals(value);
+      }
+      format2.toString = function() {
+        return specifier + "";
+      };
+      return format2;
     }
-    function behavior() {
-      context.keybinding().on(uiCmd("\u2318V"), doPaste);
-      return behavior;
+    function formatPrefix2(specifier, value) {
+      var f2 = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)), e = Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3, k = Math.pow(10, -e), prefix = prefixes[8 + e / 3];
+      return function(value2) {
+        return f2(k * value2) + prefix;
+      };
     }
-    behavior.off = function() {
-      context.keybinding().off(uiCmd("\u2318V"));
+    return {
+      format: newFormat,
+      formatPrefix: formatPrefix2
     };
-    return behavior;
   }
 
-  // modules/behavior/drag.js
-  function behaviorDrag() {
-    var dispatch10 = dispatch_default("start", "move", "end");
-    var _tolerancePx = 1;
-    var _penTolerancePx = 4;
-    var _origin = null;
-    var _selector = "";
-    var _targetNode;
-    var _targetEntity;
-    var _surface;
-    var _pointerId;
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    var d3_event_userSelectProperty = utilPrefixCSSProperty("UserSelect");
-    var d3_event_userSelectSuppress = function() {
-      var selection2 = selection_default();
-      var select = selection2.style(d3_event_userSelectProperty);
-      selection2.style(d3_event_userSelectProperty, "none");
-      return function() {
-        selection2.style(d3_event_userSelectProperty, select);
-      };
+  // node_modules/d3-format/src/defaultLocale.js
+  var locale;
+  var format;
+  var formatPrefix;
+  defaultLocale({
+    thousands: ",",
+    grouping: [3],
+    currency: ["$", ""]
+  });
+  function defaultLocale(definition) {
+    locale = locale_default(definition);
+    format = locale.format;
+    formatPrefix = locale.formatPrefix;
+    return locale;
+  }
+
+  // node_modules/d3-format/src/precisionFixed.js
+  function precisionFixed_default(step) {
+    return Math.max(0, -exponent_default(Math.abs(step)));
+  }
+
+  // node_modules/d3-format/src/precisionPrefix.js
+  function precisionPrefix_default(step, value) {
+    return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3 - exponent_default(Math.abs(step)));
+  }
+
+  // node_modules/d3-format/src/precisionRound.js
+  function precisionRound_default(step, max3) {
+    step = Math.abs(step), max3 = Math.abs(max3) - step;
+    return Math.max(0, exponent_default(max3) - exponent_default(step)) + 1;
+  }
+
+  // node_modules/d3-scale/src/tickFormat.js
+  function tickFormat(start2, stop, count, specifier) {
+    var step = tickStep(start2, stop, count), precision2;
+    specifier = formatSpecifier(specifier == null ? ",f" : specifier);
+    switch (specifier.type) {
+      case "s": {
+        var value = Math.max(Math.abs(start2), Math.abs(stop));
+        if (specifier.precision == null && !isNaN(precision2 = precisionPrefix_default(step, value)))
+          specifier.precision = precision2;
+        return formatPrefix(specifier, value);
+      }
+      case "":
+      case "e":
+      case "g":
+      case "p":
+      case "r": {
+        if (specifier.precision == null && !isNaN(precision2 = precisionRound_default(step, Math.max(Math.abs(start2), Math.abs(stop)))))
+          specifier.precision = precision2 - (specifier.type === "e");
+        break;
+      }
+      case "f":
+      case "%": {
+        if (specifier.precision == null && !isNaN(precision2 = precisionFixed_default(step)))
+          specifier.precision = precision2 - (specifier.type === "%") * 2;
+        break;
+      }
+    }
+    return format(specifier);
+  }
+
+  // node_modules/d3-scale/src/linear.js
+  function linearish(scale) {
+    var domain2 = scale.domain;
+    scale.ticks = function(count) {
+      var d = domain2();
+      return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
     };
-    function pointerdown(d3_event) {
-      if (_pointerId)
-        return;
-      _pointerId = d3_event.pointerId || "mouse";
-      _targetNode = this;
-      var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
-      var offset;
-      var startOrigin = pointerLocGetter(d3_event);
-      var started = false;
-      var selectEnable = d3_event_userSelectSuppress();
-      select_default2(window).on(_pointerPrefix + "move.drag", pointermove).on(_pointerPrefix + "up.drag pointercancel.drag", pointerup, true);
-      if (_origin) {
-        offset = _origin.call(_targetNode, _targetEntity);
-        offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
-      } else {
-        offset = [0, 0];
+    scale.tickFormat = function(count, specifier) {
+      var d = domain2();
+      return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
+    };
+    scale.nice = function(count) {
+      if (count == null)
+        count = 10;
+      var d = domain2();
+      var i0 = 0;
+      var i1 = d.length - 1;
+      var start2 = d[i0];
+      var stop = d[i1];
+      var prestep;
+      var step;
+      var maxIter = 10;
+      if (stop < start2) {
+        step = start2, start2 = stop, stop = step;
+        step = i0, i0 = i1, i1 = step;
       }
-      d3_event.stopPropagation();
-      function pointermove(d3_event2) {
-        if (_pointerId !== (d3_event2.pointerId || "mouse"))
-          return;
-        var p = pointerLocGetter(d3_event2);
-        if (!started) {
-          var dist = geoVecLength(startOrigin, p);
-          var tolerance = d3_event2.pointerType === "pen" ? _penTolerancePx : _tolerancePx;
-          if (dist < tolerance)
-            return;
-          started = true;
-          dispatch10.call("start", this, d3_event2, _targetEntity);
+      while (maxIter-- > 0) {
+        step = tickIncrement(start2, stop, count);
+        if (step === prestep) {
+          d[i0] = start2;
+          d[i1] = stop;
+          return domain2(d);
+        } else if (step > 0) {
+          start2 = Math.floor(start2 / step) * step;
+          stop = Math.ceil(stop / step) * step;
+        } else if (step < 0) {
+          start2 = Math.ceil(start2 * step) / step;
+          stop = Math.floor(stop * step) / step;
         } else {
-          startOrigin = p;
-          d3_event2.stopPropagation();
-          d3_event2.preventDefault();
-          var dx = p[0] - startOrigin[0];
-          var dy = p[1] - startOrigin[1];
-          dispatch10.call("move", this, d3_event2, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
-        }
-      }
-      function pointerup(d3_event2) {
-        if (_pointerId !== (d3_event2.pointerId || "mouse"))
-          return;
-        _pointerId = null;
-        if (started) {
-          dispatch10.call("end", this, d3_event2, _targetEntity);
-          d3_event2.preventDefault();
+          break;
         }
-        select_default2(window).on(_pointerPrefix + "move.drag", null).on(_pointerPrefix + "up.drag pointercancel.drag", null);
-        selectEnable();
+        prestep = step;
       }
+      return scale;
+    };
+    return scale;
+  }
+  function linear3() {
+    var scale = continuous();
+    scale.copy = function() {
+      return copy(scale, linear3());
+    };
+    initRange.apply(scale, arguments);
+    return linearish(scale);
+  }
+
+  // node_modules/d3-scale/src/quantize.js
+  function quantize() {
+    var x05 = 0, x12 = 1, n2 = 1, domain2 = [0.5], range3 = [0, 1], unknown;
+    function scale(x) {
+      return x != null && x <= x ? range3[bisect_default(domain2, x, 0, n2)] : unknown;
     }
-    function behavior(selection2) {
-      var matchesSelector = utilPrefixDOMProperty("matchesSelector");
-      var delegate = pointerdown;
-      if (_selector) {
-        delegate = function(d3_event) {
-          var root3 = this;
-          var target = d3_event.target;
-          for (; target && target !== root3; target = target.parentNode) {
-            var datum2 = target.__data__;
-            _targetEntity = datum2 instanceof osmNote ? datum2 : datum2 && datum2.properties && datum2.properties.entity;
-            if (_targetEntity && target[matchesSelector](_selector)) {
-              return pointerdown.call(target, d3_event);
-            }
-          }
-        };
-      }
-      selection2.on(_pointerPrefix + "down.drag" + _selector, delegate);
+    function rescale() {
+      var i2 = -1;
+      domain2 = new Array(n2);
+      while (++i2 < n2)
+        domain2[i2] = ((i2 + 1) * x12 - (i2 - n2) * x05) / (n2 + 1);
+      return scale;
     }
-    behavior.off = function(selection2) {
-      selection2.on(_pointerPrefix + "down.drag" + _selector, null);
-    };
-    behavior.selector = function(_) {
-      if (!arguments.length)
-        return _selector;
-      _selector = _;
-      return behavior;
+    scale.domain = function(_) {
+      return arguments.length ? ([x05, x12] = _, x05 = +x05, x12 = +x12, rescale()) : [x05, x12];
     };
-    behavior.origin = function(_) {
-      if (!arguments.length)
-        return _origin;
-      _origin = _;
-      return behavior;
+    scale.range = function(_) {
+      return arguments.length ? (n2 = (range3 = Array.from(_)).length - 1, rescale()) : range3.slice();
     };
-    behavior.cancel = function() {
-      select_default2(window).on(_pointerPrefix + "move.drag", null).on(_pointerPrefix + "up.drag pointercancel.drag", null);
-      return behavior;
+    scale.invertExtent = function(y) {
+      var i2 = range3.indexOf(y);
+      return i2 < 0 ? [NaN, NaN] : i2 < 1 ? [x05, domain2[0]] : i2 >= n2 ? [domain2[n2 - 1], x12] : [domain2[i2 - 1], domain2[i2]];
     };
-    behavior.targetNode = function(_) {
-      if (!arguments.length)
-        return _targetNode;
-      _targetNode = _;
-      return behavior;
+    scale.unknown = function(_) {
+      return arguments.length ? (unknown = _, scale) : scale;
     };
-    behavior.targetEntity = function(_) {
-      if (!arguments.length)
-        return _targetEntity;
-      _targetEntity = _;
-      return behavior;
+    scale.thresholds = function() {
+      return domain2.slice();
     };
-    behavior.surface = function(_) {
-      if (!arguments.length)
-        return _surface;
-      _surface = _;
-      return behavior;
+    scale.copy = function() {
+      return quantize().domain([x05, x12]).range(range3).unknown(unknown);
     };
-    return utilRebind(behavior, dispatch10, "on");
+    return initRange.apply(linearish(scale), arguments);
   }
 
-  // modules/modes/drag_node.js
-  function modeDragNode(context) {
-    var mode = {
-      id: "drag-node",
-      button: "browse"
-    };
-    var hover = behaviorHover(context).altDisables(true).on("hover", context.ui().sidebar.hover);
-    var edit2 = behaviorEdit(context);
-    var _nudgeInterval;
-    var _restoreSelectedIDs = [];
-    var _wasMidpoint = false;
-    var _isCancelled = false;
-    var _activeEntity;
-    var _startLoc;
-    var _lastLoc;
-    function startNudge(d3_event, entity, nudge) {
-      if (_nudgeInterval)
-        window.clearInterval(_nudgeInterval);
-      _nudgeInterval = window.setInterval(function() {
-        context.map().pan(nudge);
-        doMove(d3_event, entity, nudge);
-      }, 50);
+  // modules/behavior/breathe.js
+  function behaviorBreathe() {
+    var duration = 800;
+    var steps = 4;
+    var selector = ".selected.shadow, .selected .shadow";
+    var _selected = select_default2(null);
+    var _classed = "";
+    var _params = {};
+    var _done = false;
+    var _timer;
+    function ratchetyInterpolator(a, b, steps2, units) {
+      a = Number(a);
+      b = Number(b);
+      var sample = quantize().domain([0, 1]).range(quantize_default(number_default(a, b), steps2));
+      return function(t) {
+        return String(sample(t)) + (units || "");
+      };
     }
-    function stopNudge() {
-      if (_nudgeInterval) {
-        window.clearInterval(_nudgeInterval);
-        _nudgeInterval = null;
-      }
+    function reset(selection2) {
+      selection2.style("stroke-opacity", null).style("stroke-width", null).style("fill-opacity", null).style("r", null);
     }
-    function moveAnnotation(entity) {
-      return _t("operations.move.annotation." + entity.geometry(context.graph()));
+    function setAnimationParams(transition2, fromTo) {
+      var toFrom = fromTo === "from" ? "to" : "from";
+      transition2.styleTween("stroke-opacity", function(d) {
+        return ratchetyInterpolator(
+          _params[d.id][toFrom].opacity,
+          _params[d.id][fromTo].opacity,
+          steps
+        );
+      }).styleTween("stroke-width", function(d) {
+        return ratchetyInterpolator(
+          _params[d.id][toFrom].width,
+          _params[d.id][fromTo].width,
+          steps,
+          "px"
+        );
+      }).styleTween("fill-opacity", function(d) {
+        return ratchetyInterpolator(
+          _params[d.id][toFrom].opacity,
+          _params[d.id][fromTo].opacity,
+          steps
+        );
+      }).styleTween("r", function(d) {
+        return ratchetyInterpolator(
+          _params[d.id][toFrom].width,
+          _params[d.id][fromTo].width,
+          steps,
+          "px"
+        );
+      });
     }
-    function connectAnnotation(nodeEntity, targetEntity) {
-      var nodeGeometry = nodeEntity.geometry(context.graph());
-      var targetGeometry = targetEntity.geometry(context.graph());
-      if (nodeGeometry === "vertex" && targetGeometry === "vertex") {
-        var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
-        var targetParentWayIDs = context.graph().parentWays(targetEntity);
-        var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs);
-        if (sharedParentWays.length !== 0) {
-          if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
-            return _t("operations.connect.annotation.from_vertex.to_adjacent_vertex");
-          }
-          return _t("operations.connect.annotation.from_vertex.to_sibling_vertex");
+    function calcAnimationParams(selection2) {
+      selection2.call(reset).each(function(d) {
+        var s = select_default2(this);
+        var tag = s.node().tagName;
+        var p = { "from": {}, "to": {} };
+        var opacity;
+        var width;
+        if (tag === "circle") {
+          opacity = Number(s.style("fill-opacity") || 0.5);
+          width = Number(s.style("r") || 15.5);
+        } else {
+          opacity = Number(s.style("stroke-opacity") || 0.7);
+          width = Number(s.style("stroke-width") || 10);
         }
-      }
-      return _t("operations.connect.annotation.from_" + nodeGeometry + ".to_" + targetGeometry);
-    }
-    function shouldSnapToNode(target) {
-      if (!_activeEntity)
-        return false;
-      return _activeEntity.geometry(context.graph()) !== "vertex" || (target.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(target, context.graph()));
-    }
-    function origin(entity) {
-      return context.projection(entity.loc);
+        p.tag = tag;
+        p.from.opacity = opacity * 0.6;
+        p.to.opacity = opacity * 1.25;
+        p.from.width = width * 0.7;
+        p.to.width = width * (tag === "circle" ? 1.5 : 1);
+        _params[d.id] = p;
+      });
     }
-    function keydown(d3_event) {
-      if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
-        if (context.surface().classed("nope")) {
-          context.surface().classed("nope-suppressed", true);
-        }
-        context.surface().classed("nope", false).classed("nope-disabled", true);
+    function run(surface, fromTo) {
+      var toFrom = fromTo === "from" ? "to" : "from";
+      var currSelected = surface.selectAll(selector);
+      var currClassed = surface.attr("class");
+      if (_done || currSelected.empty()) {
+        _selected.call(reset);
+        _selected = select_default2(null);
+        return;
       }
-    }
-    function keyup(d3_event) {
-      if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
-        if (context.surface().classed("nope-suppressed")) {
-          context.surface().classed("nope", true);
-        }
-        context.surface().classed("nope-suppressed", false).classed("nope-disabled", false);
+      if (!(0, import_fast_deep_equal2.default)(currSelected.data(), _selected.data()) || currClassed !== _classed) {
+        _selected.call(reset);
+        _classed = currClassed;
+        _selected = currSelected.call(calcAnimationParams);
       }
-    }
-    function start2(d3_event, entity) {
-      _wasMidpoint = entity.type === "midpoint";
-      var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
-      _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
-      if (_isCancelled) {
-        if (hasHidden) {
-          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append("modes.drag_node.connected_to_hidden"))();
+      var didCallNextRun = false;
+      _selected.transition().duration(duration).call(setAnimationParams, fromTo).on("end", function() {
+        if (!didCallNextRun) {
+          surface.call(run, toFrom);
+          didCallNextRun = true;
         }
-        return drag.cancel();
-      }
-      if (_wasMidpoint) {
-        var midpoint = entity;
-        entity = osmNode();
-        context.perform(actionAddMidpoint(midpoint, entity));
-        entity = context.entity(entity.id);
-        var vertex = context.surface().selectAll("." + entity.id);
-        drag.targetNode(vertex.node()).targetEntity(entity);
-      } else {
-        context.perform(actionNoop());
-      }
-      _activeEntity = entity;
-      _startLoc = entity.loc;
-      hover.ignoreVertex(entity.geometry(context.graph()) === "vertex");
-      context.surface().selectAll("." + _activeEntity.id).classed("active", true);
-      context.enter(mode);
+        if (!select_default2(this).classed("selected")) {
+          reset(select_default2(this));
+        }
+      });
     }
-    function datum2(d3_event) {
-      if (!d3_event || d3_event.altKey) {
-        return {};
-      } else {
-        var d = d3_event.target.__data__;
-        return d && d.properties && d.properties.target ? d : {};
-      }
+    function behavior(surface) {
+      _done = false;
+      _timer = timer(function() {
+        if (surface.selectAll(selector).empty()) {
+          return false;
+        }
+        surface.call(run, "from");
+        _timer.stop();
+        return true;
+      }, 20);
     }
-    function doMove(d3_event, entity, nudge) {
-      nudge = nudge || [0, 0];
-      var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
-      var currMouse = geoVecSubtract(currPoint, nudge);
-      var loc = context.projection.invert(currMouse);
-      var target, edge;
-      if (!_nudgeInterval) {
-        var d = datum2(d3_event);
-        target = d && d.properties && d.properties.entity;
-        var targetLoc = target && target.loc;
-        var targetNodes = d && d.properties && d.properties.nodes;
-        if (targetLoc) {
-          if (shouldSnapToNode(target)) {
-            loc = targetLoc;
-          }
-        } else if (targetNodes) {
-          edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
-          if (edge) {
-            loc = edge.loc;
-          }
+    behavior.restartIfNeeded = function(surface) {
+      if (_selected.empty()) {
+        surface.call(run, "from");
+        if (_timer) {
+          _timer.stop();
         }
       }
-      context.replace(
-        actionMoveNode(entity.id, loc)
-      );
-      var isInvalid = false;
-      if (target) {
-        isInvalid = hasRelationConflict(entity, target, edge, context.graph());
-      }
-      if (!isInvalid) {
-        isInvalid = hasInvalidGeometry(entity, context.graph());
+    };
+    behavior.off = function() {
+      _done = true;
+      if (_timer) {
+        _timer.stop();
       }
-      var nope = context.surface().classed("nope");
-      if (isInvalid === "relation" || isInvalid === "restriction") {
-        if (!nope) {
-          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append(
-            "operations.connect." + isInvalid,
-            { relation: _mainPresetIndex.item("type/restriction").name() }
-          ))();
-        }
-      } else if (isInvalid) {
-        var errorID = isInvalid === "line" ? "lines" : "areas";
-        context.ui().flash.duration(3e3).iconName("#iD-icon-no").label(_t.append("self_intersection.error." + errorID))();
+      _selected.interrupt().call(reset);
+    };
+    return behavior;
+  }
+
+  // modules/behavior/operation.js
+  function behaviorOperation(context) {
+    var _operation;
+    function keypress(d3_event) {
+      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 {
-        if (nope) {
-          context.ui().flash.duration(1).label("")();
-        }
+        context.ui().flash.duration(2e3).iconName("#iD-operation-" + _operation.id).iconClass("operation").label(_operation.annotation() || _operation.title)();
+        if (_operation.point)
+          _operation.point(null);
+        _operation();
       }
-      var nopeDisabled = context.surface().classed("nope-disabled");
-      if (nopeDisabled) {
-        context.surface().classed("nope", false).classed("nope-suppressed", isInvalid);
-      } else {
-        context.surface().classed("nope", isInvalid).classed("nope-suppressed", false);
+    }
+    function behavior() {
+      if (_operation && _operation.available()) {
+        context.keybinding().on(_operation.keys, keypress);
       }
-      _lastLoc = loc;
+      return behavior;
     }
-    function hasRelationConflict(entity, target, edge, graph) {
-      var testGraph = graph.update();
-      if (edge) {
-        var midpoint = osmNode();
-        var action = actionAddMidpoint({
-          loc: edge.loc,
-          edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
-        }, midpoint);
-        testGraph = action(testGraph);
-        target = midpoint;
+    behavior.off = function() {
+      context.keybinding().off(_operation.keys);
+    };
+    behavior.which = function(_) {
+      if (!arguments.length)
+        return _operation;
+      _operation = _;
+      return behavior;
+    };
+    return behavior;
+  }
+
+  // modules/operations/circularize.js
+  function operationCircularize(context, selectedIDs) {
+    var _extent;
+    var _actions = selectedIDs.map(getAction).filter(Boolean);
+    var _amount = _actions.length === 1 ? "single" : "multiple";
+    var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function(n2) {
+      return n2.loc;
+    });
+    function getAction(entityID) {
+      var entity = context.entity(entityID);
+      if (entity.type !== "way" || new Set(entity.nodes).size <= 1)
+        return null;
+      if (!_extent) {
+        _extent = entity.extent(context.graph());
+      } else {
+        _extent = _extent.extend(entity.extent(context.graph()));
       }
-      var ids = [entity.id, target.id];
-      return actionConnect(ids).disabled(testGraph);
+      return actionCircularize(entityID, context.projection);
     }
-    function hasInvalidGeometry(entity, graph) {
-      var parents = graph.parentWays(entity);
-      var i2, j2, k;
-      for (i2 = 0; i2 < parents.length; i2++) {
-        var parent = parents[i2];
-        var nodes = [];
-        var activeIndex = null;
-        var relations = graph.parentRelations(parent);
-        for (j2 = 0; j2 < relations.length; j2++) {
-          if (!relations[j2].isMultipolygon())
-            continue;
-          var rings = osmJoinWays(relations[j2].members, graph);
-          for (k = 0; k < rings.length; k++) {
-            nodes = rings[k].nodes;
-            if (nodes.find(function(n2) {
-              return n2.id === entity.id;
-            })) {
-              activeIndex = k;
-              if (geoHasSelfIntersections(nodes, entity.id)) {
-                return "multipolygonMember";
-              }
-            }
-            rings[k].coords = nodes.map(function(n2) {
-              return n2.loc;
-            });
-          }
-          for (k = 0; k < rings.length; k++) {
-            if (k === activeIndex)
-              continue;
-            if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
-              return "multipolygonRing";
-            }
+    var operation = function() {
+      if (!_actions.length)
+        return;
+      var combinedAction = function(graph, t) {
+        _actions.forEach(function(action) {
+          if (!action.disabled(graph)) {
+            graph = action(graph, t);
           }
+        });
+        return graph;
+      };
+      combinedAction.transitionable = true;
+      context.perform(combinedAction, operation.annotation());
+      window.setTimeout(function() {
+        context.validator().validate();
+      }, 300);
+    };
+    operation.available = function() {
+      return _actions.length && selectedIDs.length === _actions.length;
+    };
+    operation.disabled = function() {
+      if (!_actions.length)
+        return "";
+      var actionDisableds = _actions.map(function(action) {
+        return action.disabled(context.graph());
+      }).filter(Boolean);
+      if (actionDisableds.length === _actions.length) {
+        if (new Set(actionDisableds).size > 1) {
+          return "multiple_blockers";
         }
-        if (activeIndex === null) {
-          nodes = parent.nodes.map(function(nodeID) {
-            return graph.entity(nodeID);
+        return actionDisableds[0];
+      } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
+        return "too_large";
+      } else if (someMissing()) {
+        return "not_downloaded";
+      } else if (selectedIDs.some(context.hasHiddenConnections)) {
+        return "connected_to_hidden";
+      }
+      return false;
+      function someMissing() {
+        if (context.inIntro())
+          return false;
+        var osm = context.connection();
+        if (osm) {
+          var missing = _coords.filter(function(loc) {
+            return !osm.isDataLoaded(loc);
           });
-          if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
-            return parent.geometry(graph);
+          if (missing.length) {
+            missing.forEach(function(loc) {
+              context.loadTileAtLoc(loc);
+            });
+            return true;
           }
         }
+        return false;
       }
-      return false;
+    };
+    operation.tooltip = function() {
+      var disable = operation.disabled();
+      return disable ? _t.append("operations.circularize." + disable + "." + _amount) : _t.append("operations.circularize.description." + _amount);
+    };
+    operation.annotation = function() {
+      return _t("operations.circularize.annotation.feature", { n: _actions.length });
+    };
+    operation.id = "circularize";
+    operation.keys = [_t("operations.circularize.key")];
+    operation.title = _t.append("operations.circularize.title");
+    operation.behavior = behaviorOperation(context).which(operation);
+    return operation;
+  }
+
+  // modules/ui/cmd.js
+  var uiCmd = function(code) {
+    var detected = utilDetect();
+    if (detected.os === "mac") {
+      return code;
     }
-    function move(d3_event, entity, point) {
-      if (_isCancelled)
-        return;
-      d3_event.stopPropagation();
-      context.surface().classed("nope-disabled", d3_event.altKey);
-      _lastLoc = context.projection.invert(point);
-      doMove(d3_event, entity);
-      var nudge = geoViewportEdge(point, context.map().dimensions());
-      if (nudge) {
-        startNudge(d3_event, entity, nudge);
+    if (detected.os === "win") {
+      if (code === "\u2318\u21E7Z")
+        return "Ctrl+Y";
+    }
+    var result = "", replacements = {
+      "\u2318": "Ctrl",
+      "\u21E7": "Shift",
+      "\u2325": "Alt",
+      "\u232B": "Backspace",
+      "\u2326": "Delete"
+    };
+    for (var i2 = 0; i2 < code.length; i2++) {
+      if (code[i2] in replacements) {
+        result += replacements[code[i2]] + (i2 < code.length - 1 ? "+" : "");
       } else {
-        stopNudge();
+        result += code[i2];
       }
     }
-    function end(d3_event, entity) {
-      if (_isCancelled)
-        return;
-      var wasPoint = entity.geometry(context.graph()) === "point";
-      var d = datum2(d3_event);
-      var nope = d && d.properties && d.properties.nope || context.surface().classed("nope");
-      var target = d && d.properties && d.properties.entity;
-      if (nope) {
-        context.perform(
-          _actionBounceBack(entity.id, _startLoc)
-        );
-      } else if (target && target.type === "way") {
-        var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
-        context.replace(
-          actionAddMidpoint({
-            loc: choice.loc,
-            edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
-          }, entity),
-          connectAnnotation(entity, target)
-        );
-      } else if (target && target.type === "node" && shouldSnapToNode(target)) {
-        context.replace(
-          actionConnect([target.id, entity.id]),
-          connectAnnotation(entity, target)
-        );
-      } else if (_wasMidpoint) {
-        context.replace(
-          actionNoop(),
-          _t("operations.add.annotation.vertex")
-        );
-      } else {
-        context.replace(
-          actionNoop(),
-          moveAnnotation(entity)
-        );
+    return result;
+  };
+  uiCmd.display = function(code) {
+    if (code.length !== 1)
+      return code;
+    var detected = utilDetect();
+    var mac = detected.os === "mac";
+    var replacements = {
+      "\u2318": mac ? "\u2318 " + _t("shortcuts.key.cmd") : _t("shortcuts.key.ctrl"),
+      "\u21E7": mac ? "\u21E7 " + _t("shortcuts.key.shift") : _t("shortcuts.key.shift"),
+      "\u2325": mac ? "\u2325 " + _t("shortcuts.key.option") : _t("shortcuts.key.alt"),
+      "\u2303": mac ? "\u2303 " + _t("shortcuts.key.ctrl") : _t("shortcuts.key.ctrl"),
+      "\u232B": mac ? "\u232B " + _t("shortcuts.key.delete") : _t("shortcuts.key.backspace"),
+      "\u2326": mac ? "\u2326 " + _t("shortcuts.key.del") : _t("shortcuts.key.del"),
+      "\u2196": mac ? "\u2196 " + _t("shortcuts.key.pgup") : _t("shortcuts.key.pgup"),
+      "\u2198": mac ? "\u2198 " + _t("shortcuts.key.pgdn") : _t("shortcuts.key.pgdn"),
+      "\u21DE": mac ? "\u21DE " + _t("shortcuts.key.home") : _t("shortcuts.key.home"),
+      "\u21DF": mac ? "\u21DF " + _t("shortcuts.key.end") : _t("shortcuts.key.end"),
+      "\u21B5": mac ? "\u23CE " + _t("shortcuts.key.return") : _t("shortcuts.key.enter"),
+      "\u238B": mac ? "\u238B " + _t("shortcuts.key.esc") : _t("shortcuts.key.esc"),
+      "\u2630": mac ? "\u2630 " + _t("shortcuts.key.menu") : _t("shortcuts.key.menu")
+    };
+    return replacements[code] || code;
+  };
+
+  // modules/operations/delete.js
+  function operationDelete(context, selectedIDs) {
+    var multi = selectedIDs.length === 1 ? "single" : "multiple";
+    var action = actionDeleteMultiple(selectedIDs);
+    var nodes = utilGetAllNodes(selectedIDs, context.graph());
+    var coords = nodes.map(function(n2) {
+      return n2.loc;
+    });
+    var extent = utilTotalExtent(selectedIDs, context.graph());
+    var operation = function() {
+      var nextSelectedID;
+      var nextSelectedLoc;
+      if (selectedIDs.length === 1) {
+        var id2 = selectedIDs[0];
+        var entity = context.entity(id2);
+        var geometry = entity.geometry(context.graph());
+        var parents = context.graph().parentWays(entity);
+        var parent = parents[0];
+        if (geometry === "vertex") {
+          var nodes2 = parent.nodes;
+          var i2 = nodes2.indexOf(id2);
+          if (i2 === 0) {
+            i2++;
+          } else if (i2 === nodes2.length - 1) {
+            i2--;
+          } else {
+            var a = geoSphericalDistance(entity.loc, context.entity(nodes2[i2 - 1]).loc);
+            var b = geoSphericalDistance(entity.loc, context.entity(nodes2[i2 + 1]).loc);
+            i2 = a < b ? i2 - 1 : i2 + 1;
+          }
+          nextSelectedID = nodes2[i2];
+          nextSelectedLoc = context.entity(nextSelectedID).loc;
+        }
       }
-      if (wasPoint) {
-        context.enter(modeSelect(context, [entity.id]));
-      } else {
-        var reselection = _restoreSelectedIDs.filter(function(id2) {
-          return context.graph().hasEntity(id2);
-        });
-        if (reselection.length) {
-          context.enter(modeSelect(context, reselection));
+      context.perform(action, operation.annotation());
+      context.validator().validate();
+      if (nextSelectedID && nextSelectedLoc) {
+        if (context.hasEntity(nextSelectedID)) {
+          context.enter(modeSelect(context, [nextSelectedID]).follow(true));
         } else {
+          context.map().centerEase(nextSelectedLoc);
           context.enter(modeBrowse(context));
         }
+      } else {
+        context.enter(modeBrowse(context));
       }
-    }
-    function _actionBounceBack(nodeID, toLoc) {
-      var moveNode = actionMoveNode(nodeID, toLoc);
-      var action = function(graph, t) {
-        if (t === 1)
-          context.pop();
-        return moveNode(graph, t);
-      };
-      action.transitionable = true;
-      return action;
-    }
-    function cancel() {
-      drag.cancel();
-      context.enter(modeBrowse(context));
-    }
-    var drag = behaviorDrag().selector(".layer-touch.points .target").surface(context.container().select(".main-map").node()).origin(origin).on("start", start2).on("move", move).on("end", end);
-    mode.enter = function() {
-      context.install(hover);
-      context.install(edit2);
-      select_default2(window).on("keydown.dragNode", keydown).on("keyup.dragNode", keyup);
-      context.history().on("undone.drag-node", cancel);
-    };
-    mode.exit = function() {
-      context.ui().sidebar.hover.cancel();
-      context.uninstall(hover);
-      context.uninstall(edit2);
-      select_default2(window).on("keydown.dragNode", null).on("keyup.dragNode", null);
-      context.history().on("undone.drag-node", null);
-      _activeEntity = null;
-      context.surface().classed("nope", false).classed("nope-suppressed", false).classed("nope-disabled", false).selectAll(".active").classed("active", false);
-      stopNudge();
-    };
-    mode.selectedIDs = function() {
-      if (!arguments.length)
-        return _activeEntity ? [_activeEntity.id] : [];
-      return mode;
     };
-    mode.activeID = function() {
-      if (!arguments.length)
-        return _activeEntity && _activeEntity.id;
-      return mode;
+    operation.available = function() {
+      return true;
     };
-    mode.restoreSelectedIDs = function(_) {
-      if (!arguments.length)
-        return _restoreSelectedIDs;
-      _restoreSelectedIDs = _;
-      return mode;
+    operation.disabled = function() {
+      if (extent.percentContainedIn(context.map().extent()) < 0.8) {
+        return "too_large";
+      } else if (someMissing()) {
+        return "not_downloaded";
+      } else if (selectedIDs.some(context.hasHiddenConnections)) {
+        return "connected_to_hidden";
+      } else if (selectedIDs.some(protectedMember)) {
+        return "part_of_relation";
+      } else if (selectedIDs.some(incompleteRelation)) {
+        return "incomplete_relation";
+      } else if (selectedIDs.some(hasWikidataTag)) {
+        return "has_wikidata_tag";
+      }
+      return false;
+      function someMissing() {
+        if (context.inIntro())
+          return false;
+        var osm = context.connection();
+        if (osm) {
+          var missing = coords.filter(function(loc) {
+            return !osm.isDataLoaded(loc);
+          });
+          if (missing.length) {
+            missing.forEach(function(loc) {
+              context.loadTileAtLoc(loc);
+            });
+            return true;
+          }
+        }
+        return false;
+      }
+      function hasWikidataTag(id2) {
+        var entity = context.entity(id2);
+        return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
+      }
+      function incompleteRelation(id2) {
+        var entity = context.entity(id2);
+        return entity.type === "relation" && !entity.isComplete(context.graph());
+      }
+      function protectedMember(id2) {
+        var entity = context.entity(id2);
+        if (entity.type !== "way")
+          return false;
+        var parents = context.graph().parentRelations(entity);
+        for (var i2 = 0; i2 < parents.length; i2++) {
+          var parent = parents[i2];
+          var type2 = parent.tags.type;
+          var role = parent.memberById(id2).role || "outer";
+          if (type2 === "route" || type2 === "boundary" || type2 === "multipolygon" && role === "outer") {
+            return true;
+          }
+        }
+        return false;
+      }
     };
-    mode.behavior = drag;
-    return mode;
+    operation.tooltip = function() {
+      var disable = operation.disabled();
+      return disable ? _t.append("operations.delete." + disable + "." + multi) : _t.append("operations.delete.description." + multi);
+    };
+    operation.annotation = function() {
+      return selectedIDs.length === 1 ? _t("operations.delete.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.delete.annotation.feature", { n: selectedIDs.length });
+    };
+    operation.id = "delete";
+    operation.keys = [uiCmd("\u2318\u232B"), uiCmd("\u2318\u2326"), uiCmd("\u2326")];
+    operation.title = _t.append("operations.delete.title");
+    operation.behavior = behaviorOperation(context).which(operation);
+    return operation;
   }
 
-  // modules/services/keepRight.js
-  var import_rbush = __toESM(require_rbush_min());
-
-  // node_modules/d3-fetch/src/text.js
-  function responseText(response) {
-    if (!response.ok)
-      throw new Error(response.status + " " + response.statusText);
-    return response.text();
-  }
-  function text_default3(input, init2) {
-    return fetch(input, init2).then(responseText);
+  // modules/operations/orthogonalize.js
+  function operationOrthogonalize(context, selectedIDs) {
+    var _extent;
+    var _type;
+    var _actions = selectedIDs.map(chooseAction).filter(Boolean);
+    var _amount = _actions.length === 1 ? "single" : "multiple";
+    var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function(n2) {
+      return n2.loc;
+    });
+    function chooseAction(entityID) {
+      var entity = context.entity(entityID);
+      var geometry = entity.geometry(context.graph());
+      if (!_extent) {
+        _extent = entity.extent(context.graph());
+      } else {
+        _extent = _extent.extend(entity.extent(context.graph()));
+      }
+      if (entity.type === "way" && new Set(entity.nodes).size > 2) {
+        if (_type && _type !== "feature")
+          return null;
+        _type = "feature";
+        return actionOrthogonalize(entityID, context.projection);
+      } else if (geometry === "vertex") {
+        if (_type && _type !== "corner")
+          return null;
+        _type = "corner";
+        var graph = context.graph();
+        var parents = graph.parentWays(entity);
+        if (parents.length === 1) {
+          var way = parents[0];
+          if (way.nodes.indexOf(entityID) !== -1) {
+            return actionOrthogonalize(way.id, context.projection, entityID);
+          }
+        }
+      }
+      return null;
+    }
+    var operation = function() {
+      if (!_actions.length)
+        return;
+      var combinedAction = function(graph, t) {
+        _actions.forEach(function(action) {
+          if (!action.disabled(graph)) {
+            graph = action(graph, t);
+          }
+        });
+        return graph;
+      };
+      combinedAction.transitionable = true;
+      context.perform(combinedAction, operation.annotation());
+      window.setTimeout(function() {
+        context.validator().validate();
+      }, 300);
+    };
+    operation.available = function() {
+      return _actions.length && selectedIDs.length === _actions.length;
+    };
+    operation.disabled = function() {
+      if (!_actions.length)
+        return "";
+      var actionDisableds = _actions.map(function(action) {
+        return action.disabled(context.graph());
+      }).filter(Boolean);
+      if (actionDisableds.length === _actions.length) {
+        if (new Set(actionDisableds).size > 1) {
+          return "multiple_blockers";
+        }
+        return actionDisableds[0];
+      } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
+        return "too_large";
+      } else if (someMissing()) {
+        return "not_downloaded";
+      } else if (selectedIDs.some(context.hasHiddenConnections)) {
+        return "connected_to_hidden";
+      }
+      return false;
+      function someMissing() {
+        if (context.inIntro())
+          return false;
+        var osm = context.connection();
+        if (osm) {
+          var missing = _coords.filter(function(loc) {
+            return !osm.isDataLoaded(loc);
+          });
+          if (missing.length) {
+            missing.forEach(function(loc) {
+              context.loadTileAtLoc(loc);
+            });
+            return true;
+          }
+        }
+        return false;
+      }
+    };
+    operation.tooltip = function() {
+      var disable = operation.disabled();
+      return disable ? _t.append("operations.orthogonalize." + disable + "." + _amount) : _t.append("operations.orthogonalize.description." + _type + "." + _amount);
+    };
+    operation.annotation = function() {
+      return _t("operations.orthogonalize.annotation." + _type, { n: _actions.length });
+    };
+    operation.id = "orthogonalize";
+    operation.keys = [_t("operations.orthogonalize.key")];
+    operation.title = _t.append("operations.orthogonalize.title");
+    operation.behavior = behaviorOperation(context).which(operation);
+    return operation;
   }
 
-  // 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;
-    return response.json();
+  // modules/operations/reflect.js
+  function operationReflectShort(context, selectedIDs) {
+    return operationReflect(context, selectedIDs, "short");
   }
-  function json_default(input, init2) {
-    return fetch(input, init2).then(responseJson);
+  function operationReflectLong(context, selectedIDs) {
+    return operationReflect(context, selectedIDs, "long");
   }
-
-  // node_modules/d3-fetch/src/xml.js
-  function parser(type3) {
-    return (input, init2) => text_default3(input, init2).then((text2) => new DOMParser().parseFromString(text2, type3));
+  function operationReflect(context, selectedIDs, axis) {
+    axis = axis || "long";
+    var multi = selectedIDs.length === 1 ? "single" : "multiple";
+    var nodes = utilGetAllNodes(selectedIDs, context.graph());
+    var coords = nodes.map(function(n2) {
+      return n2.loc;
+    });
+    var extent = utilTotalExtent(selectedIDs, context.graph());
+    var operation = function() {
+      var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === "long"));
+      context.perform(action, operation.annotation());
+      window.setTimeout(function() {
+        context.validator().validate();
+      }, 300);
+    };
+    operation.available = function() {
+      return nodes.length >= 3;
+    };
+    operation.disabled = function() {
+      if (extent.percentContainedIn(context.map().extent()) < 0.8) {
+        return "too_large";
+      } else if (someMissing()) {
+        return "not_downloaded";
+      } else if (selectedIDs.some(context.hasHiddenConnections)) {
+        return "connected_to_hidden";
+      } else if (selectedIDs.some(incompleteRelation)) {
+        return "incomplete_relation";
+      }
+      return false;
+      function someMissing() {
+        if (context.inIntro())
+          return false;
+        var osm = context.connection();
+        if (osm) {
+          var missing = coords.filter(function(loc) {
+            return !osm.isDataLoaded(loc);
+          });
+          if (missing.length) {
+            missing.forEach(function(loc) {
+              context.loadTileAtLoc(loc);
+            });
+            return true;
+          }
+        }
+        return false;
+      }
+      function incompleteRelation(id2) {
+        var entity = context.entity(id2);
+        return entity.type === "relation" && !entity.isComplete(context.graph());
+      }
+    };
+    operation.tooltip = function() {
+      var disable = operation.disabled();
+      return disable ? _t.append("operations.reflect." + disable + "." + multi) : _t.append("operations.reflect.description." + axis + "." + multi);
+    };
+    operation.annotation = function() {
+      return _t("operations.reflect.annotation." + axis + ".feature", { n: selectedIDs.length });
+    };
+    operation.id = "reflect-" + axis;
+    operation.keys = [_t("operations.reflect.key." + axis)];
+    operation.title = _t.append("operations.reflect.title." + axis);
+    operation.behavior = behaviorOperation(context).which(operation);
+    return operation;
   }
-  var xml_default = parser("application/xml");
-  var html = parser("text/html");
-  var svg = parser("image/svg+xml");
 
-  // modules/services/keepRight.js
-  var tiler = utilTiler();
-  var dispatch2 = dispatch_default("loaded");
-  var _tileZoom = 14;
-  var _krUrlRoot = "https://www.keepright.at";
-  var _krData = { errorTypes: {}, localizeStrings: {} };
-  var _cache;
-  var _krRuleset = [
-    30,
-    40,
-    50,
-    60,
-    70,
-    90,
-    100,
-    110,
-    120,
-    130,
-    150,
-    160,
-    170,
-    180,
-    190,
-    191,
-    192,
-    193,
-    194,
-    195,
-    196,
-    197,
-    198,
-    200,
-    201,
-    202,
-    203,
-    204,
-    205,
-    206,
-    207,
-    208,
-    210,
-    220,
-    230,
-    231,
-    232,
-    270,
-    280,
-    281,
-    282,
-    283,
-    284,
-    285,
-    290,
-    291,
-    292,
-    293,
-    294,
-    295,
-    296,
-    297,
-    298,
-    300,
-    310,
-    311,
-    312,
-    313,
-    320,
-    350,
-    360,
-    370,
-    380,
-    390,
-    400,
-    401,
-    402,
-    410,
-    411,
-    412,
-    413
-  ];
-  function abortRequest(controller) {
-    if (controller) {
-      controller.abort();
-    }
-  }
-  function abortUnwantedRequests(cache, tiles) {
-    Object.keys(cache.inflightTile).forEach((k) => {
-      const wanted = tiles.find((tile) => k === tile.id);
-      if (!wanted) {
-        abortRequest(cache.inflightTile[k]);
-        delete cache.inflightTile[k];
-      }
+  // modules/operations/move.js
+  function operationMove(context, selectedIDs) {
+    var multi = selectedIDs.length === 1 ? "single" : "multiple";
+    var nodes = utilGetAllNodes(selectedIDs, context.graph());
+    var coords = nodes.map(function(n2) {
+      return n2.loc;
     });
+    var extent = utilTotalExtent(selectedIDs, context.graph());
+    var operation = function() {
+      context.enter(modeMove(context, selectedIDs));
+    };
+    operation.available = function() {
+      return selectedIDs.length > 0;
+    };
+    operation.disabled = function() {
+      if (extent.percentContainedIn(context.map().extent()) < 0.8) {
+        return "too_large";
+      } else if (someMissing()) {
+        return "not_downloaded";
+      } else if (selectedIDs.some(context.hasHiddenConnections)) {
+        return "connected_to_hidden";
+      } else if (selectedIDs.some(incompleteRelation)) {
+        return "incomplete_relation";
+      }
+      return false;
+      function someMissing() {
+        if (context.inIntro())
+          return false;
+        var osm = context.connection();
+        if (osm) {
+          var missing = coords.filter(function(loc) {
+            return !osm.isDataLoaded(loc);
+          });
+          if (missing.length) {
+            missing.forEach(function(loc) {
+              context.loadTileAtLoc(loc);
+            });
+            return true;
+          }
+        }
+        return false;
+      }
+      function incompleteRelation(id2) {
+        var entity = context.entity(id2);
+        return entity.type === "relation" && !entity.isComplete(context.graph());
+      }
+    };
+    operation.tooltip = function() {
+      var disable = operation.disabled();
+      return disable ? _t.append("operations.move." + disable + "." + multi) : _t.append("operations.move.description." + multi);
+    };
+    operation.annotation = function() {
+      return selectedIDs.length === 1 ? _t("operations.move.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.move.annotation.feature", { n: selectedIDs.length });
+    };
+    operation.id = "move";
+    operation.keys = [_t("operations.move.key")];
+    operation.title = _t.append("operations.move.title");
+    operation.behavior = behaviorOperation(context).which(operation);
+    operation.mouseOnly = true;
+    return operation;
   }
-  function encodeIssueRtree(d) {
-    return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
-  }
-  function updateRtree(item, replace) {
-    _cache.rtree.remove(item, (a, b) => a.data.id === b.data.id);
-    if (replace) {
-      _cache.rtree.insert(item);
-    }
-  }
-  function tokenReplacements(d) {
-    if (!(d instanceof QAItem))
-      return;
-    const replacements = {};
-    const issueTemplate = _krData.errorTypes[d.whichType];
-    if (!issueTemplate) {
-      console.log("No Template: ", d.whichType);
-      console.log("  ", d.description);
-      return;
-    }
-    if (!issueTemplate.regex)
-      return;
-    const errorRegex = new RegExp(issueTemplate.regex, "i");
-    const errorMatch = errorRegex.exec(d.description);
-    if (!errorMatch) {
-      console.log("Unmatched: ", d.whichType);
-      console.log("  ", d.description);
-      console.log("  ", errorRegex);
-      return;
-    }
-    for (let i2 = 1; i2 < errorMatch.length; i2++) {
-      let capture = errorMatch[i2];
-      let idType;
-      idType = "IDs" in issueTemplate ? issueTemplate.IDs[i2 - 1] : "";
-      if (idType && capture) {
-        capture = parseError(capture, idType);
+
+  // modules/modes/rotate.js
+  function modeRotate(context, entityIDs) {
+    var _tolerancePx = 4;
+    var mode = {
+      id: "rotate",
+      button: "browse"
+    };
+    var keybinding = utilKeybinding("rotate");
+    var behaviors = [
+      behaviorEdit(context),
+      operationCircularize(context, entityIDs).behavior,
+      operationDelete(context, entityIDs).behavior,
+      operationMove(context, entityIDs).behavior,
+      operationOrthogonalize(context, entityIDs).behavior,
+      operationReflectLong(context, entityIDs).behavior,
+      operationReflectShort(context, entityIDs).behavior
+    ];
+    var annotation = entityIDs.length === 1 ? _t("operations.rotate.annotation." + context.graph().geometry(entityIDs[0])) : _t("operations.rotate.annotation.feature", { n: entityIDs.length });
+    var _prevGraph;
+    var _prevAngle;
+    var _prevTransform;
+    var _pivot;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function doRotate(d3_event) {
+      var fn;
+      if (context.graph() !== _prevGraph) {
+        fn = context.perform;
       } else {
-        const compare = capture.toLowerCase();
-        if (_krData.localizeStrings[compare]) {
-          capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare]);
-        } else {
-          capture = unescape_default(capture);
-        }
+        fn = context.replace;
       }
-      replacements["var" + i2] = capture;
+      var projection2 = context.projection;
+      var currTransform = projection2.transform();
+      if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
+        var nodes = utilGetAllNodes(entityIDs, context.graph());
+        var points = nodes.map(function(n2) {
+          return projection2(n2.loc);
+        });
+        _pivot = getPivot(points);
+        _prevAngle = void 0;
+      }
+      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;
+      var delta = currAngle - _prevAngle;
+      fn(actionRotate(entityIDs, _pivot, delta, projection2));
+      _prevTransform = currTransform;
+      _prevAngle = currAngle;
+      _prevGraph = context.graph();
     }
-    return replacements;
-  }
-  function parseError(capture, idType) {
-    const compare = capture.toLowerCase();
-    if (_krData.localizeStrings[compare]) {
-      capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare]);
-    }
-    switch (idType) {
-      case "this":
-        capture = linkErrorObject2(capture);
-        break;
-      case "url":
-        capture = linkURL(capture);
-        break;
-      case "n":
-      case "w":
-      case "r":
-        capture = linkEntity2(idType + capture);
-        break;
-      case "20":
-        capture = parse20(capture);
-        break;
-      case "211":
-        capture = parse211(capture);
-        break;
-      case "231":
-        capture = parse231(capture);
-        break;
-      case "294":
-        capture = parse294(capture);
-        break;
-      case "370":
-        capture = parse370(capture);
-        break;
-    }
-    return capture;
-    function linkErrorObject2(d) {
-      return { html: `<a class="error_object_link">${d}</a>` };
-    }
-    function linkEntity2(d) {
-      return { html: `<a class="error_entity_link">${d}</a>` };
-    }
-    function linkURL(d) {
-      return { html: `<a class="kr_external_link" target="_blank" href="${d}">${d}</a>` };
-    }
-    function parse211(capture2) {
-      let newList = [];
-      const items = capture2.split(", ");
-      items.forEach((item) => {
-        let id2 = linkEntity2("n" + item.slice(1));
-        newList.push(id2);
-      });
-      return newList.join(", ");
-    }
-    function parse231(capture2) {
-      let newList = [];
-      const items = capture2.split("),");
-      items.forEach((item) => {
-        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] })
-          );
+    function getPivot(points) {
+      var _pivot2;
+      if (points.length === 1) {
+        _pivot2 = points[0];
+      } else if (points.length === 2) {
+        _pivot2 = geoVecInterp(points[0], points[1], 0.5);
+      } else {
+        var polygonHull = hull_default(points);
+        if (polygonHull.length === 2) {
+          _pivot2 = geoVecInterp(points[0], points[1], 0.5);
+        } else {
+          _pivot2 = centroid_default2(hull_default(points));
         }
-      });
-      return newList.join(", ");
+      }
+      return _pivot2;
     }
-    function parse294(capture2) {
-      let newList = [];
-      const items = capture2.split(",");
-      items.forEach((item) => {
-        item = item.split(" ");
-        const role = `"${item[0]}"`;
-        const idType2 = item[1].slice(0, 1);
-        let id2 = item[2].slice(1);
-        id2 = linkEntity2(idType2 + id2);
-        newList.push(`${role} ${item[1]} ${id2}`);
-      });
-      return newList.join(", ");
+    function finish(d3_event) {
+      d3_event.stopPropagation();
+      context.replace(actionNoop(), annotation);
+      context.enter(modeSelect(context, entityIDs));
     }
-    function parse370(capture2) {
-      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] });
-      }
-      return "";
+    function cancel() {
+      if (_prevGraph)
+        context.pop();
+      context.enter(modeSelect(context, entityIDs));
     }
-    function parse20(capture2) {
-      let newList = [];
-      const items = capture2.split(",");
-      items.forEach((item) => {
-        const id2 = linkEntity2("n" + item.slice(1));
-        newList.push(id2);
-      });
-      return newList.join(", ");
+    function undone() {
+      context.enter(modeBrowse(context));
     }
+    mode.enter = function() {
+      _prevGraph = null;
+      context.features().forceVisible(entityIDs);
+      behaviors.forEach(context.install);
+      var downEvent;
+      context.surface().on(_pointerPrefix + "down.modeRotate", function(d3_event) {
+        downEvent = d3_event;
+      });
+      select_default2(window).on(_pointerPrefix + "move.modeRotate", doRotate, true).on(_pointerPrefix + "up.modeRotate", function(d3_event) {
+        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);
+        downEvent = null;
+      }, true);
+      context.history().on("undone.modeRotate", undone);
+      keybinding.on("\u238B", cancel).on("\u21A9", finish);
+      select_default2(document).call(keybinding);
+    };
+    mode.exit = function() {
+      behaviors.forEach(context.uninstall);
+      context.surface().on(_pointerPrefix + "down.modeRotate", null);
+      select_default2(window).on(_pointerPrefix + "move.modeRotate", null, true).on(_pointerPrefix + "up.modeRotate", null, true);
+      context.history().on("undone.modeRotate", null);
+      select_default2(document).call(keybinding.unbind);
+      context.features().forceVisible([]);
+    };
+    mode.selectedIDs = function() {
+      if (!arguments.length)
+        return entityIDs;
+      return mode;
+    };
+    return mode;
   }
-  var keepRight_default = {
-    title: "keepRight",
-    init() {
-      _mainFileFetcher.get("keepRight").then((d) => _krData = d);
-      if (!_cache) {
-        this.reset();
-      }
-      this.event = utilRebind(this, dispatch2, "on");
-    },
-    reset() {
-      if (_cache) {
-        Object.values(_cache.inflightTile).forEach(abortRequest);
+
+  // modules/operations/rotate.js
+  function operationRotate(context, selectedIDs) {
+    var multi = selectedIDs.length === 1 ? "single" : "multiple";
+    var nodes = utilGetAllNodes(selectedIDs, context.graph());
+    var coords = nodes.map(function(n2) {
+      return n2.loc;
+    });
+    var extent = utilTotalExtent(selectedIDs, context.graph());
+    var operation = function() {
+      context.enter(modeRotate(context, selectedIDs));
+    };
+    operation.available = function() {
+      return nodes.length >= 2;
+    };
+    operation.disabled = function() {
+      if (extent.percentContainedIn(context.map().extent()) < 0.8) {
+        return "too_large";
+      } else if (someMissing()) {
+        return "not_downloaded";
+      } else if (selectedIDs.some(context.hasHiddenConnections)) {
+        return "connected_to_hidden";
+      } else if (selectedIDs.some(incompleteRelation)) {
+        return "incomplete_relation";
       }
-      _cache = {
-        data: {},
-        loadedTile: {},
-        inflightTile: {},
-        inflightPost: {},
-        closed: {},
-        rtree: new import_rbush.default()
-      };
-    },
-    loadIssues(projection2) {
-      const options2 = {
-        format: "geojson",
-        ch: _krRuleset
-      };
-      const tiles = tiler.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection2);
-      abortUnwantedRequests(_cache, tiles);
-      tiles.forEach((tile) => {
-        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 = `${_krUrlRoot}/export.php?` + utilQsString(params);
-        const controller = new AbortController();
-        _cache.inflightTile[tile.id] = controller;
-        json_default(url, { signal: controller.signal }).then((data) => {
-          delete _cache.inflightTile[tile.id];
-          _cache.loadedTile[tile.id] = true;
-          if (!data || !data.features || !data.features.length) {
-            throw new Error("No Data");
-          }
-          data.features.forEach((feature3) => {
-            const {
-              properties: {
-                error_type: itemType,
-                error_id: id2,
-                comment = null,
-                object_id: objectId,
-                object_type: objectType,
-                schema,
-                title
-              }
-            } = feature3;
-            let {
-              geometry: { coordinates: loc },
-              properties: { description = "" }
-            } = feature3;
-            const issueTemplate = _krData.errorTypes[itemType];
-            const parentIssueType = (Math.floor(itemType / 10) * 10).toString();
-            const whichType = issueTemplate ? itemType : parentIssueType;
-            const whichTemplate = _krData.errorTypes[whichType];
-            switch (whichType) {
-              case "170":
-                description = `This feature has a FIXME tag: ${description}`;
-                break;
-              case "292":
-              case "293":
-                description = description.replace("A turn-", "This turn-");
-                break;
-              case "294":
-              case "295":
-              case "296":
-              case "297":
-              case "298":
-                description = `This turn-restriction~${description}`;
-                break;
-              case "300":
-                description = "This highway is missing a maxspeed tag";
-                break;
-              case "411":
-              case "412":
-              case "413":
-                description = `This feature~${description}`;
-                break;
-            }
-            let coincident = false;
-            do {
-              let delta = coincident ? [1e-5, 0] : [0, 1e-5];
-              loc = geoVecAdd(loc, delta);
-              let bbox = geoExtent(loc).bbox();
-              coincident = _cache.rtree.search(bbox).length;
-            } while (coincident);
-            let d = new QAItem(loc, this, itemType, id2, {
-              comment,
-              description,
-              whichType,
-              parentIssueType,
-              severity: whichTemplate.severity || "error",
-              objectId,
-              objectType,
-              schema,
-              title
-            });
-            d.replacements = tokenReplacements(d);
-            _cache.data[id2] = d;
-            _cache.rtree.insert(encodeIssueRtree(d));
+      return false;
+      function someMissing() {
+        if (context.inIntro())
+          return false;
+        var osm = context.connection();
+        if (osm) {
+          var missing = coords.filter(function(loc) {
+            return !osm.isDataLoaded(loc);
           });
-          dispatch2.call("loaded");
-        }).catch(() => {
-          delete _cache.inflightTile[tile.id];
-          _cache.loadedTile[tile.id] = true;
-        });
-      });
-    },
-    postUpdate(d, callback) {
-      if (_cache.inflightPost[d.id]) {
-        return callback({ message: "Error update already inflight", status: -2 }, d);
+          if (missing.length) {
+            missing.forEach(function(loc) {
+              context.loadTileAtLoc(loc);
+            });
+            return true;
+          }
+        }
+        return false;
       }
-      const params = { schema: d.schema, id: d.id };
-      if (d.newStatus) {
-        params.st = d.newStatus;
+      function incompleteRelation(id2) {
+        var entity = context.entity(id2);
+        return entity.type === "relation" && !entity.isComplete(context.graph());
       }
-      if (d.newComment !== void 0) {
-        params.co = d.newComment;
+    };
+    operation.tooltip = function() {
+      var disable = operation.disabled();
+      return disable ? _t.append("operations.rotate." + disable + "." + multi) : _t.append("operations.rotate.description." + multi);
+    };
+    operation.annotation = function() {
+      return selectedIDs.length === 1 ? _t("operations.rotate.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.rotate.annotation.feature", { n: selectedIDs.length });
+    };
+    operation.id = "rotate";
+    operation.keys = [_t("operations.rotate.key")];
+    operation.title = _t.append("operations.rotate.title");
+    operation.behavior = behaviorOperation(context).which(operation);
+    operation.mouseOnly = true;
+    return operation;
+  }
+
+  // modules/modes/move.js
+  function modeMove(context, entityIDs, baseGraph) {
+    var _tolerancePx = 4;
+    var mode = {
+      id: "move",
+      button: "browse"
+    };
+    var keybinding = utilKeybinding("move");
+    var behaviors = [
+      behaviorEdit(context),
+      operationCircularize(context, entityIDs).behavior,
+      operationDelete(context, entityIDs).behavior,
+      operationOrthogonalize(context, entityIDs).behavior,
+      operationReflectLong(context, entityIDs).behavior,
+      operationReflectShort(context, entityIDs).behavior,
+      operationRotate(context, entityIDs).behavior
+    ];
+    var annotation = entityIDs.length === 1 ? _t("operations.move.annotation." + context.graph().geometry(entityIDs[0])) : _t("operations.move.annotation.feature", { n: entityIDs.length });
+    var _prevGraph;
+    var _cache4;
+    var _origin;
+    var _nudgeInterval;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function doMove(nudge) {
+      nudge = nudge || [0, 0];
+      var fn;
+      if (_prevGraph !== context.graph()) {
+        _cache4 = {};
+        _origin = context.map().mouseCoordinates();
+        fn = context.perform;
+      } else {
+        fn = context.overwrite;
       }
-      const url = `${_krUrlRoot}/comment.php?` + utilQsString(params);
-      const controller = new AbortController();
-      _cache.inflightPost[d.id] = controller;
-      json_default(url, { signal: controller.signal }).finally(() => {
-        delete _cache.inflightPost[d.id];
-        if (d.newStatus === "ignore") {
-          this.removeItem(d);
-        } else if (d.newStatus === "ignore_t") {
-          this.removeItem(d);
-          _cache.closed[`${d.schema}:${d.id}`] = true;
-        } else {
-          d = this.replaceItem(d.update({
-            comment: d.newComment,
-            newComment: void 0,
-            newState: void 0
-          }));
-        }
-        if (callback)
-          callback(null, d);
-      });
-    },
-    getItems(projection2) {
-      const viewport = projection2.clipExtent();
-      const min3 = [viewport[0][0], viewport[1][1]];
-      const max3 = [viewport[1][0], viewport[0][1]];
-      const bbox = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
-      return _cache.rtree.search(bbox).map((d) => d.data);
-    },
-    getError(id2) {
-      return _cache.data[id2];
-    },
-    replaceItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
-      _cache.data[item.id] = item;
-      updateRtree(encodeIssueRtree(item), true);
-      return item;
-    },
-    removeItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
-      delete _cache.data[item.id];
-      updateRtree(encodeIssueRtree(item), false);
-    },
-    issueURL(item) {
-      return `${_krUrlRoot}/report_map.php?schema=${item.schema}&error=${item.id}`;
-    },
-    getClosedIDs() {
-      return Object.keys(_cache.closed).sort();
+      var currMouse = context.map().mouse();
+      var origMouse = context.projection(_origin);
+      var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
+      fn(actionMove(entityIDs, delta, context.projection, _cache4));
+      _prevGraph = context.graph();
     }
-  };
-
-  // 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(i2) {
-    Object.values(i2).forEach((controller) => {
-      if (controller) {
-        controller.abort();
+    function startNudge(nudge) {
+      if (_nudgeInterval)
+        window.clearInterval(_nudgeInterval);
+      _nudgeInterval = window.setInterval(function() {
+        context.map().pan(nudge);
+        doMove(nudge);
+      }, 50);
+    }
+    function stopNudge() {
+      if (_nudgeInterval) {
+        window.clearInterval(_nudgeInterval);
+        _nudgeInterval = null;
       }
-    });
-  }
-  function abortUnwantedRequests2(cache, tiles) {
-    Object.keys(cache.inflightTile).forEach((k) => {
-      const wanted = tiles.find((tile) => k === tile.id);
-      if (!wanted) {
-        abortRequest2(cache.inflightTile[k]);
-        delete cache.inflightTile[k];
+    }
+    function move() {
+      doMove();
+      var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
+      if (nudge) {
+        startNudge(nudge);
+      } else {
+        stopNudge();
       }
-    });
-  }
-  function encodeIssueRtree2(d) {
-    return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
-  }
-  function updateRtree2(item, replace) {
-    _cache2.rtree.remove(item, (a, b) => a.data.id === b.data.id);
-    if (replace) {
-      _cache2.rtree.insert(item);
     }
-  }
-  function linkErrorObject(d) {
-    return { html: `<a class="error_object_link">${d}</a>` };
-  }
-  function linkEntity(d) {
-    return { html: `<a class="error_entity_link">${d}</a>` };
-  }
-  function pointAverage(points) {
-    if (points.length) {
-      const sum = points.reduce(
-        (acc, point) => geoVecAdd(acc, [point.lon, point.lat]),
-        [0, 0]
-      );
-      return geoVecScale(sum, 1 / points.length);
-    } else {
-      return [0, 0];
+    function finish(d3_event) {
+      d3_event.stopPropagation();
+      context.replace(actionNoop(), annotation);
+      context.enter(modeSelect(context, entityIDs));
+      stopNudge();
     }
-  }
-  function relativeBearing(p1, p2) {
-    let angle2 = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
-    if (angle2 < 0) {
-      angle2 += 2 * Math.PI;
+    function cancel() {
+      if (baseGraph) {
+        while (context.graph() !== baseGraph)
+          context.pop();
+        context.enter(modeBrowse(context));
+      } else {
+        if (_prevGraph)
+          context.pop();
+        context.enter(modeSelect(context, entityIDs));
+      }
+      stopNudge();
     }
-    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"
+    function undone() {
+      context.enter(modeBrowse(context));
+    }
+    mode.enter = function() {
+      _origin = context.map().mouseCoordinates();
+      _prevGraph = null;
+      _cache4 = {};
+      context.features().forceVisible(entityIDs);
+      behaviors.forEach(context.install);
+      var downEvent;
+      context.surface().on(_pointerPrefix + "down.modeMove", function(d3_event) {
+        downEvent = d3_event;
+      });
+      select_default2(window).on(_pointerPrefix + "move.modeMove", move, true).on(_pointerPrefix + "up.modeMove", function(d3_event) {
+        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);
+        downEvent = null;
+      }, true);
+      context.history().on("undone.modeMove", undone);
+      keybinding.on("\u238B", cancel).on("\u21A9", finish);
+      select_default2(document).call(keybinding);
     };
-    return _t(`QA.improveOSM.directions.${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 bbox = geoExtent(loc).bbox();
-      coincident = _cache2.rtree.search(bbox).length;
-    } while (coincident);
-    return loc;
+    mode.exit = function() {
+      stopNudge();
+      behaviors.forEach(function(behavior) {
+        context.uninstall(behavior);
+      });
+      context.surface().on(_pointerPrefix + "down.modeMove", null);
+      select_default2(window).on(_pointerPrefix + "move.modeMove", null, true).on(_pointerPrefix + "up.modeMove", null, true);
+      context.history().on("undone.modeMove", null);
+      select_default2(document).call(keybinding.unbind);
+      context.features().forceVisible([]);
+    };
+    mode.selectedIDs = function() {
+      if (!arguments.length)
+        return entityIDs;
+      return mode;
+    };
+    return mode;
   }
-  var improveOSM_default = {
-    title: "improveOSM",
-    init() {
-      _mainFileFetcher.get("qa_data").then((d) => _impOsmData = d.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"
-      };
-      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((k) => {
-          const kParams = Object.assign(
-            {},
-            params,
-            k === "mr" ? { type: "PARKING,ROAD,BOTH,PATH" } : { confidenceLevel: "C1" }
-          );
-          const url = `${_impOsmUrls[k]}/search?` + utilQsString(kParams);
-          const controller = new AbortController();
-          requests[k] = controller;
-          json_default(url, { signal: controller.signal }).then((data) => {
-            delete _cache2.inflightTile[tile.id][k];
-            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 = `${wayId}${fromNodeId}${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 d = new QAItem(loc, this, k, itemId, {
-                  issueKey: k,
-                  identifier: {
-                    wayId,
-                    fromNodeId,
-                    toNodeId
-                  },
-                  objectId: wayId,
-                  objectType: "way"
-                });
-                d.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[d.id] = d;
-                _cache2.rtree.insert(encodeIssueRtree2(d));
-              });
-            }
-            if (data.tiles) {
-              data.tiles.forEach((feature3) => {
-                const { type: type3, x, y, numberOfTrips } = feature3;
-                const geoType = type3.toLowerCase();
-                const itemId = `${geoType}${x}${y}${numberOfTrips}`;
-                let loc = pointAverage(feature3.points);
-                loc = preventCoincident(loc, false);
-                let d = new QAItem(loc, this, `${k}-${geoType}`, itemId, {
-                  issueKey: k,
-                  identifier: { x, y }
-                });
-                d.replacements = {
-                  num_trips: numberOfTrips,
-                  geometry_type: _t(`QA.improveOSM.geometry_types.${geoType}`)
-                };
-                if (numberOfTrips === -1) {
-                  d.desc = _t("QA.improveOSM.error_types.mr.description_alt", d.replacements);
-                }
-                _cache2.data[d.id] = d;
-                _cache2.rtree.insert(encodeIssueRtree2(d));
-              });
-            }
-            if (data.entities) {
-              data.entities.forEach((feature3) => {
-                const { point, id: id2, segments, numberOfPasses, turnType } = feature3;
-                const itemId = `${id2.replace(/[,:+#]/g, "_")}`;
-                const loc = preventCoincident([point.lon, point.lat], true);
-                const ids = id2.split(",");
-                const from_way = ids[0];
-                const via_node = ids[3];
-                const to_way = ids[2].split(":")[1];
-                let d = new QAItem(loc, this, k, itemId, {
-                  issueKey: k,
-                  identifier: id2,
-                  objectId: via_node,
-                  objectType: "node"
-                });
-                const [p1, p2] = segments[0].points;
-                const dir_of_travel = cardinalDirection(relativeBearing(p1, p2));
-                d.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[d.id] = d;
-                _cache2.rtree.insert(encodeIssueRtree2(d));
-                dispatch3.call("loaded");
-              });
-            }
-          }).catch(() => {
-            delete _cache2.inflightTile[tile.id][k];
-            if (!Object.keys(_cache2.inflightTile[tile.id]).length) {
-              delete _cache2.inflightTile[tile.id];
-              _cache2.loadedTile[tile.id] = true;
-            }
-          });
-        });
-        _cache2.inflightTile[tile.id] = requests;
+
+  // modules/behavior/paste.js
+  function behaviorPaste(context) {
+    function doPaste(d3_event) {
+      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;
+      var oldIDs = context.copyIDs();
+      if (!oldIDs.length)
+        return;
+      var extent = geoExtent();
+      var oldGraph = context.copyGraph();
+      var newIDs = [];
+      var action = actionCopyEntities(oldIDs, oldGraph);
+      context.perform(action);
+      var copies = action.copies();
+      var originals = /* @__PURE__ */ new Set();
+      Object.values(copies).forEach(function(entity) {
+        originals.add(entity.id);
       });
-    },
-    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;
+      for (var id2 in copies) {
+        var oldEntity = oldGraph.entity(id2);
+        var newEntity = copies[id2];
+        extent._extend(oldEntity.extent(oldGraph));
+        var parents = context.graph().parentWays(newEntity);
+        var parentCopied = parents.some(function(parent) {
+          return originals.has(parent.id);
+        });
+        if (!parentCopied) {
+          newIDs.push(newEntity.id);
+        }
       }
-      const url = `${_impOsmUrls[key]}/retrieveComments?` + utilQsString(qParams);
-      const cacheComments = (data) => {
-        item.comments = data.comments ? data.comments.reverse() : [];
-        this.replaceItem(item);
+      var copyPoint = context.copyLonLat() && projection2(context.copyLonLat()) || projection2(extent.center());
+      var delta = geoVecSubtract(mouse, copyPoint);
+      context.perform(actionMove(newIDs, delta, projection2));
+      context.enter(modeMove(context, newIDs, baseGraph));
+    }
+    function behavior() {
+      context.keybinding().on(uiCmd("\u2318V"), doPaste);
+      return behavior;
+    }
+    behavior.off = function() {
+      context.keybinding().off(uiCmd("\u2318V"));
+    };
+    return behavior;
+  }
+
+  // modules/behavior/drag.js
+  function behaviorDrag() {
+    var dispatch10 = dispatch_default("start", "move", "end");
+    var _tolerancePx = 1;
+    var _penTolerancePx = 4;
+    var _origin = null;
+    var _selector = "";
+    var _targetNode;
+    var _targetEntity;
+    var _surface;
+    var _pointerId;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    var d3_event_userSelectProperty = utilPrefixCSSProperty("UserSelect");
+    var d3_event_userSelectSuppress = function() {
+      var selection2 = selection_default();
+      var select = selection2.style(d3_event_userSelectProperty);
+      selection2.style(d3_event_userSelectProperty, "none");
+      return function() {
+        selection2.style(d3_event_userSelectProperty, select);
       };
-      return json_default(url).then(cacheComments).then(() => item);
-    },
-    postUpdate(d, callback) {
-      if (!osm_default.authenticated()) {
-        return callback({ message: "Not Authenticated", status: -3 }, d);
-      }
-      if (_cache2.inflightPost[d.id]) {
-        return callback({ message: "Error update already inflight", status: -2 }, d);
+    };
+    function pointerdown(d3_event) {
+      if (_pointerId)
+        return;
+      _pointerId = d3_event.pointerId || "mouse";
+      _targetNode = this;
+      var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
+      var offset;
+      var startOrigin = pointerLocGetter(d3_event);
+      var started = false;
+      var selectEnable = d3_event_userSelectSuppress();
+      select_default2(window).on(_pointerPrefix + "move.drag", pointermove).on(_pointerPrefix + "up.drag pointercancel.drag", pointerup, true);
+      if (_origin) {
+        offset = _origin.call(_targetNode, _targetEntity);
+        offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
+      } else {
+        offset = [0, 0];
       }
-      osm_default.userDetails(sendPayload.bind(this));
-      function sendPayload(err, user) {
-        if (err) {
-          return callback(err, d);
-        }
-        const key = d.issueKey;
-        const url = `${_impOsmUrls[key]}/comment`;
-        const payload = {
-          username: user.display_name,
-          targetIds: [d.identifier]
-        };
-        if (d.newStatus) {
-          payload.status = d.newStatus;
-          payload.text = "status changed";
+      d3_event.stopPropagation();
+      function pointermove(d3_event2) {
+        if (_pointerId !== (d3_event2.pointerId || "mouse"))
+          return;
+        var p = pointerLocGetter(d3_event2);
+        if (!started) {
+          var dist = geoVecLength(startOrigin, p);
+          var tolerance = d3_event2.pointerType === "pen" ? _penTolerancePx : _tolerancePx;
+          if (dist < tolerance)
+            return;
+          started = true;
+          dispatch10.call("start", this, d3_event2, _targetEntity);
+        } else {
+          startOrigin = p;
+          d3_event2.stopPropagation();
+          d3_event2.preventDefault();
+          var dx = p[0] - startOrigin[0];
+          var dy = p[1] - startOrigin[1];
+          dispatch10.call("move", this, d3_event2, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
         }
-        if (d.newComment) {
-          payload.text = d.newComment;
+      }
+      function pointerup(d3_event2) {
+        if (_pointerId !== (d3_event2.pointerId || "mouse"))
+          return;
+        _pointerId = null;
+        if (started) {
+          dispatch10.call("end", this, d3_event2, _targetEntity);
+          d3_event2.preventDefault();
         }
-        const controller = new AbortController();
-        _cache2.inflightPost[d.id] = controller;
-        const options2 = {
-          method: "POST",
-          signal: controller.signal,
-          body: JSON.stringify(payload)
-        };
-        json_default(url, options2).then(() => {
-          delete _cache2.inflightPost[d.id];
-          if (!d.newStatus) {
-            const now3 = new Date();
-            let comments = d.comments ? d.comments : [];
-            comments.push({
-              username: payload.username,
-              text: payload.text,
-              timestamp: now3.getTime() / 1e3
-            });
-            this.replaceItem(d.update({
-              comments,
-              newComment: void 0
-            }));
-          } else {
-            this.removeItem(d);
-            if (d.newStatus === "SOLVED") {
-              if (!(d.issueKey in _cache2.closed)) {
-                _cache2.closed[d.issueKey] = 0;
-              }
-              _cache2.closed[d.issueKey] += 1;
+        select_default2(window).on(_pointerPrefix + "move.drag", null).on(_pointerPrefix + "up.drag pointercancel.drag", null);
+        selectEnable();
+      }
+    }
+    function behavior(selection2) {
+      var matchesSelector = utilPrefixDOMProperty("matchesSelector");
+      var delegate = pointerdown;
+      if (_selector) {
+        delegate = function(d3_event) {
+          var root3 = this;
+          var target = d3_event.target;
+          for (; target && target !== root3; target = target.parentNode) {
+            var datum2 = target.__data__;
+            _targetEntity = datum2 instanceof osmNote ? datum2 : datum2 && datum2.properties && datum2.properties.entity;
+            if (_targetEntity && target[matchesSelector](_selector)) {
+              return pointerdown.call(target, d3_event);
             }
           }
-          if (callback)
-            callback(null, d);
-        }).catch((err2) => {
-          delete _cache2.inflightPost[d.id];
-          if (callback)
-            callback(err2.message);
-        });
+        };
       }
-    },
-    getItems(projection2) {
-      const viewport = projection2.clipExtent();
-      const min3 = [viewport[0][0], viewport[1][1]];
-      const max3 = [viewport[1][0], viewport[0][1]];
-      const bbox = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
-      return _cache2.rtree.search(bbox).map((d) => d.data);
-    },
-    getError(id2) {
-      return _cache2.data[id2];
-    },
-    getIcon(itemType) {
-      return _impOsmData.icons[itemType];
-    },
-    replaceItem(issue) {
-      if (!(issue instanceof QAItem) || !issue.id)
-        return;
-      _cache2.data[issue.id] = issue;
-      updateRtree2(encodeIssueRtree2(issue), true);
-      return issue;
-    },
-    removeItem(issue) {
-      if (!(issue instanceof QAItem) || !issue.id)
-        return;
-      delete _cache2.data[issue.id];
-      updateRtree2(encodeIssueRtree2(issue), false);
-    },
-    getClosedCounts() {
-      return _cache2.closed;
+      selection2.on(_pointerPrefix + "down.drag" + _selector, delegate);
     }
-  };
-
-  // modules/services/osmose.js
-  var import_rbush3 = __toESM(require_rbush_min());
-
-  // node_modules/marked/lib/marked.esm.js
-  function getDefaults() {
-    return {
-      async: false,
-      baseUrl: null,
-      breaks: false,
-      extensions: null,
-      gfm: true,
-      headerIds: true,
-      headerPrefix: "",
-      highlight: null,
-      langPrefix: "language-",
-      mangle: true,
-      pedantic: false,
-      renderer: null,
-      sanitize: false,
-      sanitizer: null,
-      silent: false,
-      smartLists: false,
-      smartypants: false,
-      tokenizer: null,
-      walkTokens: null,
-      xhtml: false
+    behavior.off = function(selection2) {
+      selection2.on(_pointerPrefix + "down.drag" + _selector, null);
     };
+    behavior.selector = function(_) {
+      if (!arguments.length)
+        return _selector;
+      _selector = _;
+      return behavior;
+    };
+    behavior.origin = function(_) {
+      if (!arguments.length)
+        return _origin;
+      _origin = _;
+      return behavior;
+    };
+    behavior.cancel = function() {
+      select_default2(window).on(_pointerPrefix + "move.drag", null).on(_pointerPrefix + "up.drag pointercancel.drag", null);
+      return behavior;
+    };
+    behavior.targetNode = function(_) {
+      if (!arguments.length)
+        return _targetNode;
+      _targetNode = _;
+      return behavior;
+    };
+    behavior.targetEntity = function(_) {
+      if (!arguments.length)
+        return _targetEntity;
+      _targetEntity = _;
+      return behavior;
+    };
+    behavior.surface = function(_) {
+      if (!arguments.length)
+        return _surface;
+      _surface = _;
+      return behavior;
+    };
+    return utilRebind(behavior, dispatch10, "on");
   }
-  var defaults = getDefaults();
-  function changeDefaults(newDefaults) {
-    defaults = newDefaults;
-  }
-  var escapeTest = /[&<>"']/;
-  var escapeReplace = /[&<>"']/g;
-  var escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
-  var escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
-  var escapeReplacements = {
-    "&": "&amp;",
-    "<": "&lt;",
-    ">": "&gt;",
-    '"': "&quot;",
-    "'": "&#39;"
-  };
-  var getEscapeReplacement = (ch) => escapeReplacements[ch];
-  function escape4(html2, encode) {
-    if (encode) {
-      if (escapeTest.test(html2)) {
-        return html2.replace(escapeReplace, getEscapeReplacement);
-      }
-    } else {
-      if (escapeTestNoEncode.test(html2)) {
-        return html2.replace(escapeReplaceNoEncode, getEscapeReplacement);
-      }
-    }
-    return html2;
-  }
-  var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
-  function unescape3(html2) {
-    return html2.replace(unescapeTest, (_, n2) => {
-      n2 = n2.toLowerCase();
-      if (n2 === "colon")
-        return ":";
-      if (n2.charAt(0) === "#") {
-        return n2.charAt(1) === "x" ? String.fromCharCode(parseInt(n2.substring(2), 16)) : String.fromCharCode(+n2.substring(1));
-      }
-      return "";
-    });
-  }
-  var caret = /(^|[^\[])\^/g;
-  function edit(regex, opt) {
-    regex = typeof regex === "string" ? regex : regex.source;
-    opt = opt || "";
-    const obj = {
-      replace: (name, val) => {
-        val = val.source || val;
-        val = val.replace(caret, "$1");
-        regex = regex.replace(name, val);
-        return obj;
-      },
-      getRegex: () => {
-        return new RegExp(regex, opt);
-      }
+
+  // modules/modes/drag_node.js
+  function modeDragNode(context) {
+    var mode = {
+      id: "drag-node",
+      button: "browse"
     };
-    return obj;
-  }
-  var nonWordAndColonTest = /[^\w:]/g;
-  var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
-  function cleanUrl(sanitize, base, href) {
-    if (sanitize) {
-      let prot;
-      try {
-        prot = decodeURIComponent(unescape3(href)).replace(nonWordAndColonTest, "").toLowerCase();
-      } catch (e) {
-        return null;
+    var hover = behaviorHover(context).altDisables(true).on("hover", context.ui().sidebar.hover);
+    var edit2 = behaviorEdit(context);
+    var _nudgeInterval;
+    var _restoreSelectedIDs = [];
+    var _wasMidpoint = false;
+    var _isCancelled = false;
+    var _activeEntity;
+    var _startLoc;
+    var _lastLoc;
+    function startNudge(d3_event, entity, nudge) {
+      if (_nudgeInterval)
+        window.clearInterval(_nudgeInterval);
+      _nudgeInterval = window.setInterval(function() {
+        context.map().pan(nudge);
+        doMove(d3_event, entity, nudge);
+      }, 50);
+    }
+    function stopNudge() {
+      if (_nudgeInterval) {
+        window.clearInterval(_nudgeInterval);
+        _nudgeInterval = null;
       }
-      if (prot.indexOf("javascript:") === 0 || prot.indexOf("vbscript:") === 0 || prot.indexOf("data:") === 0) {
-        return null;
+    }
+    function moveAnnotation(entity) {
+      return _t("operations.move.annotation." + entity.geometry(context.graph()));
+    }
+    function connectAnnotation(nodeEntity, targetEntity) {
+      var nodeGeometry = nodeEntity.geometry(context.graph());
+      var targetGeometry = targetEntity.geometry(context.graph());
+      if (nodeGeometry === "vertex" && targetGeometry === "vertex") {
+        var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
+        var targetParentWayIDs = context.graph().parentWays(targetEntity);
+        var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs);
+        if (sharedParentWays.length !== 0) {
+          if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
+            return _t("operations.connect.annotation.from_vertex.to_adjacent_vertex");
+          }
+          return _t("operations.connect.annotation.from_vertex.to_sibling_vertex");
+        }
       }
+      return _t("operations.connect.annotation.from_" + nodeGeometry + ".to_" + targetGeometry);
     }
-    if (base && !originIndependentUrl.test(href)) {
-      href = resolveUrl(base, href);
+    function shouldSnapToNode(target) {
+      if (!_activeEntity)
+        return false;
+      return _activeEntity.geometry(context.graph()) !== "vertex" || (target.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(target, context.graph()));
     }
-    try {
-      href = encodeURI(href).replace(/%25/g, "%");
-    } catch (e) {
-      return null;
+    function origin(entity) {
+      return context.projection(entity.loc);
     }
-    return href;
-  }
-  var baseUrls = {};
-  var justDomain = /^[^:]+:\/*[^/]*$/;
-  var protocol = /^([^:]+:)[\s\S]*$/;
-  var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
-  function resolveUrl(base, href) {
-    if (!baseUrls[" " + base]) {
-      if (justDomain.test(base)) {
-        baseUrls[" " + base] = base + "/";
-      } else {
-        baseUrls[" " + base] = rtrim(base, "/", true);
+    function keydown(d3_event) {
+      if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
+        if (context.surface().classed("nope")) {
+          context.surface().classed("nope-suppressed", true);
+        }
+        context.surface().classed("nope", false).classed("nope-disabled", true);
       }
     }
-    base = baseUrls[" " + base];
-    const relativeBase = base.indexOf(":") === -1;
-    if (href.substring(0, 2) === "//") {
-      if (relativeBase) {
-        return href;
-      }
-      return base.replace(protocol, "$1") + href;
-    } else if (href.charAt(0) === "/") {
-      if (relativeBase) {
-        return href;
+    function keyup(d3_event) {
+      if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
+        if (context.surface().classed("nope-suppressed")) {
+          context.surface().classed("nope", true);
+        }
+        context.surface().classed("nope-suppressed", false).classed("nope-disabled", false);
       }
-      return base.replace(domain, "$1") + href;
-    } else {
-      return base + href;
     }
-  }
-  var noopTest = { exec: function noopTest2() {
-  } };
-  function merge2(obj) {
-    let i2 = 1, target, key;
-    for (; i2 < arguments.length; i2++) {
-      target = arguments[i2];
-      for (key in target) {
-        if (Object.prototype.hasOwnProperty.call(target, key)) {
-          obj[key] = target[key];
+    function start2(d3_event, entity) {
+      _wasMidpoint = entity.type === "midpoint";
+      var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
+      _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
+      if (_isCancelled) {
+        if (hasHidden) {
+          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append("modes.drag_node.connected_to_hidden"))();
         }
+        return drag.cancel();
       }
-    }
-    return obj;
-  }
-  function splitCells(tableRow, count) {
-    const row = tableRow.replace(/\|/g, (match, offset, str2) => {
-      let escaped = false, curr = offset;
-      while (--curr >= 0 && str2[curr] === "\\")
-        escaped = !escaped;
-      if (escaped) {
-        return "|";
+      if (_wasMidpoint) {
+        var midpoint = entity;
+        entity = osmNode();
+        context.perform(actionAddMidpoint(midpoint, entity));
+        entity = context.entity(entity.id);
+        var vertex = context.surface().selectAll("." + entity.id);
+        drag.targetNode(vertex.node()).targetEntity(entity);
       } else {
-        return " |";
+        context.perform(actionNoop());
       }
-    }), cells = row.split(/ \|/);
-    let i2 = 0;
-    if (!cells[0].trim()) {
-      cells.shift();
-    }
-    if (cells.length > 0 && !cells[cells.length - 1].trim()) {
-      cells.pop();
-    }
-    if (cells.length > count) {
-      cells.splice(count);
-    } else {
-      while (cells.length < count)
-        cells.push("");
-    }
-    for (; i2 < cells.length; i2++) {
-      cells[i2] = cells[i2].trim().replace(/\\\|/g, "|");
-    }
-    return cells;
-  }
-  function rtrim(str2, c, invert) {
-    const l = str2.length;
-    if (l === 0) {
-      return "";
+      _activeEntity = entity;
+      _startLoc = entity.loc;
+      hover.ignoreVertex(entity.geometry(context.graph()) === "vertex");
+      context.surface().selectAll("." + _activeEntity.id).classed("active", true);
+      context.enter(mode);
     }
-    let suffLen = 0;
-    while (suffLen < l) {
-      const currChar = str2.charAt(l - suffLen - 1);
-      if (currChar === c && !invert) {
-        suffLen++;
-      } else if (currChar !== c && invert) {
-        suffLen++;
+    function datum2(d3_event) {
+      if (!d3_event || d3_event.altKey) {
+        return {};
       } else {
-        break;
+        var d = d3_event.target.__data__;
+        return d && d.properties && d.properties.target ? d : {};
       }
     }
-    return str2.slice(0, l - suffLen);
-  }
-  function findClosingBracket(str2, b) {
-    if (str2.indexOf(b[1]) === -1) {
-      return -1;
-    }
-    const l = str2.length;
-    let level = 0, i2 = 0;
-    for (; i2 < l; i2++) {
-      if (str2[i2] === "\\") {
-        i2++;
-      } else if (str2[i2] === b[0]) {
-        level++;
-      } else if (str2[i2] === b[1]) {
-        level--;
-        if (level < 0) {
-          return i2;
+    function doMove(d3_event, entity, nudge) {
+      nudge = nudge || [0, 0];
+      var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
+      var currMouse = geoVecSubtract(currPoint, nudge);
+      var loc = context.projection.invert(currMouse);
+      var target, edge;
+      if (!_nudgeInterval) {
+        var d = datum2(d3_event);
+        target = d && d.properties && d.properties.entity;
+        var targetLoc = target && target.loc;
+        var targetNodes = d && d.properties && d.properties.nodes;
+        if (targetLoc) {
+          if (shouldSnapToNode(target)) {
+            loc = targetLoc;
+          }
+        } else if (targetNodes) {
+          edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
+          if (edge) {
+            loc = edge.loc;
+          }
         }
       }
-    }
-    return -1;
-  }
-  function checkSanitizeDeprecation(opt) {
-    if (opt && opt.sanitize && !opt.silent) {
-      console.warn("marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options");
-    }
-  }
-  function repeatString(pattern, count) {
-    if (count < 1) {
-      return "";
-    }
-    let result = "";
-    while (count > 1) {
-      if (count & 1) {
-        result += pattern;
-      }
-      count >>= 1;
-      pattern += pattern;
-    }
-    return result + pattern;
-  }
-  function outputLink(cap, link2, raw, lexer2) {
-    const href = link2.href;
-    const title = link2.title ? escape4(link2.title) : null;
-    const text2 = cap[1].replace(/\\([\[\]])/g, "$1");
-    if (cap[0].charAt(0) !== "!") {
-      lexer2.state.inLink = true;
-      const token = {
-        type: "link",
-        raw,
-        href,
-        title,
-        text: text2,
-        tokens: lexer2.inlineTokens(text2)
-      };
-      lexer2.state.inLink = false;
-      return token;
-    }
-    return {
-      type: "image",
-      raw,
-      href,
-      title,
-      text: escape4(text2)
-    };
-  }
-  function indentCodeCompensation(raw, text2) {
-    const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
-    if (matchIndentToCode === null) {
-      return text2;
-    }
-    const indentToCode = matchIndentToCode[1];
-    return text2.split("\n").map((node) => {
-      const matchIndentInNode = node.match(/^\s+/);
-      if (matchIndentInNode === null) {
-        return node;
+      context.replace(
+        actionMoveNode(entity.id, loc)
+      );
+      var isInvalid = false;
+      if (target) {
+        isInvalid = hasRelationConflict(entity, target, edge, context.graph());
       }
-      const [indentInNode] = matchIndentInNode;
-      if (indentInNode.length >= indentToCode.length) {
-        return node.slice(indentToCode.length);
+      if (!isInvalid) {
+        isInvalid = hasInvalidGeometry(entity, context.graph());
       }
-      return node;
-    }).join("\n");
-  }
-  var Tokenizer = class {
-    constructor(options2) {
-      this.options = options2 || defaults;
-    }
-    space(src) {
-      const cap = this.rules.block.newline.exec(src);
-      if (cap && cap[0].length > 0) {
-        return {
-          type: "space",
-          raw: cap[0]
-        };
+      var nope = context.surface().classed("nope");
+      if (isInvalid === "relation" || isInvalid === "restriction") {
+        if (!nope) {
+          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append(
+            "operations.connect." + isInvalid,
+            { relation: _mainPresetIndex.item("type/restriction").name() }
+          ))();
+        }
+      } else if (isInvalid) {
+        var errorID = isInvalid === "line" ? "lines" : "areas";
+        context.ui().flash.duration(3e3).iconName("#iD-icon-no").label(_t.append("self_intersection.error." + errorID))();
+      } else {
+        if (nope) {
+          context.ui().flash.duration(1).label("")();
+        }
       }
-    }
-    code(src) {
-      const cap = this.rules.block.code.exec(src);
-      if (cap) {
-        const text2 = cap[0].replace(/^ {1,4}/gm, "");
-        return {
-          type: "code",
-          raw: cap[0],
-          codeBlockStyle: "indented",
-          text: !this.options.pedantic ? rtrim(text2, "\n") : text2
-        };
+      var nopeDisabled = context.surface().classed("nope-disabled");
+      if (nopeDisabled) {
+        context.surface().classed("nope", false).classed("nope-suppressed", isInvalid);
+      } else {
+        context.surface().classed("nope", isInvalid).classed("nope-suppressed", false);
       }
+      _lastLoc = loc;
     }
-    fences(src) {
-      const cap = this.rules.block.fences.exec(src);
-      if (cap) {
-        const raw = cap[0];
-        const text2 = indentCodeCompensation(raw, cap[3] || "");
-        return {
-          type: "code",
-          raw,
-          lang: cap[2] ? cap[2].trim() : cap[2],
-          text: text2
-        };
+    function hasRelationConflict(entity, target, edge, graph) {
+      var testGraph = graph.update();
+      if (edge) {
+        var midpoint = osmNode();
+        var action = actionAddMidpoint({
+          loc: edge.loc,
+          edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
+        }, midpoint);
+        testGraph = action(testGraph);
+        target = midpoint;
       }
+      var ids = [entity.id, target.id];
+      return actionConnect(ids).disabled(testGraph);
     }
-    heading(src) {
-      const cap = this.rules.block.heading.exec(src);
-      if (cap) {
-        let text2 = cap[2].trim();
-        if (/#$/.test(text2)) {
-          const trimmed = rtrim(text2, "#");
-          if (this.options.pedantic) {
-            text2 = trimmed.trim();
-          } else if (!trimmed || / $/.test(trimmed)) {
-            text2 = trimmed.trim();
+    function hasInvalidGeometry(entity, graph) {
+      var parents = graph.parentWays(entity);
+      var i2, j2, k;
+      for (i2 = 0; i2 < parents.length; i2++) {
+        var parent = parents[i2];
+        var nodes = [];
+        var activeIndex = null;
+        var relations = graph.parentRelations(parent);
+        for (j2 = 0; j2 < relations.length; j2++) {
+          if (!relations[j2].isMultipolygon())
+            continue;
+          var rings = osmJoinWays(relations[j2].members, graph);
+          for (k = 0; k < rings.length; k++) {
+            nodes = rings[k].nodes;
+            if (nodes.find(function(n2) {
+              return n2.id === entity.id;
+            })) {
+              activeIndex = k;
+              if (geoHasSelfIntersections(nodes, entity.id)) {
+                return "multipolygonMember";
+              }
+            }
+            rings[k].coords = nodes.map(function(n2) {
+              return n2.loc;
+            });
+          }
+          for (k = 0; k < rings.length; k++) {
+            if (k === activeIndex)
+              continue;
+            if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
+              return "multipolygonRing";
+            }
+          }
+        }
+        if (activeIndex === null) {
+          nodes = parent.nodes.map(function(nodeID) {
+            return graph.entity(nodeID);
+          });
+          if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
+            return parent.geometry(graph);
           }
         }
-        return {
-          type: "heading",
-          raw: cap[0],
-          depth: cap[1].length,
-          text: text2,
-          tokens: this.lexer.inline(text2)
-        };
       }
+      return false;
     }
-    hr(src) {
-      const cap = this.rules.block.hr.exec(src);
-      if (cap) {
-        return {
-          type: "hr",
-          raw: cap[0]
-        };
+    function move(d3_event, entity, point2) {
+      if (_isCancelled)
+        return;
+      d3_event.stopPropagation();
+      context.surface().classed("nope-disabled", d3_event.altKey);
+      _lastLoc = context.projection.invert(point2);
+      doMove(d3_event, entity);
+      var nudge = geoViewportEdge(point2, context.map().dimensions());
+      if (nudge) {
+        startNudge(d3_event, entity, nudge);
+      } else {
+        stopNudge();
       }
     }
-    blockquote(src) {
-      const cap = this.rules.block.blockquote.exec(src);
-      if (cap) {
-        const text2 = cap[0].replace(/^ *>[ \t]?/gm, "");
-        return {
-          type: "blockquote",
-          raw: cap[0],
-          tokens: this.lexer.blockTokens(text2, []),
-          text: text2
-        };
+    function end(d3_event, entity) {
+      if (_isCancelled)
+        return;
+      var wasPoint = entity.geometry(context.graph()) === "point";
+      var d = datum2(d3_event);
+      var nope = d && d.properties && d.properties.nope || context.surface().classed("nope");
+      var target = d && d.properties && d.properties.entity;
+      if (nope) {
+        context.perform(
+          _actionBounceBack(entity.id, _startLoc)
+        );
+      } else if (target && target.type === "way") {
+        var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
+        context.replace(
+          actionAddMidpoint({
+            loc: choice.loc,
+            edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
+          }, entity),
+          connectAnnotation(entity, target)
+        );
+      } else if (target && target.type === "node" && shouldSnapToNode(target)) {
+        context.replace(
+          actionConnect([target.id, entity.id]),
+          connectAnnotation(entity, target)
+        );
+      } else if (_wasMidpoint) {
+        context.replace(
+          actionNoop(),
+          _t("operations.add.annotation.vertex")
+        );
+      } else {
+        context.replace(
+          actionNoop(),
+          moveAnnotation(entity)
+        );
       }
-    }
-    list(src) {
-      let cap = this.rules.block.list.exec(src);
-      if (cap) {
-        let raw, istask, ischecked, indent2, i2, blankLine, endsWithBlankLine, line, nextLine, rawLine, itemContents, endEarly;
-        let bull = cap[1].trim();
-        const isordered = bull.length > 1;
-        const list = {
-          type: "list",
-          raw: "",
-          ordered: isordered,
-          start: isordered ? +bull.slice(0, -1) : "",
-          loose: false,
-          items: []
-        };
-        bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
-        if (this.options.pedantic) {
-          bull = isordered ? bull : "[*+-]";
-        }
-        const itemRegex = new RegExp(`^( {0,3}${bull})((?:[     ][^\\n]*)?(?:\\n|$))`);
-        while (src) {
-          endEarly = false;
-          if (!(cap = itemRegex.exec(src))) {
-            break;
-          }
-          if (this.rules.block.hr.test(src)) {
-            break;
-          }
-          raw = cap[0];
-          src = src.substring(raw.length);
-          line = cap[2].split("\n", 1)[0];
-          nextLine = src.split("\n", 1)[0];
-          if (this.options.pedantic) {
-            indent2 = 2;
-            itemContents = line.trimLeft();
-          } else {
-            indent2 = cap[2].search(/[^ ]/);
-            indent2 = indent2 > 4 ? 1 : indent2;
-            itemContents = line.slice(indent2);
-            indent2 += cap[1].length;
-          }
-          blankLine = false;
-          if (!line && /^ *$/.test(nextLine)) {
-            raw += nextLine + "\n";
-            src = src.substring(nextLine.length + 1);
-            endEarly = true;
-          }
-          if (!endEarly) {
-            const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent2 - 1)}}(?:[*+-]|\\d{1,9}[.)])((?: [^\\n]*)?(?:\\n|$))`);
-            const hrRegex = new RegExp(`^ {0,${Math.min(3, indent2 - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
-            const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent2 - 1)}}(?:\`\`\`|~~~)`);
-            const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent2 - 1)}}#`);
-            while (src) {
-              rawLine = src.split("\n", 1)[0];
-              line = rawLine;
-              if (this.options.pedantic) {
-                line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, "  ");
-              }
-              if (fencesBeginRegex.test(line)) {
-                break;
-              }
-              if (headingBeginRegex.test(line)) {
-                break;
-              }
-              if (nextBulletRegex.test(line)) {
-                break;
-              }
-              if (hrRegex.test(src)) {
-                break;
-              }
-              if (line.search(/[^ ]/) >= indent2 || !line.trim()) {
-                itemContents += "\n" + line.slice(indent2);
-              } else if (!blankLine) {
-                itemContents += "\n" + line;
-              } else {
-                break;
-              }
-              if (!blankLine && !line.trim()) {
-                blankLine = true;
-              }
-              raw += rawLine + "\n";
-              src = src.substring(rawLine.length + 1);
-            }
-          }
-          if (!list.loose) {
-            if (endsWithBlankLine) {
-              list.loose = true;
-            } else if (/\n *\n *$/.test(raw)) {
-              endsWithBlankLine = true;
-            }
-          }
-          if (this.options.gfm) {
-            istask = /^\[[ xX]\] /.exec(itemContents);
-            if (istask) {
-              ischecked = istask[0] !== "[ ] ";
-              itemContents = itemContents.replace(/^\[[ xX]\] +/, "");
-            }
-          }
-          list.items.push({
-            type: "list_item",
-            raw,
-            task: !!istask,
-            checked: ischecked,
-            loose: false,
-            text: itemContents
-          });
-          list.raw += raw;
-        }
-        list.items[list.items.length - 1].raw = raw.trimRight();
-        list.items[list.items.length - 1].text = itemContents.trimRight();
-        list.raw = list.raw.trimRight();
-        const l = list.items.length;
-        for (i2 = 0; i2 < l; i2++) {
-          this.lexer.state.top = false;
-          list.items[i2].tokens = this.lexer.blockTokens(list.items[i2].text, []);
-          const spacers = list.items[i2].tokens.filter((t) => t.type === "space");
-          const hasMultipleLineBreaks = spacers.every((t) => {
-            const chars = t.raw.split("");
-            let lineBreaks = 0;
-            for (const char of chars) {
-              if (char === "\n") {
-                lineBreaks += 1;
-              }
-              if (lineBreaks > 1) {
-                return true;
-              }
-            }
-            return false;
-          });
-          if (!list.loose && spacers.length && hasMultipleLineBreaks) {
-            list.loose = true;
-            list.items[i2].loose = true;
-          }
-        }
-        return list;
-      }
-    }
-    html(src) {
-      const cap = this.rules.block.html.exec(src);
-      if (cap) {
-        const token = {
-          type: "html",
-          raw: cap[0],
-          pre: !this.options.sanitizer && (cap[1] === "pre" || cap[1] === "script" || cap[1] === "style"),
-          text: cap[0]
-        };
-        if (this.options.sanitize) {
-          const text2 = this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape4(cap[0]);
-          token.type = "paragraph";
-          token.text = text2;
-          token.tokens = this.lexer.inline(text2);
+      if (wasPoint) {
+        context.enter(modeSelect(context, [entity.id]));
+      } else {
+        var reselection = _restoreSelectedIDs.filter(function(id2) {
+          return context.graph().hasEntity(id2);
+        });
+        if (reselection.length) {
+          context.enter(modeSelect(context, reselection));
+        } else {
+          context.enter(modeBrowse(context));
         }
-        return token;
-      }
-    }
-    def(src) {
-      const cap = this.rules.block.def.exec(src);
-      if (cap) {
-        if (cap[3])
-          cap[3] = cap[3].substring(1, cap[3].length - 1);
-        const tag = cap[1].toLowerCase().replace(/\s+/g, " ");
-        return {
-          type: "def",
-          tag,
-          raw: cap[0],
-          href: cap[2],
-          title: cap[3]
-        };
       }
     }
-    table(src) {
-      const cap = this.rules.block.table.exec(src);
-      if (cap) {
-        const item = {
-          type: "table",
-          header: splitCells(cap[1]).map((c) => {
-            return { text: c };
-          }),
-          align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
-          rows: cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, "").split("\n") : []
-        };
-        if (item.header.length === item.align.length) {
-          item.raw = cap[0];
-          let l = item.align.length;
-          let i2, j2, k, row;
-          for (i2 = 0; i2 < l; i2++) {
-            if (/^ *-+: *$/.test(item.align[i2])) {
-              item.align[i2] = "right";
-            } else if (/^ *:-+: *$/.test(item.align[i2])) {
-              item.align[i2] = "center";
-            } else if (/^ *:-+ *$/.test(item.align[i2])) {
-              item.align[i2] = "left";
-            } else {
-              item.align[i2] = null;
-            }
-          }
-          l = item.rows.length;
-          for (i2 = 0; i2 < l; i2++) {
-            item.rows[i2] = splitCells(item.rows[i2], item.header.length).map((c) => {
-              return { text: c };
-            });
-          }
-          l = item.header.length;
-          for (j2 = 0; j2 < l; j2++) {
-            item.header[j2].tokens = this.lexer.inline(item.header[j2].text);
-          }
-          l = item.rows.length;
-          for (j2 = 0; j2 < l; j2++) {
-            row = item.rows[j2];
-            for (k = 0; k < row.length; k++) {
-              row[k].tokens = this.lexer.inline(row[k].text);
-            }
-          }
-          return item;
-        }
-      }
+    function _actionBounceBack(nodeID, toLoc) {
+      var moveNode = actionMoveNode(nodeID, toLoc);
+      var action = function(graph, t) {
+        if (t === 1)
+          context.pop();
+        return moveNode(graph, t);
+      };
+      action.transitionable = true;
+      return action;
     }
-    lheading(src) {
-      const cap = this.rules.block.lheading.exec(src);
-      if (cap) {
-        return {
-          type: "heading",
-          raw: cap[0],
-          depth: cap[2].charAt(0) === "=" ? 1 : 2,
-          text: cap[1],
-          tokens: this.lexer.inline(cap[1])
-        };
-      }
+    function cancel() {
+      drag.cancel();
+      context.enter(modeBrowse(context));
     }
-    paragraph(src) {
-      const cap = this.rules.block.paragraph.exec(src);
-      if (cap) {
-        const text2 = cap[1].charAt(cap[1].length - 1) === "\n" ? cap[1].slice(0, -1) : cap[1];
-        return {
-          type: "paragraph",
-          raw: cap[0],
-          text: text2,
-          tokens: this.lexer.inline(text2)
-        };
-      }
+    var drag = behaviorDrag().selector(".layer-touch.points .target").surface(context.container().select(".main-map").node()).origin(origin).on("start", start2).on("move", move).on("end", end);
+    mode.enter = function() {
+      context.install(hover);
+      context.install(edit2);
+      select_default2(window).on("keydown.dragNode", keydown).on("keyup.dragNode", keyup);
+      context.history().on("undone.drag-node", cancel);
+    };
+    mode.exit = function() {
+      context.ui().sidebar.hover.cancel();
+      context.uninstall(hover);
+      context.uninstall(edit2);
+      select_default2(window).on("keydown.dragNode", null).on("keyup.dragNode", null);
+      context.history().on("undone.drag-node", null);
+      _activeEntity = null;
+      context.surface().classed("nope", false).classed("nope-suppressed", false).classed("nope-disabled", false).selectAll(".active").classed("active", false);
+      stopNudge();
+    };
+    mode.selectedIDs = function() {
+      if (!arguments.length)
+        return _activeEntity ? [_activeEntity.id] : [];
+      return mode;
+    };
+    mode.activeID = function() {
+      if (!arguments.length)
+        return _activeEntity && _activeEntity.id;
+      return mode;
+    };
+    mode.restoreSelectedIDs = function(_) {
+      if (!arguments.length)
+        return _restoreSelectedIDs;
+      _restoreSelectedIDs = _;
+      return mode;
+    };
+    mode.behavior = drag;
+    return mode;
+  }
+
+  // modules/services/keepRight.js
+  var import_rbush = __toESM(require_rbush_min());
+
+  // node_modules/d3-fetch/src/text.js
+  function responseText(response) {
+    if (!response.ok)
+      throw new Error(response.status + " " + response.statusText);
+    return response.text();
+  }
+  function text_default3(input, init2) {
+    return fetch(input, init2).then(responseText);
+  }
+
+  // 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;
+    return response.json();
+  }
+  function json_default(input, init2) {
+    return fetch(input, init2).then(responseJson);
+  }
+
+  // node_modules/d3-fetch/src/xml.js
+  function parser(type2) {
+    return (input, init2) => text_default3(input, init2).then((text2) => new DOMParser().parseFromString(text2, type2));
+  }
+  var xml_default = parser("application/xml");
+  var html = parser("text/html");
+  var svg = parser("image/svg+xml");
+
+  // modules/services/keepRight.js
+  var tiler = utilTiler();
+  var dispatch2 = dispatch_default("loaded");
+  var _tileZoom = 14;
+  var _krUrlRoot = "https://www.keepright.at";
+  var _krData = { errorTypes: {}, localizeStrings: {} };
+  var _cache;
+  var _krRuleset = [
+    // no 20 - multiple node on same spot - these are mostly boundaries overlapping roads
+    30,
+    40,
+    50,
+    60,
+    70,
+    90,
+    100,
+    110,
+    120,
+    130,
+    150,
+    160,
+    170,
+    180,
+    190,
+    191,
+    192,
+    193,
+    194,
+    195,
+    196,
+    197,
+    198,
+    200,
+    201,
+    202,
+    203,
+    204,
+    205,
+    206,
+    207,
+    208,
+    210,
+    220,
+    230,
+    231,
+    232,
+    270,
+    280,
+    281,
+    282,
+    283,
+    284,
+    285,
+    290,
+    291,
+    292,
+    293,
+    294,
+    295,
+    296,
+    297,
+    298,
+    300,
+    310,
+    311,
+    312,
+    313,
+    320,
+    350,
+    360,
+    370,
+    380,
+    390,
+    400,
+    401,
+    402,
+    410,
+    411,
+    412,
+    413
+  ];
+  function abortRequest(controller) {
+    if (controller) {
+      controller.abort();
     }
-    text(src) {
-      const cap = this.rules.block.text.exec(src);
-      if (cap) {
-        return {
-          type: "text",
-          raw: cap[0],
-          text: cap[0],
-          tokens: this.lexer.inline(cap[0])
-        };
+  }
+  function abortUnwantedRequests(cache, tiles) {
+    Object.keys(cache.inflightTile).forEach((k) => {
+      const wanted = tiles.find((tile) => k === tile.id);
+      if (!wanted) {
+        abortRequest(cache.inflightTile[k]);
+        delete cache.inflightTile[k];
       }
+    });
+  }
+  function encodeIssueRtree(d) {
+    return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
+  }
+  function updateRtree(item, replace) {
+    _cache.rtree.remove(item, (a, b) => a.data.id === b.data.id);
+    if (replace) {
+      _cache.rtree.insert(item);
     }
-    escape(src) {
-      const cap = this.rules.inline.escape.exec(src);
-      if (cap) {
-        return {
-          type: "escape",
-          raw: cap[0],
-          text: escape4(cap[1])
-        };
-      }
+  }
+  function tokenReplacements(d) {
+    if (!(d instanceof QAItem))
+      return;
+    const replacements = {};
+    const issueTemplate = _krData.errorTypes[d.whichType];
+    if (!issueTemplate) {
+      console.log("No Template: ", d.whichType);
+      console.log("  ", d.description);
+      return;
     }
-    tag(src) {
-      const cap = this.rules.inline.tag.exec(src);
-      if (cap) {
-        if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
-          this.lexer.state.inLink = true;
-        } else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
-          this.lexer.state.inLink = false;
-        }
-        if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
-          this.lexer.state.inRawBlock = true;
-        } else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
-          this.lexer.state.inRawBlock = false;
-        }
-        return {
-          type: this.options.sanitize ? "text" : "html",
-          raw: cap[0],
-          inLink: this.lexer.state.inLink,
-          inRawBlock: this.lexer.state.inRawBlock,
-          text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape4(cap[0]) : cap[0]
-        };
-      }
+    if (!issueTemplate.regex)
+      return;
+    const errorRegex = new RegExp(issueTemplate.regex, "i");
+    const errorMatch = errorRegex.exec(d.description);
+    if (!errorMatch) {
+      console.log("Unmatched: ", d.whichType);
+      console.log("  ", d.description);
+      console.log("  ", errorRegex);
+      return;
     }
-    link(src) {
-      const cap = this.rules.inline.link.exec(src);
-      if (cap) {
-        const trimmedUrl = cap[2].trim();
-        if (!this.options.pedantic && /^</.test(trimmedUrl)) {
-          if (!/>$/.test(trimmedUrl)) {
-            return;
-          }
-          const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), "\\");
-          if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
-            return;
-          }
-        } else {
-          const lastParenIndex = findClosingBracket(cap[2], "()");
-          if (lastParenIndex > -1) {
-            const start2 = cap[0].indexOf("!") === 0 ? 5 : 4;
-            const linkLen = start2 + cap[1].length + lastParenIndex;
-            cap[2] = cap[2].substring(0, lastParenIndex);
-            cap[0] = cap[0].substring(0, linkLen).trim();
-            cap[3] = "";
-          }
-        }
-        let href = cap[2];
-        let title = "";
-        if (this.options.pedantic) {
-          const link2 = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
-          if (link2) {
-            href = link2[1];
-            title = link2[3];
-          }
+    for (let i2 = 1; i2 < errorMatch.length; i2++) {
+      let capture = errorMatch[i2];
+      let idType;
+      idType = "IDs" in issueTemplate ? issueTemplate.IDs[i2 - 1] : "";
+      if (idType && capture) {
+        capture = parseError(capture, idType);
+      } else {
+        const compare = capture.toLowerCase();
+        if (_krData.localizeStrings[compare]) {
+          capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare]);
         } else {
-          title = cap[3] ? cap[3].slice(1, -1) : "";
-        }
-        href = href.trim();
-        if (/^</.test(href)) {
-          if (this.options.pedantic && !/>$/.test(trimmedUrl)) {
-            href = href.slice(1);
-          } else {
-            href = href.slice(1, -1);
-          }
+          capture = unescape_default(capture);
         }
-        return outputLink(cap, {
-          href: href ? href.replace(this.rules.inline._escapes, "$1") : href,
-          title: title ? title.replace(this.rules.inline._escapes, "$1") : title
-        }, cap[0], this.lexer);
       }
+      replacements["var" + i2] = capture;
     }
-    reflink(src, links) {
-      let cap;
-      if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
-        let link2 = (cap[2] || cap[1]).replace(/\s+/g, " ");
-        link2 = links[link2.toLowerCase()];
-        if (!link2 || !link2.href) {
-          const text2 = cap[0].charAt(0);
-          return {
-            type: "text",
-            raw: text2,
-            text: text2
-          };
-        }
-        return outputLink(cap, link2, cap[0], this.lexer);
-      }
+    return replacements;
+  }
+  function parseError(capture, idType) {
+    const compare = capture.toLowerCase();
+    if (_krData.localizeStrings[compare]) {
+      capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare]);
     }
-    emStrong(src, maskedSrc, prevChar = "") {
-      let match = this.rules.inline.emStrong.lDelim.exec(src);
-      if (!match)
-        return;
-      if (match[3] && prevChar.match(/[\p{L}\p{N}]/u))
-        return;
-      const nextChar = match[1] || match[2] || "";
-      if (!nextChar || nextChar && (prevChar === "" || this.rules.inline.punctuation.exec(prevChar))) {
-        const lLength = match[0].length - 1;
-        let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
-        const endReg = match[0][0] === "*" ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
-        endReg.lastIndex = 0;
-        maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
-        while ((match = endReg.exec(maskedSrc)) != null) {
-          rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
-          if (!rDelim)
-            continue;
-          rLength = rDelim.length;
-          if (match[3] || match[4]) {
-            delimTotal += rLength;
-            continue;
-          } else if (match[5] || match[6]) {
-            if (lLength % 3 && !((lLength + rLength) % 3)) {
-              midDelimTotal += rLength;
-              continue;
-            }
-          }
-          delimTotal -= rLength;
-          if (delimTotal > 0)
-            continue;
-          rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
-          if (Math.min(lLength, rLength) % 2) {
-            const text3 = src.slice(1, lLength + match.index + rLength);
-            return {
-              type: "em",
-              raw: src.slice(0, lLength + match.index + rLength + 1),
-              text: text3,
-              tokens: this.lexer.inlineTokens(text3)
-            };
-          }
-          const text2 = src.slice(2, lLength + match.index + rLength - 1);
-          return {
-            type: "strong",
-            raw: src.slice(0, lLength + match.index + rLength + 1),
-            text: text2,
-            tokens: this.lexer.inlineTokens(text2)
-          };
-        }
-      }
+    switch (idType) {
+      case "this":
+        capture = linkErrorObject2(capture);
+        break;
+      case "url":
+        capture = linkURL(capture);
+        break;
+      case "n":
+      case "w":
+      case "r":
+        capture = linkEntity2(idType + capture);
+        break;
+      case "20":
+        capture = parse20(capture);
+        break;
+      case "211":
+        capture = parse211(capture);
+        break;
+      case "231":
+        capture = parse231(capture);
+        break;
+      case "294":
+        capture = parse294(capture);
+        break;
+      case "370":
+        capture = parse370(capture);
+        break;
     }
-    codespan(src) {
-      const cap = this.rules.inline.code.exec(src);
-      if (cap) {
-        let text2 = cap[2].replace(/\n/g, " ");
-        const hasNonSpaceChars = /[^ ]/.test(text2);
-        const hasSpaceCharsOnBothEnds = /^ /.test(text2) && / $/.test(text2);
-        if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
-          text2 = text2.substring(1, text2.length - 1);
-        }
-        text2 = escape4(text2, true);
-        return {
-          type: "codespan",
-          raw: cap[0],
-          text: text2
-        };
-      }
+    return capture;
+    function linkErrorObject2(d) {
+      return { html: `<a class="error_object_link">${d}</a>` };
     }
-    br(src) {
-      const cap = this.rules.inline.br.exec(src);
-      if (cap) {
-        return {
-          type: "br",
-          raw: cap[0]
-        };
-      }
+    function linkEntity2(d) {
+      return { html: `<a class="error_entity_link">${d}</a>` };
     }
-    del(src) {
-      const cap = this.rules.inline.del.exec(src);
-      if (cap) {
-        return {
-          type: "del",
-          raw: cap[0],
-          text: cap[2],
-          tokens: this.lexer.inlineTokens(cap[2])
-        };
-      }
+    function linkURL(d) {
+      return { html: `<a class="kr_external_link" target="_blank" href="${d}">${d}</a>` };
     }
-    autolink(src, mangle2) {
-      const cap = this.rules.inline.autolink.exec(src);
-      if (cap) {
-        let text2, href;
-        if (cap[2] === "@") {
-          text2 = escape4(this.options.mangle ? mangle2(cap[1]) : cap[1]);
-          href = "mailto:" + text2;
-        } else {
-          text2 = escape4(cap[1]);
-          href = text2;
+    function parse211(capture2) {
+      let newList = [];
+      const items = capture2.split(", ");
+      items.forEach((item) => {
+        let id2 = linkEntity2("n" + item.slice(1));
+        newList.push(id2);
+      });
+      return newList.join(", ");
+    }
+    function parse231(capture2) {
+      let newList = [];
+      const items = capture2.split("),");
+      items.forEach((item) => {
+        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] })
+          );
         }
-        return {
-          type: "link",
-          raw: cap[0],
-          text: text2,
-          href,
-          tokens: [
-            {
-              type: "text",
-              raw: text2,
-              text: text2
-            }
-          ]
-        };
+      });
+      return newList.join(", ");
+    }
+    function parse294(capture2) {
+      let newList = [];
+      const items = capture2.split(",");
+      items.forEach((item) => {
+        item = item.split(" ");
+        const role = `"${item[0]}"`;
+        const idType2 = item[1].slice(0, 1);
+        let id2 = item[2].slice(1);
+        id2 = linkEntity2(idType2 + id2);
+        newList.push(`${role} ${item[1]} ${id2}`);
+      });
+      return newList.join(", ");
+    }
+    function parse370(capture2) {
+      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] });
       }
+      return "";
     }
-    url(src, mangle2) {
-      let cap;
-      if (cap = this.rules.inline.url.exec(src)) {
-        let text2, href;
-        if (cap[2] === "@") {
-          text2 = escape4(this.options.mangle ? mangle2(cap[0]) : cap[0]);
-          href = "mailto:" + text2;
-        } else {
-          let prevCapZero;
-          do {
-            prevCapZero = cap[0];
-            cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
-          } while (prevCapZero !== cap[0]);
-          text2 = escape4(cap[0]);
-          if (cap[1] === "www.") {
-            href = "http://" + text2;
-          } else {
-            href = text2;
+    function parse20(capture2) {
+      let newList = [];
+      const items = capture2.split(",");
+      items.forEach((item) => {
+        const id2 = linkEntity2("n" + item.slice(1));
+        newList.push(id2);
+      });
+      return newList.join(", ");
+    }
+  }
+  var keepRight_default = {
+    title: "keepRight",
+    init() {
+      _mainFileFetcher.get("keepRight").then((d) => _krData = d);
+      if (!_cache) {
+        this.reset();
+      }
+      this.event = utilRebind(this, dispatch2, "on");
+    },
+    reset() {
+      if (_cache) {
+        Object.values(_cache.inflightTile).forEach(abortRequest);
+      }
+      _cache = {
+        data: {},
+        loadedTile: {},
+        inflightTile: {},
+        inflightPost: {},
+        closed: {},
+        rtree: new import_rbush.default()
+      };
+    },
+    // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
+    loadIssues(projection2) {
+      const options2 = {
+        format: "geojson",
+        ch: _krRuleset
+      };
+      const tiles = tiler.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection2);
+      abortUnwantedRequests(_cache, tiles);
+      tiles.forEach((tile) => {
+        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 = `${_krUrlRoot}/export.php?` + utilQsString(params);
+        const controller = new AbortController();
+        _cache.inflightTile[tile.id] = controller;
+        json_default(url, { signal: controller.signal }).then((data) => {
+          delete _cache.inflightTile[tile.id];
+          _cache.loadedTile[tile.id] = true;
+          if (!data || !data.features || !data.features.length) {
+            throw new Error("No Data");
           }
-        }
-        return {
-          type: "link",
-          raw: cap[0],
-          text: text2,
-          href,
-          tokens: [
-            {
-              type: "text",
-              raw: text2,
-              text: text2
+          data.features.forEach((feature3) => {
+            const {
+              properties: {
+                error_type: itemType,
+                error_id: id2,
+                comment = null,
+                object_id: objectId,
+                object_type: objectType,
+                schema,
+                title
+              }
+            } = feature3;
+            let {
+              geometry: { coordinates: loc },
+              properties: { description = "" }
+            } = feature3;
+            const issueTemplate = _krData.errorTypes[itemType];
+            const parentIssueType = (Math.floor(itemType / 10) * 10).toString();
+            const whichType = issueTemplate ? itemType : parentIssueType;
+            const whichTemplate = _krData.errorTypes[whichType];
+            switch (whichType) {
+              case "170":
+                description = `This feature has a FIXME tag: ${description}`;
+                break;
+              case "292":
+              case "293":
+                description = description.replace("A turn-", "This turn-");
+                break;
+              case "294":
+              case "295":
+              case "296":
+              case "297":
+              case "298":
+                description = `This turn-restriction~${description}`;
+                break;
+              case "300":
+                description = "This highway is missing a maxspeed tag";
+                break;
+              case "411":
+              case "412":
+              case "413":
+                description = `This feature~${description}`;
+                break;
             }
-          ]
-        };
+            let coincident = false;
+            do {
+              let delta = coincident ? [1e-5, 0] : [0, 1e-5];
+              loc = geoVecAdd(loc, delta);
+              let bbox2 = geoExtent(loc).bbox();
+              coincident = _cache.rtree.search(bbox2).length;
+            } while (coincident);
+            let d = new QAItem(loc, this, itemType, id2, {
+              comment,
+              description,
+              whichType,
+              parentIssueType,
+              severity: whichTemplate.severity || "error",
+              objectId,
+              objectType,
+              schema,
+              title
+            });
+            d.replacements = tokenReplacements(d);
+            _cache.data[id2] = d;
+            _cache.rtree.insert(encodeIssueRtree(d));
+          });
+          dispatch2.call("loaded");
+        }).catch(() => {
+          delete _cache.inflightTile[tile.id];
+          _cache.loadedTile[tile.id] = true;
+        });
+      });
+    },
+    postUpdate(d, callback) {
+      if (_cache.inflightPost[d.id]) {
+        return callback({ message: "Error update already inflight", status: -2 }, d);
       }
-    }
-    inlineText(src, smartypants2) {
-      const cap = this.rules.inline.text.exec(src);
-      if (cap) {
-        let text2;
-        if (this.lexer.state.inRawBlock) {
-          text2 = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape4(cap[0]) : cap[0];
+      const params = { schema: d.schema, id: d.id };
+      if (d.newStatus) {
+        params.st = d.newStatus;
+      }
+      if (d.newComment !== void 0) {
+        params.co = d.newComment;
+      }
+      const url = `${_krUrlRoot}/comment.php?` + utilQsString(params);
+      const controller = new AbortController();
+      _cache.inflightPost[d.id] = controller;
+      json_default(url, { signal: controller.signal }).finally(() => {
+        delete _cache.inflightPost[d.id];
+        if (d.newStatus === "ignore") {
+          this.removeItem(d);
+        } else if (d.newStatus === "ignore_t") {
+          this.removeItem(d);
+          _cache.closed[`${d.schema}:${d.id}`] = true;
         } else {
-          text2 = escape4(this.options.smartypants ? smartypants2(cap[0]) : cap[0]);
+          d = this.replaceItem(d.update({
+            comment: d.newComment,
+            newComment: void 0,
+            newState: void 0
+          }));
         }
-        return {
-          type: "text",
-          raw: cap[0],
-          text: text2
-        };
-      }
-    }
-  };
-  var block = {
-    newline: /^(?: *(?:\n|$))+/,
-    code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
-    fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
-    hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
-    heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
-    blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
-    list: /^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/,
-    html: "^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))",
-    def: /^ {0,3}\[(label)\]: *(?:\n *)?<?([^\s>]+)>?(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,
-    table: noopTest,
-    lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
-    _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
-    text: /^[^\n]+/
-  };
-  block._label = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
-  block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
-  block.def = edit(block.def).replace("label", block._label).replace("title", block._title).getRegex();
-  block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
-  block.listItemStart = edit(/^( *)(bull) */).replace("bull", block.bullet).getRegex();
-  block.list = edit(block.list).replace(/bull/g, block.bullet).replace("hr", "\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def", "\\n+(?=" + block.def.source + ")").getRegex();
-  block._tag = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
-  block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
-  block.html = edit(block.html, "i").replace("comment", block._comment).replace("tag", block._tag).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
-  block.paragraph = edit(block._paragraph).replace("hr", block.hr).replace("heading", " {0,3}#{1,6} ").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", block._tag).getRegex();
-  block.blockquote = edit(block.blockquote).replace("paragraph", block.paragraph).getRegex();
-  block.normal = merge2({}, block);
-  block.gfm = merge2({}, block.normal, {
-    table: "^ *([^\\n ].*\\|.*)\\n {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"
-  });
-  block.gfm.table = edit(block.gfm.table).replace("hr", block.hr).replace("heading", " {0,3}#{1,6} ").replace("blockquote", " {0,3}>").replace("code", " {4}[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", block._tag).getRegex();
-  block.gfm.paragraph = edit(block._paragraph).replace("hr", block.hr).replace("heading", " {0,3}#{1,6} ").replace("|lheading", "").replace("table", block.gfm.table).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", block._tag).getRegex();
-  block.pedantic = merge2({}, block.normal, {
-    html: edit(
-      `^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`
-    ).replace("comment", block._comment).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),
-    def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
-    heading: /^(#{1,6})(.*)(?:\n+|$)/,
-    fences: noopTest,
-    paragraph: edit(block.normal._paragraph).replace("hr", block.hr).replace("heading", " *#{1,6} *[^\n]").replace("lheading", block.lheading).replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").getRegex()
-  });
-  var inline = {
-    escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
-    autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
-    url: noopTest,
-    tag: "^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",
-    link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
-    reflink: /^!?\[(label)\]\[(ref)\]/,
-    nolink: /^!?\[(ref)\](?:\[\])?/,
-    reflinkSearch: "reflink|nolink(?!\\()",
-    emStrong: {
-      lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
-      rDelimAst: /^[^_*]*?\_\_[^_*]*?\*[^_*]*?(?=\_\_)|[^*]+(?=[^*])|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
-      rDelimUnd: /^[^_*]*?\*\*[^_*]*?\_[^_*]*?(?=\*\*)|[^_]+(?=[^_])|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/
+        if (callback)
+          callback(null, d);
+      });
     },
-    code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
-    br: /^( {2,}|\\)\n(?!\s*$)/,
-    del: noopTest,
-    text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
-    punctuation: /^([\spunctuation])/
-  };
-  inline._punctuation = "!\"#$%&'()+\\-.,/:;<=>?@\\[\\]`^{|}~";
-  inline.punctuation = edit(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex();
-  inline.blockSkip = /\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g;
-  inline.escapedEmSt = /\\\*|\\_/g;
-  inline._comment = edit(block._comment).replace("(?:-->|$)", "-->").getRegex();
-  inline.emStrong.lDelim = edit(inline.emStrong.lDelim).replace(/punct/g, inline._punctuation).getRegex();
-  inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, "g").replace(/punct/g, inline._punctuation).getRegex();
-  inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, "g").replace(/punct/g, inline._punctuation).getRegex();
-  inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
-  inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
-  inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
-  inline.autolink = edit(inline.autolink).replace("scheme", inline._scheme).replace("email", inline._email).getRegex();
-  inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
-  inline.tag = edit(inline.tag).replace("comment", inline._comment).replace("attribute", inline._attribute).getRegex();
-  inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
-  inline._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
-  inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
-  inline.link = edit(inline.link).replace("label", inline._label).replace("href", inline._href).replace("title", inline._title).getRegex();
-  inline.reflink = edit(inline.reflink).replace("label", inline._label).replace("ref", block._label).getRegex();
-  inline.nolink = edit(inline.nolink).replace("ref", block._label).getRegex();
-  inline.reflinkSearch = edit(inline.reflinkSearch, "g").replace("reflink", inline.reflink).replace("nolink", inline.nolink).getRegex();
-  inline.normal = merge2({}, inline);
-  inline.pedantic = merge2({}, inline.normal, {
-    strong: {
-      start: /^__|\*\*/,
-      middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
-      endAst: /\*\*(?!\*)/g,
-      endUnd: /__(?!_)/g
+    // 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 _cache.rtree.search(bbox2).map((d) => d.data);
     },
-    em: {
-      start: /^_|\*/,
-      middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
-      endAst: /\*(?!\*)/g,
-      endUnd: /_(?!_)/g
+    // Get a QAItem from cache
+    // NOTE: Don't change method name until UI v3 is merged
+    getError(id2) {
+      return _cache.data[id2];
     },
-    link: edit(/^!?\[(label)\]\((.*?)\)/).replace("label", inline._label).getRegex(),
-    reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", inline._label).getRegex()
-  });
-  inline.gfm = merge2({}, inline.normal, {
-    escape: edit(inline.escape).replace("])", "~|])").getRegex(),
-    _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
-    url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
-    _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
-    del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
-    text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
-  });
-  inline.gfm.url = edit(inline.gfm.url, "i").replace("email", inline.gfm._extended_email).getRegex();
-  inline.breaks = merge2({}, inline.gfm, {
-    br: edit(inline.br).replace("{2,}", "*").getRegex(),
-    text: edit(inline.gfm.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex()
-  });
-  function smartypants(text2) {
-    return text2.replace(/---/g, "\u2014").replace(/--/g, "\u2013").replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018").replace(/'/g, "\u2019").replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C").replace(/"/g, "\u201D").replace(/\.{3}/g, "\u2026");
-  }
-  function mangle(text2) {
-    let out = "", i2, ch;
-    const l = text2.length;
-    for (i2 = 0; i2 < l; i2++) {
-      ch = text2.charCodeAt(i2);
-      if (Math.random() > 0.5) {
-        ch = "x" + ch.toString(16);
-      }
-      out += "&#" + ch + ";";
+    // Replace a single QAItem in the cache
+    replaceItem(item) {
+      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;
+      delete _cache.data[item.id];
+      updateRtree(encodeIssueRtree(item), false);
+    },
+    issueURL(item) {
+      return `${_krUrlRoot}/report_map.php?schema=${item.schema}&error=${item.id}`;
+    },
+    // Get an array of issues closed during this session.
+    // Used to populate `closed:keepright` changeset tag
+    getClosedIDs() {
+      return Object.keys(_cache.closed).sort();
     }
-    return out;
-  }
-  var Lexer = class {
-    constructor(options2) {
-      this.tokens = [];
-      this.tokens.links = /* @__PURE__ */ Object.create(null);
-      this.options = options2 || defaults;
-      this.options.tokenizer = this.options.tokenizer || new Tokenizer();
-      this.tokenizer = this.options.tokenizer;
-      this.tokenizer.options = this.options;
-      this.tokenizer.lexer = this;
-      this.inlineQueue = [];
-      this.state = {
-        inLink: false,
-        inRawBlock: false,
-        top: true
-      };
-      const rules = {
-        block: block.normal,
-        inline: inline.normal
-      };
-      if (this.options.pedantic) {
-        rules.block = block.pedantic;
-        rules.inline = inline.pedantic;
-      } else if (this.options.gfm) {
-        rules.block = block.gfm;
-        if (this.options.breaks) {
-          rules.inline = inline.breaks;
-        } else {
-          rules.inline = inline.gfm;
-        }
+  };
+
+  // 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(i2) {
+    Object.values(i2).forEach((controller) => {
+      if (controller) {
+        controller.abort();
       }
-      this.tokenizer.rules = rules;
-    }
-    static get rules() {
-      return {
-        block,
-        inline
-      };
+    });
+  }
+  function abortUnwantedRequests2(cache, tiles) {
+    Object.keys(cache.inflightTile).forEach((k) => {
+      const wanted = tiles.find((tile) => k === tile.id);
+      if (!wanted) {
+        abortRequest2(cache.inflightTile[k]);
+        delete cache.inflightTile[k];
+      }
+    });
+  }
+  function encodeIssueRtree2(d) {
+    return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
+  }
+  function updateRtree2(item, replace) {
+    _cache2.rtree.remove(item, (a, b) => a.data.id === b.data.id);
+    if (replace) {
+      _cache2.rtree.insert(item);
     }
-    static lex(src, options2) {
-      const lexer2 = new Lexer(options2);
-      return lexer2.lex(src);
+  }
+  function linkErrorObject(d) {
+    return { html: `<a class="error_object_link">${d}</a>` };
+  }
+  function linkEntity(d) {
+    return { html: `<a class="error_entity_link">${d}</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];
     }
-    static lexInline(src, options2) {
-      const lexer2 = new Lexer(options2);
-      return lexer2.inlineTokens(src);
+  }
+  function relativeBearing(p1, p2) {
+    let angle2 = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
+    if (angle2 < 0) {
+      angle2 += 2 * Math.PI;
     }
-    lex(src) {
-      src = src.replace(/\r\n|\r/g, "\n");
-      this.blockTokens(src, this.tokens);
-      let next;
-      while (next = this.inlineQueue.shift()) {
-        this.inlineTokens(next.src, next.tokens);
+    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.${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((d) => _impOsmData = d.improveOSM);
+      if (!_cache2) {
+        this.reset();
       }
-      return this.tokens;
-    }
-    blockTokens(src, tokens = []) {
-      if (this.options.pedantic) {
-        src = src.replace(/\t/g, "    ").replace(/^ +$/gm, "");
-      } else {
-        src = src.replace(/^( *)(\t+)/gm, (_, leading, tabs) => {
-          return leading + "    ".repeat(tabs.length);
-        });
+      this.event = utilRebind(this, dispatch3, "on");
+    },
+    reset() {
+      if (_cache2) {
+        Object.values(_cache2.inflightTile).forEach(abortRequest2);
       }
-      let token, lastToken, cutSrc, 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)) {
-            src = src.substring(token.raw.length);
-            tokens.push(token);
-            return true;
-          }
-          return false;
-        })) {
-          continue;
-        }
-        if (token = this.tokenizer.space(src)) {
-          src = src.substring(token.raw.length);
-          if (token.raw.length === 1 && tokens.length > 0) {
-            tokens[tokens.length - 1].raw += "\n";
-          } else {
-            tokens.push(token);
-          }
-          continue;
-        }
-        if (token = this.tokenizer.code(src)) {
-          src = src.substring(token.raw.length);
-          lastToken = tokens[tokens.length - 1];
-          if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
-            lastToken.raw += "\n" + token.raw;
-            lastToken.text += "\n" + token.text;
-            this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
-          } else {
-            tokens.push(token);
-          }
-          continue;
-        }
-        if (token = this.tokenizer.fences(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.heading(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.hr(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.blockquote(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.list(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.html(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.def(src)) {
-          src = src.substring(token.raw.length);
-          lastToken = tokens[tokens.length - 1];
-          if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
-            lastToken.raw += "\n" + token.raw;
-            lastToken.text += "\n" + token.raw;
-            this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
-          } else if (!this.tokens.links[token.tag]) {
-            this.tokens.links[token.tag] = {
-              href: token.href,
-              title: token.title
-            };
-          }
-          continue;
-        }
-        if (token = this.tokenizer.table(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.lheading(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        cutSrc = src;
-        if (this.options.extensions && this.options.extensions.startBlock) {
-          let startIndex = Infinity;
-          const tempSrc = src.slice(1);
-          let tempStart;
-          this.options.extensions.startBlock.forEach(function(getStartIndex) {
-            tempStart = getStartIndex.call({ lexer: this }, tempSrc);
-            if (typeof tempStart === "number" && tempStart >= 0) {
-              startIndex = Math.min(startIndex, tempStart);
+      _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((k) => {
+          const kParams = Object.assign(
+            {},
+            params,
+            k === "mr" ? { type: "PARKING,ROAD,BOTH,PATH" } : { confidenceLevel: "C1" }
+          );
+          const url = `${_impOsmUrls[k]}/search?` + utilQsString(kParams);
+          const controller = new AbortController();
+          requests[k] = controller;
+          json_default(url, { signal: controller.signal }).then((data) => {
+            delete _cache2.inflightTile[tile.id][k];
+            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 = `${wayId}${fromNodeId}${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 d = new QAItem(loc, this, k, itemId, {
+                  issueKey: k,
+                  // used as a category
+                  identifier: {
+                    // used to post changes
+                    wayId,
+                    fromNodeId,
+                    toNodeId
+                  },
+                  objectId: wayId,
+                  objectType: "way"
+                });
+                d.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[d.id] = d;
+                _cache2.rtree.insert(encodeIssueRtree2(d));
+              });
+            }
+            if (data.tiles) {
+              data.tiles.forEach((feature3) => {
+                const { type: type2, x, y, numberOfTrips } = feature3;
+                const geoType = type2.toLowerCase();
+                const itemId = `${geoType}${x}${y}${numberOfTrips}`;
+                let loc = pointAverage(feature3.points);
+                loc = preventCoincident(loc, false);
+                let d = new QAItem(loc, this, `${k}-${geoType}`, itemId, {
+                  issueKey: k,
+                  identifier: { x, y }
+                });
+                d.replacements = {
+                  num_trips: numberOfTrips,
+                  geometry_type: _t(`QA.improveOSM.geometry_types.${geoType}`)
+                };
+                if (numberOfTrips === -1) {
+                  d.desc = _t("QA.improveOSM.error_types.mr.description_alt", d.replacements);
+                }
+                _cache2.data[d.id] = d;
+                _cache2.rtree.insert(encodeIssueRtree2(d));
+              });
+            }
+            if (data.entities) {
+              data.entities.forEach((feature3) => {
+                const { point: point2, id: id2, segments, numberOfPasses, turnType } = feature3;
+                const itemId = `${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 d = new QAItem(loc, this, k, itemId, {
+                  issueKey: k,
+                  identifier: id2,
+                  objectId: via_node,
+                  objectType: "node"
+                });
+                const [p1, p2] = segments[0].points;
+                const dir_of_travel = cardinalDirection(relativeBearing(p1, p2));
+                d.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[d.id] = d;
+                _cache2.rtree.insert(encodeIssueRtree2(d));
+                dispatch3.call("loaded");
+              });
+            }
+          }).catch(() => {
+            delete _cache2.inflightTile[tile.id][k];
+            if (!Object.keys(_cache2.inflightTile[tile.id]).length) {
+              delete _cache2.inflightTile[tile.id];
+              _cache2.loadedTile[tile.id] = true;
             }
           });
-          if (startIndex < Infinity && startIndex >= 0) {
-            cutSrc = src.substring(0, startIndex + 1);
-          }
-        }
-        if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
-          lastToken = tokens[tokens.length - 1];
-          if (lastParagraphClipped && lastToken.type === "paragraph") {
-            lastToken.raw += "\n" + token.raw;
-            lastToken.text += "\n" + token.text;
-            this.inlineQueue.pop();
-            this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
-          } else {
-            tokens.push(token);
-          }
-          lastParagraphClipped = cutSrc.length !== src.length;
-          src = src.substring(token.raw.length);
-          continue;
-        }
-        if (token = this.tokenizer.text(src)) {
-          src = src.substring(token.raw.length);
-          lastToken = tokens[tokens.length - 1];
-          if (lastToken && lastToken.type === "text") {
-            lastToken.raw += "\n" + token.raw;
-            lastToken.text += "\n" + token.text;
-            this.inlineQueue.pop();
-            this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
-          } else {
-            tokens.push(token);
-          }
-          continue;
-        }
-        if (src) {
-          const errMsg = "Infinite loop on byte: " + src.charCodeAt(0);
-          if (this.options.silent) {
-            console.error(errMsg);
-            break;
-          } else {
-            throw new Error(errMsg);
-          }
-        }
+        });
+        _cache2.inflightTile[tile.id] = requests;
+      });
+    },
+    getComments(item) {
+      if (item.comments) {
+        return Promise.resolve(item);
       }
-      this.state.top = true;
-      return tokens;
-    }
-    inline(src, tokens = []) {
-      this.inlineQueue.push({ src, tokens });
-      return tokens;
-    }
-    inlineTokens(src, tokens = []) {
-      let token, lastToken, cutSrc;
-      let maskedSrc = src;
-      let match;
-      let keepPrevChar, prevChar;
-      if (this.tokens.links) {
-        const links = Object.keys(this.tokens.links);
-        if (links.length > 0) {
-          while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
-            if (links.includes(match[0].slice(match[0].lastIndexOf("[") + 1, -1))) {
-              maskedSrc = maskedSrc.slice(0, match.index) + "[" + repeatString("a", match[0].length - 2) + "]" + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
-            }
-          }
-        }
+      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;
       }
-      while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
-        maskedSrc = maskedSrc.slice(0, match.index) + "[" + repeatString("a", match[0].length - 2) + "]" + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
+      const url = `${_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(d, callback) {
+      if (!osm_default.authenticated()) {
+        return callback({ message: "Not Authenticated", status: -3 }, d);
       }
-      while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {
-        maskedSrc = maskedSrc.slice(0, match.index) + "++" + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);
+      if (_cache2.inflightPost[d.id]) {
+        return callback({ message: "Error update already inflight", status: -2 }, d);
       }
-      while (src) {
-        if (!keepPrevChar) {
-          prevChar = "";
+      osm_default.userDetails(sendPayload.bind(this));
+      function sendPayload(err, user) {
+        if (err) {
+          return callback(err, d);
         }
-        keepPrevChar = false;
-        if (this.options.extensions && this.options.extensions.inline && this.options.extensions.inline.some((extTokenizer) => {
-          if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
-            src = src.substring(token.raw.length);
-            tokens.push(token);
-            return true;
-          }
-          return false;
-        })) {
-          continue;
+        const key = d.issueKey;
+        const url = `${_impOsmUrls[key]}/comment`;
+        const payload = {
+          username: user.display_name,
+          targetIds: [d.identifier]
+        };
+        if (d.newStatus) {
+          payload.status = d.newStatus;
+          payload.text = "status changed";
         }
-        if (token = this.tokenizer.escape(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
+        if (d.newComment) {
+          payload.text = d.newComment;
         }
-        if (token = this.tokenizer.tag(src)) {
-          src = src.substring(token.raw.length);
-          lastToken = tokens[tokens.length - 1];
-          if (lastToken && token.type === "text" && lastToken.type === "text") {
-            lastToken.raw += token.raw;
-            lastToken.text += token.text;
+        const controller = new AbortController();
+        _cache2.inflightPost[d.id] = controller;
+        const options2 = {
+          method: "POST",
+          signal: controller.signal,
+          body: JSON.stringify(payload)
+        };
+        json_default(url, options2).then(() => {
+          delete _cache2.inflightPost[d.id];
+          if (!d.newStatus) {
+            const now3 = /* @__PURE__ */ new Date();
+            let comments = d.comments ? d.comments : [];
+            comments.push({
+              username: payload.username,
+              text: payload.text,
+              timestamp: now3.getTime() / 1e3
+            });
+            this.replaceItem(d.update({
+              comments,
+              newComment: void 0
+            }));
           } else {
-            tokens.push(token);
-          }
-          continue;
-        }
-        if (token = this.tokenizer.link(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.reflink(src, this.tokens.links)) {
-          src = src.substring(token.raw.length);
-          lastToken = tokens[tokens.length - 1];
-          if (lastToken && token.type === "text" && lastToken.type === "text") {
-            lastToken.raw += token.raw;
-            lastToken.text += token.text;
-          } else {
-            tokens.push(token);
-          }
-          continue;
-        }
-        if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.codespan(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.br(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.del(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (token = this.tokenizer.autolink(src, mangle)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        if (!this.state.inLink && (token = this.tokenizer.url(src, mangle))) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        cutSrc = src;
-        if (this.options.extensions && this.options.extensions.startInline) {
-          let startIndex = Infinity;
-          const tempSrc = src.slice(1);
-          let tempStart;
-          this.options.extensions.startInline.forEach(function(getStartIndex) {
-            tempStart = getStartIndex.call({ lexer: this }, tempSrc);
-            if (typeof tempStart === "number" && tempStart >= 0) {
-              startIndex = Math.min(startIndex, tempStart);
+            this.removeItem(d);
+            if (d.newStatus === "SOLVED") {
+              if (!(d.issueKey in _cache2.closed)) {
+                _cache2.closed[d.issueKey] = 0;
+              }
+              _cache2.closed[d.issueKey] += 1;
             }
-          });
-          if (startIndex < Infinity && startIndex >= 0) {
-            cutSrc = src.substring(0, startIndex + 1);
-          }
-        }
-        if (token = this.tokenizer.inlineText(cutSrc, smartypants)) {
-          src = src.substring(token.raw.length);
-          if (token.raw.slice(-1) !== "_") {
-            prevChar = token.raw.slice(-1);
-          }
-          keepPrevChar = true;
-          lastToken = tokens[tokens.length - 1];
-          if (lastToken && lastToken.type === "text") {
-            lastToken.raw += token.raw;
-            lastToken.text += token.text;
-          } else {
-            tokens.push(token);
           }
-          continue;
-        }
-        if (src) {
-          const errMsg = "Infinite loop on byte: " + src.charCodeAt(0);
-          if (this.options.silent) {
-            console.error(errMsg);
-            break;
-          } else {
-            throw new Error(errMsg);
-          }
-        }
+          if (callback)
+            callback(null, d);
+        }).catch((err2) => {
+          delete _cache2.inflightPost[d.id];
+          if (callback)
+            callback(err2.message);
+        });
       }
-      return tokens;
+    },
+    // 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((d) => d.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;
     }
   };
-  var Renderer = class {
-    constructor(options2) {
-      this.options = options2 || defaults;
-    }
-    code(code, infostring, escaped) {
-      const lang = (infostring || "").match(/\S*/)[0];
-      if (this.options.highlight) {
-        const out = this.options.highlight(code, lang);
-        if (out != null && out !== code) {
-          escaped = true;
-          code = out;
-        }
+
+  // modules/services/osmose.js
+  var import_rbush3 = __toESM(require_rbush_min());
+
+  // node_modules/marked/lib/marked.esm.js
+  function getDefaults() {
+    return {
+      async: false,
+      baseUrl: null,
+      breaks: false,
+      extensions: null,
+      gfm: true,
+      headerIds: true,
+      headerPrefix: "",
+      highlight: null,
+      hooks: null,
+      langPrefix: "language-",
+      mangle: true,
+      pedantic: false,
+      renderer: null,
+      sanitize: false,
+      sanitizer: null,
+      silent: false,
+      smartypants: false,
+      tokenizer: null,
+      walkTokens: null,
+      xhtml: false
+    };
+  }
+  var defaults = getDefaults();
+  function changeDefaults(newDefaults) {
+    defaults = newDefaults;
+  }
+  var escapeTest = /[&<>"']/;
+  var escapeReplace = new RegExp(escapeTest.source, "g");
+  var escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
+  var escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, "g");
+  var escapeReplacements = {
+    "&": "&amp;",
+    "<": "&lt;",
+    ">": "&gt;",
+    '"': "&quot;",
+    "'": "&#39;"
+  };
+  var getEscapeReplacement = (ch) => escapeReplacements[ch];
+  function escape4(html2, encode) {
+    if (encode) {
+      if (escapeTest.test(html2)) {
+        return html2.replace(escapeReplace, getEscapeReplacement);
       }
-      code = code.replace(/\n$/, "") + "\n";
-      if (!lang) {
-        return "<pre><code>" + (escaped ? code : escape4(code, true)) + "</code></pre>\n";
+    } else {
+      if (escapeTestNoEncode.test(html2)) {
+        return html2.replace(escapeReplaceNoEncode, getEscapeReplacement);
       }
-      return '<pre><code class="' + this.options.langPrefix + escape4(lang, true) + '">' + (escaped ? code : escape4(code, true)) + "</code></pre>\n";
-    }
-    blockquote(quote2) {
-      return `<blockquote>
-${quote2}</blockquote>
-`;
-    }
-    html(html2) {
-      return html2;
     }
-    heading(text2, level, raw, slugger) {
-      if (this.options.headerIds) {
-        const id2 = this.options.headerPrefix + slugger.slug(raw);
-        return `<h${level} id="${id2}">${text2}</h${level}>
-`;
+    return html2;
+  }
+  var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
+  function unescape3(html2) {
+    return html2.replace(unescapeTest, (_, n2) => {
+      n2 = n2.toLowerCase();
+      if (n2 === "colon")
+        return ":";
+      if (n2.charAt(0) === "#") {
+        return n2.charAt(1) === "x" ? String.fromCharCode(parseInt(n2.substring(2), 16)) : String.fromCharCode(+n2.substring(1));
+      }
+      return "";
+    });
+  }
+  var caret = /(^|[^\[])\^/g;
+  function edit(regex, opt) {
+    regex = typeof regex === "string" ? regex : regex.source;
+    opt = opt || "";
+    const obj = {
+      replace: (name, val) => {
+        val = val.source || val;
+        val = val.replace(caret, "$1");
+        regex = regex.replace(name, val);
+        return obj;
+      },
+      getRegex: () => {
+        return new RegExp(regex, opt);
+      }
+    };
+    return obj;
+  }
+  var nonWordAndColonTest = /[^\w:]/g;
+  var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
+  function cleanUrl(sanitize, base, href) {
+    if (sanitize) {
+      let prot;
+      try {
+        prot = decodeURIComponent(unescape3(href)).replace(nonWordAndColonTest, "").toLowerCase();
+      } catch (e) {
+        return null;
+      }
+      if (prot.indexOf("javascript:") === 0 || prot.indexOf("vbscript:") === 0 || prot.indexOf("data:") === 0) {
+        return null;
       }
-      return `<h${level}>${text2}</h${level}>
-`;
-    }
-    hr() {
-      return this.options.xhtml ? "<hr/>\n" : "<hr>\n";
-    }
-    list(body, ordered, start2) {
-      const type3 = ordered ? "ol" : "ul", startatt = ordered && start2 !== 1 ? ' start="' + start2 + '"' : "";
-      return "<" + type3 + startatt + ">\n" + body + "</" + type3 + ">\n";
-    }
-    listitem(text2) {
-      return `<li>${text2}</li>
-`;
-    }
-    checkbox(checked) {
-      return "<input " + (checked ? 'checked="" ' : "") + 'disabled="" type="checkbox"' + (this.options.xhtml ? " /" : "") + "> ";
     }
-    paragraph(text2) {
-      return `<p>${text2}</p>
-`;
+    if (base && !originIndependentUrl.test(href)) {
+      href = resolveUrl(base, href);
     }
-    table(header, body) {
-      if (body)
-        body = `<tbody>${body}</tbody>`;
-      return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n";
+    try {
+      href = encodeURI(href).replace(/%25/g, "%");
+    } catch (e) {
+      return null;
     }
-    tablerow(content) {
-      return `<tr>
-${content}</tr>
-`;
+    return href;
+  }
+  var baseUrls = {};
+  var justDomain = /^[^:]+:\/*[^/]*$/;
+  var protocol = /^([^:]+:)[\s\S]*$/;
+  var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
+  function resolveUrl(base, href) {
+    if (!baseUrls[" " + base]) {
+      if (justDomain.test(base)) {
+        baseUrls[" " + base] = base + "/";
+      } else {
+        baseUrls[" " + base] = rtrim(base, "/", true);
+      }
     }
-    tablecell(content, flags) {
-      const type3 = flags.header ? "th" : "td";
-      const tag = flags.align ? `<${type3} align="${flags.align}">` : `<${type3}>`;
-      return tag + content + `</${type3}>
-`;
+    base = baseUrls[" " + base];
+    const relativeBase = base.indexOf(":") === -1;
+    if (href.substring(0, 2) === "//") {
+      if (relativeBase) {
+        return href;
+      }
+      return base.replace(protocol, "$1") + href;
+    } else if (href.charAt(0) === "/") {
+      if (relativeBase) {
+        return href;
+      }
+      return base.replace(domain, "$1") + href;
+    } else {
+      return base + href;
     }
-    strong(text2) {
-      return `<strong>${text2}</strong>`;
+  }
+  var noopTest = { exec: function noopTest2() {
+  } };
+  function splitCells(tableRow, count) {
+    const row = tableRow.replace(/\|/g, (match, offset, str2) => {
+      let escaped = false, curr = offset;
+      while (--curr >= 0 && str2[curr] === "\\")
+        escaped = !escaped;
+      if (escaped) {
+        return "|";
+      } else {
+        return " |";
+      }
+    }), cells = row.split(/ \|/);
+    let i2 = 0;
+    if (!cells[0].trim()) {
+      cells.shift();
     }
-    em(text2) {
-      return `<em>${text2}</em>`;
+    if (cells.length > 0 && !cells[cells.length - 1].trim()) {
+      cells.pop();
     }
-    codespan(text2) {
-      return `<code>${text2}</code>`;
+    if (cells.length > count) {
+      cells.splice(count);
+    } else {
+      while (cells.length < count)
+        cells.push("");
     }
-    br() {
-      return this.options.xhtml ? "<br/>" : "<br>";
+    for (; i2 < cells.length; i2++) {
+      cells[i2] = cells[i2].trim().replace(/\\\|/g, "|");
     }
-    del(text2) {
-      return `<del>${text2}</del>`;
+    return cells;
+  }
+  function rtrim(str2, c, invert) {
+    const l = str2.length;
+    if (l === 0) {
+      return "";
     }
-    link(href, title, text2) {
-      href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
-      if (href === null) {
-        return text2;
-      }
-      let out = '<a href="' + escape4(href) + '"';
-      if (title) {
-        out += ' title="' + title + '"';
+    let suffLen = 0;
+    while (suffLen < l) {
+      const currChar = str2.charAt(l - suffLen - 1);
+      if (currChar === c && !invert) {
+        suffLen++;
+      } else if (currChar !== c && invert) {
+        suffLen++;
+      } else {
+        break;
       }
-      out += ">" + text2 + "</a>";
-      return out;
     }
-    image(href, title, text2) {
-      href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
-      if (href === null) {
-        return text2;
-      }
-      let out = `<img src="${href}" alt="${text2}"`;
-      if (title) {
-        out += ` title="${title}"`;
-      }
-      out += this.options.xhtml ? "/>" : ">";
-      return out;
+    return str2.slice(0, l - suffLen);
+  }
+  function findClosingBracket(str2, b) {
+    if (str2.indexOf(b[1]) === -1) {
+      return -1;
     }
-    text(text2) {
-      return text2;
+    const l = str2.length;
+    let level = 0, i2 = 0;
+    for (; i2 < l; i2++) {
+      if (str2[i2] === "\\") {
+        i2++;
+      } else if (str2[i2] === b[0]) {
+        level++;
+      } else if (str2[i2] === b[1]) {
+        level--;
+        if (level < 0) {
+          return i2;
+        }
+      }
     }
-  };
-  var TextRenderer = class {
-    strong(text2) {
-      return text2;
+    return -1;
+  }
+  function checkDeprecations(opt, callback) {
+    if (!opt || opt.silent) {
+      return;
     }
-    em(text2) {
-      return text2;
+    if (callback) {
+      console.warn("marked(): callback is deprecated since version 5.0.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/using_pro#async");
     }
-    codespan(text2) {
-      return text2;
+    if (opt.sanitize || opt.sanitizer) {
+      console.warn("marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options");
     }
-    del(text2) {
-      return text2;
+    if (opt.highlight || opt.langPrefix !== "language-") {
+      console.warn("marked(): highlight and langPrefix parameters are deprecated since version 5.0.0, should not be used and will be removed in the future. Instead use https://www.npmjs.com/package/marked-highlight.");
     }
-    html(text2) {
-      return text2;
+    if (opt.mangle) {
+      console.warn("marked(): mangle parameter is enabled by default, but is deprecated since version 5.0.0, and will be removed in the future. To clear this warning, install https://www.npmjs.com/package/marked-mangle, or disable by setting `{mangle: false}`.");
     }
-    text(text2) {
-      return text2;
+    if (opt.baseUrl) {
+      console.warn("marked(): baseUrl parameter is deprecated since version 5.0.0, should not be used and will be removed in the future. Instead use https://www.npmjs.com/package/marked-base-url.");
     }
-    link(href, title, text2) {
-      return "" + text2;
+    if (opt.smartypants) {
+      console.warn("marked(): smartypants parameter is deprecated since version 5.0.0, should not be used and will be removed in the future. Instead use https://www.npmjs.com/package/marked-smartypants.");
     }
-    image(href, title, text2) {
-      return "" + text2;
+    if (opt.xhtml) {
+      console.warn("marked(): xhtml parameter is deprecated since version 5.0.0, should not be used and will be removed in the future. Instead use https://www.npmjs.com/package/marked-xhtml.");
     }
-    br() {
-      return "";
+    if (opt.headerIds || opt.headerPrefix) {
+      console.warn("marked(): headerIds and headerPrefix parameters enabled by default, but are deprecated since version 5.0.0, and will be removed in the future. To clear this warning, install  https://www.npmjs.com/package/marked-gfm-heading-id, or disable by setting `{headerIds: false}`.");
     }
-  };
-  var Slugger = class {
-    constructor() {
-      this.seen = {};
+  }
+  function outputLink(cap, link2, raw, lexer2) {
+    const href = link2.href;
+    const title = link2.title ? escape4(link2.title) : null;
+    const text2 = cap[1].replace(/\\([\[\]])/g, "$1");
+    if (cap[0].charAt(0) !== "!") {
+      lexer2.state.inLink = true;
+      const token = {
+        type: "link",
+        raw,
+        href,
+        title,
+        text: text2,
+        tokens: lexer2.inlineTokens(text2)
+      };
+      lexer2.state.inLink = false;
+      return token;
     }
-    serialize(value) {
-      return value.toLowerCase().trim().replace(/<[!\/a-z].*?>/ig, "").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, "").replace(/\s/g, "-");
+    return {
+      type: "image",
+      raw,
+      href,
+      title,
+      text: escape4(text2)
+    };
+  }
+  function indentCodeCompensation(raw, text2) {
+    const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
+    if (matchIndentToCode === null) {
+      return text2;
     }
-    getNextSafeSlug(originalSlug, isDryRun) {
-      let slug = originalSlug;
-      let occurenceAccumulator = 0;
-      if (this.seen.hasOwnProperty(slug)) {
-        occurenceAccumulator = this.seen[originalSlug];
-        do {
-          occurenceAccumulator++;
-          slug = originalSlug + "-" + occurenceAccumulator;
-        } while (this.seen.hasOwnProperty(slug));
+    const indentToCode = matchIndentToCode[1];
+    return text2.split("\n").map((node) => {
+      const matchIndentInNode = node.match(/^\s+/);
+      if (matchIndentInNode === null) {
+        return node;
       }
-      if (!isDryRun) {
-        this.seen[originalSlug] = occurenceAccumulator;
-        this.seen[slug] = 0;
+      const [indentInNode] = matchIndentInNode;
+      if (indentInNode.length >= indentToCode.length) {
+        return node.slice(indentToCode.length);
       }
-      return slug;
-    }
-    slug(value, options2 = {}) {
-      const slug = this.serialize(value);
-      return this.getNextSafeSlug(slug, options2.dryrun);
-    }
-  };
-  var Parser = class {
+      return node;
+    }).join("\n");
+  }
+  var Tokenizer = class {
     constructor(options2) {
       this.options = options2 || defaults;
-      this.options.renderer = this.options.renderer || new Renderer();
-      this.renderer = this.options.renderer;
-      this.renderer.options = this.options;
-      this.textRenderer = new TextRenderer();
-      this.slugger = new Slugger();
-    }
-    static parse(tokens, options2) {
-      const parser3 = new Parser(options2);
-      return parser3.parse(tokens);
     }
-    static parseInline(tokens, options2) {
-      const parser3 = new Parser(options2);
-      return parser3.parseInline(tokens);
+    space(src) {
+      const cap = this.rules.block.newline.exec(src);
+      if (cap && cap[0].length > 0) {
+        return {
+          type: "space",
+          raw: cap[0]
+        };
+      }
     }
-    parse(tokens, top = true) {
-      let out = "", i2, j2, k, l2, l3, row, cell, header, body, token, ordered, start2, loose, itemBody, item, checked, task, checkbox, ret;
-      const l = tokens.length;
-      for (i2 = 0; i2 < l; i2++) {
-        token = tokens[i2];
-        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
-          ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
-          if (ret !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "paragraph", "text"].includes(token.type)) {
-            out += ret || "";
-            continue;
+    code(src) {
+      const cap = this.rules.block.code.exec(src);
+      if (cap) {
+        const text2 = cap[0].replace(/^ {1,4}/gm, "");
+        return {
+          type: "code",
+          raw: cap[0],
+          codeBlockStyle: "indented",
+          text: !this.options.pedantic ? rtrim(text2, "\n") : text2
+        };
+      }
+    }
+    fences(src) {
+      const cap = this.rules.block.fences.exec(src);
+      if (cap) {
+        const raw = cap[0];
+        const text2 = indentCodeCompensation(raw, cap[3] || "");
+        return {
+          type: "code",
+          raw,
+          lang: cap[2] ? cap[2].trim().replace(this.rules.inline._escapes, "$1") : cap[2],
+          text: text2
+        };
+      }
+    }
+    heading(src) {
+      const cap = this.rules.block.heading.exec(src);
+      if (cap) {
+        let text2 = cap[2].trim();
+        if (/#$/.test(text2)) {
+          const trimmed = rtrim(text2, "#");
+          if (this.options.pedantic) {
+            text2 = trimmed.trim();
+          } else if (!trimmed || / $/.test(trimmed)) {
+            text2 = trimmed.trim();
           }
         }
-        switch (token.type) {
-          case "space": {
-            continue;
+        return {
+          type: "heading",
+          raw: cap[0],
+          depth: cap[1].length,
+          text: text2,
+          tokens: this.lexer.inline(text2)
+        };
+      }
+    }
+    hr(src) {
+      const cap = this.rules.block.hr.exec(src);
+      if (cap) {
+        return {
+          type: "hr",
+          raw: cap[0]
+        };
+      }
+    }
+    blockquote(src) {
+      const cap = this.rules.block.blockquote.exec(src);
+      if (cap) {
+        const text2 = cap[0].replace(/^ *>[ \t]?/gm, "");
+        const top = this.lexer.state.top;
+        this.lexer.state.top = true;
+        const tokens = this.lexer.blockTokens(text2);
+        this.lexer.state.top = top;
+        return {
+          type: "blockquote",
+          raw: cap[0],
+          tokens,
+          text: text2
+        };
+      }
+    }
+    list(src) {
+      let cap = this.rules.block.list.exec(src);
+      if (cap) {
+        let raw, istask, ischecked, indent2, i2, blankLine, endsWithBlankLine, line, nextLine, rawLine, itemContents, endEarly;
+        let bull = cap[1].trim();
+        const isordered = bull.length > 1;
+        const list = {
+          type: "list",
+          raw: "",
+          ordered: isordered,
+          start: isordered ? +bull.slice(0, -1) : "",
+          loose: false,
+          items: []
+        };
+        bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
+        if (this.options.pedantic) {
+          bull = isordered ? bull : "[*+-]";
+        }
+        const itemRegex = new RegExp(`^( {0,3}${bull})((?:[     ][^\\n]*)?(?:\\n|$))`);
+        while (src) {
+          endEarly = false;
+          if (!(cap = itemRegex.exec(src))) {
+            break;
           }
-          case "hr": {
-            out += this.renderer.hr();
-            continue;
+          if (this.rules.block.hr.test(src)) {
+            break;
           }
-          case "heading": {
-            out += this.renderer.heading(
-              this.parseInline(token.tokens),
-              token.depth,
-              unescape3(this.parseInline(token.tokens, this.textRenderer)),
-              this.slugger
-            );
-            continue;
+          raw = cap[0];
+          src = src.substring(raw.length);
+          line = cap[2].split("\n", 1)[0].replace(/^\t+/, (t) => " ".repeat(3 * t.length));
+          nextLine = src.split("\n", 1)[0];
+          if (this.options.pedantic) {
+            indent2 = 2;
+            itemContents = line.trimLeft();
+          } else {
+            indent2 = cap[2].search(/[^ ]/);
+            indent2 = indent2 > 4 ? 1 : indent2;
+            itemContents = line.slice(indent2);
+            indent2 += cap[1].length;
           }
-          case "code": {
-            out += this.renderer.code(
-              token.text,
-              token.lang,
-              token.escaped
-            );
-            continue;
+          blankLine = false;
+          if (!line && /^ *$/.test(nextLine)) {
+            raw += nextLine + "\n";
+            src = src.substring(nextLine.length + 1);
+            endEarly = true;
           }
-          case "table": {
-            header = "";
-            cell = "";
-            l2 = token.header.length;
-            for (j2 = 0; j2 < l2; j2++) {
-              cell += this.renderer.tablecell(
-                this.parseInline(token.header[j2].tokens),
-                { header: true, align: token.align[j2] }
-              );
-            }
-            header += this.renderer.tablerow(cell);
-            body = "";
-            l2 = token.rows.length;
-            for (j2 = 0; j2 < l2; j2++) {
-              row = token.rows[j2];
-              cell = "";
-              l3 = row.length;
-              for (k = 0; k < l3; k++) {
-                cell += this.renderer.tablecell(
-                  this.parseInline(row[k].tokens),
-                  { header: false, align: token.align[k] }
-                );
+          if (!endEarly) {
+            const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent2 - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[   ][^\\n]*)?(?:\\n|$))`);
+            const hrRegex = new RegExp(`^ {0,${Math.min(3, indent2 - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
+            const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent2 - 1)}}(?:\`\`\`|~~~)`);
+            const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent2 - 1)}}#`);
+            while (src) {
+              rawLine = src.split("\n", 1)[0];
+              nextLine = rawLine;
+              if (this.options.pedantic) {
+                nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, "  ");
               }
-              body += this.renderer.tablerow(cell);
-            }
-            out += this.renderer.table(header, body);
-            continue;
-          }
-          case "blockquote": {
-            body = this.parse(token.tokens);
-            out += this.renderer.blockquote(body);
-            continue;
-          }
-          case "list": {
-            ordered = token.ordered;
-            start2 = token.start;
-            loose = token.loose;
-            l2 = token.items.length;
-            body = "";
-            for (j2 = 0; j2 < l2; j2++) {
-              item = token.items[j2];
-              checked = item.checked;
-              task = item.task;
-              itemBody = "";
-              if (item.task) {
-                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;
+              if (fencesBeginRegex.test(nextLine)) {
+                break;
+              }
+              if (headingBeginRegex.test(nextLine)) {
+                break;
+              }
+              if (nextBulletRegex.test(nextLine)) {
+                break;
+              }
+              if (hrRegex.test(src)) {
+                break;
+              }
+              if (nextLine.search(/[^ ]/) >= indent2 || !nextLine.trim()) {
+                itemContents += "\n" + nextLine.slice(indent2);
+              } else {
+                if (blankLine) {
+                  break;
+                }
+                if (line.search(/[^ ]/) >= 4) {
+                  break;
+                }
+                if (fencesBeginRegex.test(line)) {
+                  break;
                 }
+                if (headingBeginRegex.test(line)) {
+                  break;
+                }
+                if (hrRegex.test(line)) {
+                  break;
+                }
+                itemContents += "\n" + nextLine;
               }
-              itemBody += this.parse(item.tokens, loose);
-              body += this.renderer.listitem(itemBody, task, checked);
+              if (!blankLine && !nextLine.trim()) {
+                blankLine = true;
+              }
+              raw += rawLine + "\n";
+              src = src.substring(rawLine.length + 1);
+              line = nextLine.slice(indent2);
             }
-            out += this.renderer.list(body, ordered, start2);
-            continue;
-          }
-          case "html": {
-            out += this.renderer.html(token.text);
-            continue;
-          }
-          case "paragraph": {
-            out += this.renderer.paragraph(this.parseInline(token.tokens));
-            continue;
           }
-          case "text": {
-            body = token.tokens ? this.parseInline(token.tokens) : token.text;
-            while (i2 + 1 < l && tokens[i2 + 1].type === "text") {
-              token = tokens[++i2];
-              body += "\n" + (token.tokens ? this.parseInline(token.tokens) : token.text);
+          if (!list.loose) {
+            if (endsWithBlankLine) {
+              list.loose = true;
+            } else if (/\n *\n *$/.test(raw)) {
+              endsWithBlankLine = true;
             }
-            out += top ? this.renderer.paragraph(body) : body;
-            continue;
           }
-          default: {
-            const errMsg = 'Token with "' + token.type + '" type was not found.';
-            if (this.options.silent) {
-              console.error(errMsg);
-              return;
-            } else {
-              throw new Error(errMsg);
+          if (this.options.gfm) {
+            istask = /^\[[ xX]\] /.exec(itemContents);
+            if (istask) {
+              ischecked = istask[0] !== "[ ] ";
+              itemContents = itemContents.replace(/^\[[ xX]\] +/, "");
             }
           }
+          list.items.push({
+            type: "list_item",
+            raw,
+            task: !!istask,
+            checked: ischecked,
+            loose: false,
+            text: itemContents
+          });
+          list.raw += raw;
         }
-      }
-      return out;
-    }
-    parseInline(tokens, renderer) {
-      renderer = renderer || this.renderer;
-      let out = "", i2, token, ret;
-      const l = tokens.length;
-      for (i2 = 0; i2 < l; i2++) {
-        token = tokens[i2];
-        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
-          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)) {
-            out += ret || "";
-            continue;
+        list.items[list.items.length - 1].raw = raw.trimRight();
+        list.items[list.items.length - 1].text = itemContents.trimRight();
+        list.raw = list.raw.trimRight();
+        const l = list.items.length;
+        for (i2 = 0; i2 < l; i2++) {
+          this.lexer.state.top = false;
+          list.items[i2].tokens = this.lexer.blockTokens(list.items[i2].text, []);
+          if (!list.loose) {
+            const spacers = list.items[i2].tokens.filter((t) => t.type === "space");
+            const hasMultipleLineBreaks = spacers.length > 0 && spacers.some((t) => /\n.*\n/.test(t.raw));
+            list.loose = hasMultipleLineBreaks;
           }
         }
-        switch (token.type) {
-          case "escape": {
-            out += renderer.text(token.text);
-            break;
-          }
-          case "html": {
-            out += renderer.html(token.text);
-            break;
-          }
-          case "link": {
-            out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
-            break;
-          }
-          case "image": {
-            out += renderer.image(token.href, token.title, token.text);
-            break;
-          }
-          case "strong": {
-            out += renderer.strong(this.parseInline(token.tokens, renderer));
-            break;
-          }
-          case "em": {
-            out += renderer.em(this.parseInline(token.tokens, renderer));
-            break;
-          }
-          case "codespan": {
-            out += renderer.codespan(token.text);
-            break;
-          }
-          case "br": {
-            out += renderer.br();
-            break;
-          }
-          case "del": {
-            out += renderer.del(this.parseInline(token.tokens, renderer));
-            break;
-          }
-          case "text": {
-            out += renderer.text(token.text);
-            break;
-          }
-          default: {
-            const errMsg = 'Token with "' + token.type + '" type was not found.';
-            if (this.options.silent) {
-              console.error(errMsg);
-              return;
-            } else {
-              throw new Error(errMsg);
-            }
+        if (list.loose) {
+          for (i2 = 0; i2 < l; i2++) {
+            list.items[i2].loose = true;
           }
         }
+        return list;
       }
-      return out;
-    }
-  };
-  function marked(src, opt, callback) {
-    if (typeof src === "undefined" || src === null) {
-      throw new Error("marked(): input parameter is undefined or null");
-    }
-    if (typeof src !== "string") {
-      throw new Error("marked(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected");
-    }
-    if (typeof opt === "function") {
-      callback = opt;
-      opt = null;
     }
-    opt = merge2({}, marked.defaults, opt || {});
-    checkSanitizeDeprecation(opt);
-    if (callback) {
-      const highlight = opt.highlight;
-      let tokens;
-      try {
-        tokens = Lexer.lex(src, opt);
-      } catch (e) {
-        return callback(e);
-      }
-      const done = function(err) {
-        let out;
-        if (!err) {
-          try {
-            if (opt.walkTokens) {
-              marked.walkTokens(tokens, opt.walkTokens);
-            }
-            out = Parser.parse(tokens, opt);
-          } catch (e) {
-            err = e;
-          }
-        }
-        opt.highlight = highlight;
-        return err ? callback(err) : callback(null, out);
-      };
-      if (!highlight || highlight.length < 3) {
-        return done();
-      }
-      delete opt.highlight;
-      if (!tokens.length)
-        return done();
-      let pending = 0;
-      marked.walkTokens(tokens, function(token) {
-        if (token.type === "code") {
-          pending++;
-          setTimeout(() => {
-            highlight(token.text, token.lang, function(err, code) {
-              if (err) {
-                return done(err);
-              }
-              if (code != null && code !== token.text) {
-                token.text = code;
-                token.escaped = true;
-              }
-              pending--;
-              if (pending === 0) {
-                done();
-              }
-            });
-          }, 0);
+    html(src) {
+      const cap = this.rules.block.html.exec(src);
+      if (cap) {
+        const token = {
+          type: "html",
+          block: true,
+          raw: cap[0],
+          pre: !this.options.sanitizer && (cap[1] === "pre" || cap[1] === "script" || cap[1] === "style"),
+          text: cap[0]
+        };
+        if (this.options.sanitize) {
+          const text2 = this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape4(cap[0]);
+          token.type = "paragraph";
+          token.text = text2;
+          token.tokens = this.lexer.inline(text2);
         }
-      });
-      if (pending === 0) {
-        done();
-      }
-      return;
-    }
-    function onError(e) {
-      e.message += "\nPlease report this to https://github.com/markedjs/marked.";
-      if (opt.silent) {
-        return "<p>An error occurred:</p><pre>" + escape4(e.message + "", true) + "</pre>";
+        return token;
       }
-      throw e;
     }
-    try {
-      const tokens = Lexer.lex(src, opt);
-      if (opt.walkTokens) {
-        if (opt.async) {
-          return Promise.all(marked.walkTokens(tokens, opt.walkTokens)).then(() => {
-            return Parser.parse(tokens, opt);
-          }).catch(onError);
-        }
-        marked.walkTokens(tokens, opt.walkTokens);
+    def(src) {
+      const cap = this.rules.block.def.exec(src);
+      if (cap) {
+        const tag = cap[1].toLowerCase().replace(/\s+/g, " ");
+        const href = cap[2] ? cap[2].replace(/^<(.*)>$/, "$1").replace(this.rules.inline._escapes, "$1") : "";
+        const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline._escapes, "$1") : cap[3];
+        return {
+          type: "def",
+          tag,
+          raw: cap[0],
+          href,
+          title
+        };
       }
-      return Parser.parse(tokens, opt);
-    } catch (e) {
-      onError(e);
     }
-  }
-  marked.options = marked.setOptions = function(opt) {
-    merge2(marked.defaults, opt);
-    changeDefaults(marked.defaults);
-    return marked;
-  };
-  marked.getDefaults = getDefaults;
-  marked.defaults = defaults;
-  marked.use = function(...args) {
-    const opts = merge2({}, ...args);
-    const extensions = marked.defaults.extensions || { renderers: {}, childTokens: {} };
-    let hasExtensions;
-    args.forEach((pack) => {
-      if (pack.extensions) {
-        hasExtensions = true;
-        pack.extensions.forEach((ext) => {
-          if (!ext.name) {
-            throw new Error("extension name required");
-          }
-          if (ext.renderer) {
-            const prevRenderer = extensions.renderers ? extensions.renderers[ext.name] : null;
-            if (prevRenderer) {
-              extensions.renderers[ext.name] = function(...args2) {
-                let ret = ext.renderer.apply(this, args2);
-                if (ret === false) {
-                  ret = prevRenderer.apply(this, args2);
-                }
-                return ret;
-              };
-            } else {
-              extensions.renderers[ext.name] = ext.renderer;
-            }
-          }
-          if (ext.tokenizer) {
-            if (!ext.level || ext.level !== "block" && ext.level !== "inline") {
-              throw new Error("extension level must be 'block' or 'inline'");
-            }
-            if (extensions[ext.level]) {
-              extensions[ext.level].unshift(ext.tokenizer);
+    table(src) {
+      const cap = this.rules.block.table.exec(src);
+      if (cap) {
+        const item = {
+          type: "table",
+          header: splitCells(cap[1]).map((c) => {
+            return { text: c };
+          }),
+          align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
+          rows: cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, "").split("\n") : []
+        };
+        if (item.header.length === item.align.length) {
+          item.raw = cap[0];
+          let l = item.align.length;
+          let i2, j2, k, row;
+          for (i2 = 0; i2 < l; i2++) {
+            if (/^ *-+: *$/.test(item.align[i2])) {
+              item.align[i2] = "right";
+            } else if (/^ *:-+: *$/.test(item.align[i2])) {
+              item.align[i2] = "center";
+            } else if (/^ *:-+ *$/.test(item.align[i2])) {
+              item.align[i2] = "left";
             } else {
-              extensions[ext.level] = [ext.tokenizer];
-            }
-            if (ext.start) {
-              if (ext.level === "block") {
-                if (extensions.startBlock) {
-                  extensions.startBlock.push(ext.start);
-                } else {
-                  extensions.startBlock = [ext.start];
-                }
-              } else if (ext.level === "inline") {
-                if (extensions.startInline) {
-                  extensions.startInline.push(ext.start);
-                } else {
-                  extensions.startInline = [ext.start];
-                }
-              }
+              item.align[i2] = null;
             }
           }
-          if (ext.childTokens) {
-            extensions.childTokens[ext.name] = ext.childTokens;
-          }
-        });
-      }
-      if (pack.renderer) {
-        const renderer = marked.defaults.renderer || new Renderer();
-        for (const prop in pack.renderer) {
-          const prevRenderer = renderer[prop];
-          renderer[prop] = (...args2) => {
-            let ret = pack.renderer[prop].apply(renderer, args2);
-            if (ret === false) {
-              ret = prevRenderer.apply(renderer, args2);
-            }
-            return ret;
-          };
-        }
-        opts.renderer = renderer;
-      }
-      if (pack.tokenizer) {
-        const tokenizer = marked.defaults.tokenizer || new Tokenizer();
-        for (const prop in pack.tokenizer) {
-          const prevTokenizer = tokenizer[prop];
-          tokenizer[prop] = (...args2) => {
-            let ret = pack.tokenizer[prop].apply(tokenizer, args2);
-            if (ret === false) {
-              ret = prevTokenizer.apply(tokenizer, args2);
-            }
-            return ret;
-          };
-        }
-        opts.tokenizer = tokenizer;
-      }
-      if (pack.walkTokens) {
-        const walkTokens2 = marked.defaults.walkTokens;
-        opts.walkTokens = function(token) {
-          let values = [];
-          values.push(pack.walkTokens.call(this, token));
-          if (walkTokens2) {
-            values = values.concat(walkTokens2.call(this, token));
+          l = item.rows.length;
+          for (i2 = 0; i2 < l; i2++) {
+            item.rows[i2] = splitCells(item.rows[i2], item.header.length).map((c) => {
+              return { text: c };
+            });
           }
-          return values;
-        };
-      }
-      if (hasExtensions) {
-        opts.extensions = extensions;
-      }
-      marked.setOptions(opts);
-    });
-  };
-  marked.walkTokens = function(tokens, callback) {
-    let values = [];
-    for (const token of tokens) {
-      values = values.concat(callback.call(marked, token));
-      switch (token.type) {
-        case "table": {
-          for (const cell of token.header) {
-            values = values.concat(marked.walkTokens(cell.tokens, callback));
+          l = item.header.length;
+          for (j2 = 0; j2 < l; j2++) {
+            item.header[j2].tokens = this.lexer.inline(item.header[j2].text);
           }
-          for (const row of token.rows) {
-            for (const cell of row) {
-              values = values.concat(marked.walkTokens(cell.tokens, callback));
+          l = item.rows.length;
+          for (j2 = 0; j2 < l; j2++) {
+            row = item.rows[j2];
+            for (k = 0; k < row.length; k++) {
+              row[k].tokens = this.lexer.inline(row[k].text);
             }
           }
-          break;
-        }
-        case "list": {
-          values = values.concat(marked.walkTokens(token.items, callback));
-          break;
-        }
-        default: {
-          if (marked.defaults.extensions && marked.defaults.extensions.childTokens && marked.defaults.extensions.childTokens[token.type]) {
-            marked.defaults.extensions.childTokens[token.type].forEach(function(childTokens) {
-              values = values.concat(marked.walkTokens(token[childTokens], callback));
-            });
-          } else if (token.tokens) {
-            values = values.concat(marked.walkTokens(token.tokens, callback));
-          }
+          return item;
         }
       }
     }
-    return values;
-  };
-  marked.parseInline = function(src, opt) {
-    if (typeof src === "undefined" || src === null) {
-      throw new Error("marked.parseInline(): input parameter is undefined or null");
-    }
-    if (typeof src !== "string") {
-      throw new Error("marked.parseInline(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected");
+    lheading(src) {
+      const cap = this.rules.block.lheading.exec(src);
+      if (cap) {
+        return {
+          type: "heading",
+          raw: cap[0],
+          depth: cap[2].charAt(0) === "=" ? 1 : 2,
+          text: cap[1],
+          tokens: this.lexer.inline(cap[1])
+        };
+      }
     }
-    opt = merge2({}, marked.defaults, opt || {});
-    checkSanitizeDeprecation(opt);
-    try {
-      const tokens = Lexer.lexInline(src, opt);
-      if (opt.walkTokens) {
-        marked.walkTokens(tokens, opt.walkTokens);
+    paragraph(src) {
+      const cap = this.rules.block.paragraph.exec(src);
+      if (cap) {
+        const text2 = cap[1].charAt(cap[1].length - 1) === "\n" ? cap[1].slice(0, -1) : cap[1];
+        return {
+          type: "paragraph",
+          raw: cap[0],
+          text: text2,
+          tokens: this.lexer.inline(text2)
+        };
       }
-      return Parser.parseInline(tokens, opt);
-    } catch (e) {
-      e.message += "\nPlease report this to https://github.com/markedjs/marked.";
-      if (opt.silent) {
-        return "<p>An error occurred:</p><pre>" + escape4(e.message + "", true) + "</pre>";
+    }
+    text(src) {
+      const cap = this.rules.block.text.exec(src);
+      if (cap) {
+        return {
+          type: "text",
+          raw: cap[0],
+          text: cap[0],
+          tokens: this.lexer.inline(cap[0])
+        };
       }
-      throw e;
     }
-  };
-  marked.Parser = Parser;
-  marked.parser = Parser.parse;
-  marked.Renderer = Renderer;
-  marked.TextRenderer = TextRenderer;
-  marked.Lexer = Lexer;
-  marked.lexer = Lexer.lex;
-  marked.Tokenizer = Tokenizer;
-  marked.Slugger = Slugger;
-  marked.parse = marked;
-  var options = marked.options;
-  var setOptions = marked.setOptions;
-  var use = marked.use;
-  var walkTokens = marked.walkTokens;
-  var parseInline = marked.parseInline;
-  var parser2 = Parser.parse;
-  var lexer = Lexer.lex;
-
-  // modules/services/osmose.js
-  var tiler3 = utilTiler();
-  var dispatch4 = dispatch_default("loaded");
-  var _tileZoom3 = 14;
-  var _osmoseUrlRoot = "https://osmose.openstreetmap.fr/api/0.3";
-  var _osmoseData = { icons: {}, items: [] };
-  var _cache3;
-  function abortRequest3(controller) {
-    if (controller) {
-      controller.abort();
-    }
-  }
-  function abortUnwantedRequests3(cache, tiles) {
-    Object.keys(cache.inflightTile).forEach((k) => {
-      let wanted = tiles.find((tile) => k === tile.id);
-      if (!wanted) {
-        abortRequest3(cache.inflightTile[k]);
-        delete cache.inflightTile[k];
+    escape(src) {
+      const cap = this.rules.inline.escape.exec(src);
+      if (cap) {
+        return {
+          type: "escape",
+          raw: cap[0],
+          text: escape4(cap[1])
+        };
       }
-    });
-  }
-  function encodeIssueRtree3(d) {
-    return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
-  }
-  function updateRtree3(item, replace) {
-    _cache3.rtree.remove(item, (a, b) => a.data.id === b.data.id);
-    if (replace) {
-      _cache3.rtree.insert(item);
     }
-  }
-  function preventCoincident2(loc) {
-    let coincident = false;
-    do {
-      let delta = coincident ? [1e-5, 0] : [0, 1e-5];
-      loc = geoVecAdd(loc, delta);
-      let bbox = geoExtent(loc).bbox();
-      coincident = _cache3.rtree.search(bbox).length;
-    } while (coincident);
-    return loc;
-  }
-  var osmose_default = {
-    title: "osmose",
-    init() {
-      _mainFileFetcher.get("qa_data").then((d) => {
-        _osmoseData = d.osmose;
-        _osmoseData.items = Object.keys(d.osmose.icons).map((s) => s.split("-")[0]).reduce((unique, item) => unique.indexOf(item) !== -1 ? unique : [...unique, item], []);
-      });
-      if (!_cache3) {
-        this.reset();
-      }
-      this.event = utilRebind(this, dispatch4, "on");
-    },
-    reset() {
-      let _strings = {};
-      let _colors = {};
-      if (_cache3) {
-        Object.values(_cache3.inflightTile).forEach(abortRequest3);
-        _strings = _cache3.strings;
-        _colors = _cache3.colors;
+    tag(src) {
+      const cap = this.rules.inline.tag.exec(src);
+      if (cap) {
+        if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
+          this.lexer.state.inLink = true;
+        } else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
+          this.lexer.state.inLink = false;
+        }
+        if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
+          this.lexer.state.inRawBlock = true;
+        } else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
+          this.lexer.state.inRawBlock = false;
+        }
+        return {
+          type: this.options.sanitize ? "text" : "html",
+          raw: cap[0],
+          inLink: this.lexer.state.inLink,
+          inRawBlock: this.lexer.state.inRawBlock,
+          block: false,
+          text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape4(cap[0]) : cap[0]
+        };
       }
-      _cache3 = {
-        data: {},
-        loadedTile: {},
-        inflightTile: {},
-        inflightPost: {},
-        closed: {},
-        rtree: new import_rbush3.default(),
-        strings: _strings,
-        colors: _colors
-      };
-    },
-    loadIssues(projection2) {
-      let params = {
-        item: _osmoseData.items
-      };
-      let tiles = tiler3.zoomExtent([_tileZoom3, _tileZoom3]).getTiles(projection2);
-      abortUnwantedRequests3(_cache3, tiles);
-      tiles.forEach((tile) => {
-        if (_cache3.loadedTile[tile.id] || _cache3.inflightTile[tile.id])
-          return;
-        let [x, y, z] = tile.xyz;
-        let url = `${_osmoseUrlRoot}/issues/${z}/${x}/${y}.geojson?` + utilQsString(params);
-        let controller = new AbortController();
-        _cache3.inflightTile[tile.id] = controller;
-        json_default(url, { signal: controller.signal }).then((data) => {
-          delete _cache3.inflightTile[tile.id];
-          _cache3.loadedTile[tile.id] = true;
-          if (data.features) {
-            data.features.forEach((issue) => {
-              const { item, class: cl, uuid: id2 } = issue.properties;
-              const itemType = `${item}-${cl}`;
-              if (itemType in _osmoseData.icons) {
-                let loc = issue.geometry.coordinates;
-                loc = preventCoincident2(loc);
-                let d = new QAItem(loc, this, itemType, id2, { item });
-                if (item === 8300 || item === 8360) {
-                  d.elems = [];
-                }
-                _cache3.data[d.id] = d;
-                _cache3.rtree.insert(encodeIssueRtree3(d));
-              }
-            });
+    }
+    link(src) {
+      const cap = this.rules.inline.link.exec(src);
+      if (cap) {
+        const trimmedUrl = cap[2].trim();
+        if (!this.options.pedantic && /^</.test(trimmedUrl)) {
+          if (!/>$/.test(trimmedUrl)) {
+            return;
           }
-          dispatch4.call("loaded");
-        }).catch(() => {
-          delete _cache3.inflightTile[tile.id];
-          _cache3.loadedTile[tile.id] = true;
-        });
-      });
-    },
-    loadIssueDetail(issue) {
-      if (issue.elems !== void 0) {
-        return Promise.resolve(issue);
-      }
-      const url = `${_osmoseUrlRoot}/issue/${issue.id}?langs=${_mainLocalizer.localeCode()}`;
-      const cacheDetails = (data) => {
-        issue.elems = data.elems.map((e) => e.type.substring(0, 1) + e.id);
-        issue.detail = data.subtitle ? marked(data.subtitle.auto) : "";
-        this.replaceItem(issue);
-      };
-      return json_default(url).then(cacheDetails).then(() => issue);
-    },
-    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 _cache3.strings)) {
-        _cache3.strings[locale2] = {};
-      }
-      const allRequests = items.map((itemType) => {
-        if (itemType in _cache3.strings[locale2])
-          return null;
-        const cacheData = (data) => {
-          const [cat = { items: [] }] = data.categories;
-          const [item2 = { class: [] }] = cat.items;
-          const [cl2 = null] = item2.class;
-          if (!cl2) {
-            console.log(`Osmose strings request (${itemType}) had unexpected data`);
+          const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), "\\");
+          if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
             return;
           }
-          const { item: itemInt, color: color2 } = item2;
-          if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color2)) {
-            _cache3.colors[itemInt] = color2;
+        } else {
+          const lastParenIndex = findClosingBracket(cap[2], "()");
+          if (lastParenIndex > -1) {
+            const start2 = cap[0].indexOf("!") === 0 ? 5 : 4;
+            const linkLen = start2 + cap[1].length + lastParenIndex;
+            cap[2] = cap[2].substring(0, lastParenIndex);
+            cap[0] = cap[0].substring(0, linkLen).trim();
+            cap[3] = "";
           }
-          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;
-        };
-        const [item, cl] = itemType.split("-");
-        const url = `${_osmoseUrlRoot}/items/${item}/class/${cl}?langs=${locale2}`;
-        return json_default(url).then(cacheData);
-      }).filter(Boolean);
-      return Promise.all(allRequests).then(() => _cache3.strings[locale2]);
-    },
-    getStrings(itemType, locale2 = _mainLocalizer.localeCode()) {
-      return locale2 in _cache3.strings ? _cache3.strings[locale2][itemType] : {};
-    },
-    getColor(itemType) {
-      return itemType in _cache3.colors ? _cache3.colors[itemType] : "#FFFFFF";
-    },
-    postUpdate(issue, callback) {
-      if (_cache3.inflightPost[issue.id]) {
-        return callback({ message: "Issue update already inflight", status: -2 }, issue);
-      }
-      const url = `${_osmoseUrlRoot}/issue/${issue.id}/${issue.newStatus}`;
-      const controller = new AbortController();
-      const after = () => {
-        delete _cache3.inflightPost[issue.id];
-        this.removeItem(issue);
-        if (issue.newStatus === "done") {
-          if (!(issue.item in _cache3.closed)) {
-            _cache3.closed[issue.item] = 0;
+        }
+        let href = cap[2];
+        let title = "";
+        if (this.options.pedantic) {
+          const link2 = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
+          if (link2) {
+            href = link2[1];
+            title = link2[3];
           }
-          _cache3.closed[issue.item] += 1;
+        } else {
+          title = cap[3] ? cap[3].slice(1, -1) : "";
         }
-        if (callback)
-          callback(null, issue);
-      };
-      _cache3.inflightPost[issue.id] = controller;
-      fetch(url, { signal: controller.signal }).then(after).catch((err) => {
-        delete _cache3.inflightPost[issue.id];
-        if (callback)
-          callback(err.message);
-      });
-    },
-    getItems(projection2) {
-      const viewport = projection2.clipExtent();
-      const min3 = [viewport[0][0], viewport[1][1]];
-      const max3 = [viewport[1][0], viewport[0][1]];
-      const bbox = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
-      return _cache3.rtree.search(bbox).map((d) => d.data);
-    },
-    getError(id2) {
-      return _cache3.data[id2];
-    },
-    getIcon(itemType) {
-      return _osmoseData.icons[itemType];
-    },
-    replaceItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
-      _cache3.data[item.id] = item;
-      updateRtree3(encodeIssueRtree3(item), true);
-      return item;
-    },
-    removeItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
-      delete _cache3.data[item.id];
-      updateRtree3(encodeIssueRtree3(item), false);
-    },
-    getClosedCounts() {
-      return _cache3.closed;
-    },
-    itemURL(item) {
-      return `https://osmose.openstreetmap.fr/en/error/${item.id}`;
-    }
-  };
-
-  // 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 mapFeatureTileUrl = `${baseTileUrl}/mly_map_feature_point/2/{z}/{x}/{y}?access_token=${accessToken}`;
-  var tileUrl = `${baseTileUrl}/mly1_public/2/{z}/{x}/{y}?access_token=${accessToken}`;
-  var trafficSignTileUrl = `${baseTileUrl}/mly_map_feature_traffic_sign/2/{z}/{x}/{y}?access_token=${accessToken}`;
-  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 _loadViewerPromise;
-  var _mlyActiveImage;
-  var _mlyCache;
-  var _mlyFallback = false;
-  var _mlyHighlightedDetection;
-  var _mlyShowFeatureDetections = false;
-  var _mlyShowSignDetections = false;
-  var _mlyViewer;
-  var _mlyViewerFilter = ["all"];
-  function loadTiles(which, url, maxZoom2, 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 = `${tile.id}-${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) {
-        throw new Error("No Data");
-      }
-      loadTileDataToCache(data, tile, which);
-      if (which === "images") {
-        dispatch5.call("loadedImages");
-      } else if (which === "signs") {
-        dispatch5.call("loadedSigns");
-      } else if (which === "points") {
-        dispatch5.call("loadedMapFeatures");
-      }
-    }).catch(function() {
-      cache.loaded[tileId] = true;
-      delete cache.inflight[tileId];
-    });
-  }
-  function loadTileDataToCache(data, tile, which) {
-    const vectorTile = new import_vector_tile.VectorTile(new import_pbf.default(data));
-    let features2, cache, layer, i2, feature3, loc, d;
-    if (vectorTile.layers.hasOwnProperty("image")) {
-      features2 = [];
-      cache = _mlyCache.images;
-      layer = vectorTile.layers.image;
-      for (i2 = 0; i2 < layer.length; i2++) {
-        feature3 = layer.feature(i2).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
-        loc = feature3.geometry.coordinates;
-        d = {
-          loc,
-          captured_at: feature3.properties.captured_at,
-          ca: feature3.properties.compass_angle,
-          id: feature3.properties.id,
-          is_pano: feature3.properties.is_pano,
-          sequence_id: feature3.properties.sequence_id
-        };
-        cache.forImageId[d.id] = d;
-        features2.push({
-          minX: loc[0],
-          minY: loc[1],
-          maxX: loc[0],
-          maxY: loc[1],
-          data: d
-        });
+        href = href.trim();
+        if (/^</.test(href)) {
+          if (this.options.pedantic && !/>$/.test(trimmedUrl)) {
+            href = href.slice(1);
+          } else {
+            href = href.slice(1, -1);
+          }
+        }
+        return outputLink(cap, {
+          href: href ? href.replace(this.rules.inline._escapes, "$1") : href,
+          title: title ? title.replace(this.rules.inline._escapes, "$1") : title
+        }, cap[0], this.lexer);
       }
-      if (cache.rtree) {
-        cache.rtree.load(features2);
+    }
+    reflink(src, links) {
+      let cap;
+      if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
+        let link2 = (cap[2] || cap[1]).replace(/\s+/g, " ");
+        link2 = links[link2.toLowerCase()];
+        if (!link2) {
+          const text2 = cap[0].charAt(0);
+          return {
+            type: "text",
+            raw: text2,
+            text: text2
+          };
+        }
+        return outputLink(cap, link2, cap[0], this.lexer);
       }
     }
-    if (vectorTile.layers.hasOwnProperty("sequence")) {
-      features2 = [];
-      cache = _mlyCache.sequences;
-      layer = vectorTile.layers.sequence;
-      for (i2 = 0; i2 < layer.length; i2++) {
-        feature3 = layer.feature(i2).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];
+    emStrong(src, maskedSrc, prevChar = "") {
+      let match = this.rules.inline.emStrong.lDelim.exec(src);
+      if (!match)
+        return;
+      if (match[3] && prevChar.match(/[\p{L}\p{N}]/u))
+        return;
+      const nextChar = match[1] || match[2] || "";
+      if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
+        const lLength = match[0].length - 1;
+        let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
+        const endReg = match[0][0] === "*" ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
+        endReg.lastIndex = 0;
+        maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
+        while ((match = endReg.exec(maskedSrc)) != null) {
+          rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
+          if (!rDelim)
+            continue;
+          rLength = rDelim.length;
+          if (match[3] || match[4]) {
+            delimTotal += rLength;
+            continue;
+          } else if (match[5] || match[6]) {
+            if (lLength % 3 && !((lLength + rLength) % 3)) {
+              midDelimTotal += rLength;
+              continue;
+            }
+          }
+          delimTotal -= rLength;
+          if (delimTotal > 0)
+            continue;
+          rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
+          const raw = src.slice(0, lLength + match.index + rLength + 1);
+          if (Math.min(lLength, rLength) % 2) {
+            const text3 = raw.slice(1, -1);
+            return {
+              type: "em",
+              raw,
+              text: text3,
+              tokens: this.lexer.inlineTokens(text3)
+            };
+          }
+          const text2 = raw.slice(2, -2);
+          return {
+            type: "strong",
+            raw,
+            text: text2,
+            tokens: this.lexer.inlineTokens(text2)
+          };
         }
       }
     }
-    if (vectorTile.layers.hasOwnProperty("point")) {
-      features2 = [];
-      cache = _mlyCache[which];
-      layer = vectorTile.layers.point;
-      for (i2 = 0; i2 < layer.length; i2++) {
-        feature3 = layer.feature(i2).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
-        loc = feature3.geometry.coordinates;
-        d = {
-          loc,
-          id: feature3.properties.id,
-          first_seen_at: feature3.properties.first_seen_at,
-          last_seen_at: feature3.properties.last_seen_at,
-          value: feature3.properties.value
+    codespan(src) {
+      const cap = this.rules.inline.code.exec(src);
+      if (cap) {
+        let text2 = cap[2].replace(/\n/g, " ");
+        const hasNonSpaceChars = /[^ ]/.test(text2);
+        const hasSpaceCharsOnBothEnds = /^ /.test(text2) && / $/.test(text2);
+        if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
+          text2 = text2.substring(1, text2.length - 1);
+        }
+        text2 = escape4(text2, true);
+        return {
+          type: "codespan",
+          raw: cap[0],
+          text: text2
         };
-        features2.push({
-          minX: loc[0],
-          minY: loc[1],
-          maxX: loc[0],
-          maxY: loc[1],
-          data: d
-        });
-      }
-      if (cache.rtree) {
-        cache.rtree.load(features2);
       }
     }
-    if (vectorTile.layers.hasOwnProperty("traffic_sign")) {
-      features2 = [];
-      cache = _mlyCache[which];
-      layer = vectorTile.layers.traffic_sign;
-      for (i2 = 0; i2 < layer.length; i2++) {
-        feature3 = layer.feature(i2).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
-        loc = feature3.geometry.coordinates;
-        d = {
-          loc,
-          id: feature3.properties.id,
-          first_seen_at: feature3.properties.first_seen_at,
-          last_seen_at: feature3.properties.last_seen_at,
-          value: feature3.properties.value
+    br(src) {
+      const cap = this.rules.inline.br.exec(src);
+      if (cap) {
+        return {
+          type: "br",
+          raw: cap[0]
         };
-        features2.push({
-          minX: loc[0],
-          minY: loc[1],
-          maxX: loc[0],
-          maxY: loc[1],
-          data: d
-        });
-      }
-      if (cache.rtree) {
-        cache.rtree.load(features2);
       }
     }
-  }
-  function loadData(url) {
-    return fetch(url).then(function(response) {
-      if (!response.ok) {
-        throw new Error(response.status + " " + response.statusText);
-      }
-      return response.json();
-    }).then(function(result) {
-      if (!result) {
-        return [];
-      }
-      return result.data || [];
-    });
-  }
-  function partitionViewport(projection2) {
-    const z = geoScaleToZoom(projection2.scale());
-    const z2 = Math.ceil(z * 2) / 2 + 2.5;
-    const tiler8 = utilTiler().zoomExtent([z2, z2]);
-    return tiler8.getTiles(projection2).map(function(tile) {
-      return tile.extent;
-    });
-  }
-  function searchLimited(limit, projection2, rtree) {
-    limit = limit || 5;
-    return partitionViewport(projection2).reduce(function(result, extent) {
-      const found = rtree.search(extent.bbox()).slice(0, limit).map(function(d) {
-        return d.data;
-      });
-      return found.length ? result.concat(found) : result;
-    }, []);
-  }
-  var mapillary_default = {
-    init: function() {
-      if (!_mlyCache) {
-        this.reset();
-      }
-      this.event = utilRebind(this, dispatch5, "on");
-    },
-    reset: function() {
-      if (_mlyCache) {
-        Object.values(_mlyCache.requests.inflight).forEach(function(request3) {
-          request3.abort();
-        });
+    del(src) {
+      const cap = this.rules.inline.del.exec(src);
+      if (cap) {
+        return {
+          type: "del",
+          raw: cap[0],
+          text: cap[2],
+          tokens: this.lexer.inlineTokens(cap[2])
+        };
       }
-      _mlyCache = {
-        images: { rtree: new import_rbush4.default(), forImageId: {} },
-        image_detections: { forImageId: {} },
-        signs: { rtree: new import_rbush4.default() },
-        points: { rtree: new import_rbush4.default() },
-        sequences: { rtree: new import_rbush4.default(), lineString: {} },
-        requests: { loaded: {}, inflight: {} }
-      };
-      _mlyActiveImage = null;
-    },
-    images: function(projection2) {
-      const limit = 5;
-      return searchLimited(limit, projection2, _mlyCache.images.rtree);
-    },
-    signs: function(projection2) {
-      const limit = 5;
-      return searchLimited(limit, projection2, _mlyCache.signs.rtree);
-    },
-    mapFeatures: function(projection2) {
-      const limit = 5;
-      return searchLimited(limit, projection2, _mlyCache.points.rtree);
-    },
-    cachedImage: function(imageId) {
-      return _mlyCache.images.forImageId[imageId];
-    },
-    sequences: function(projection2) {
-      const viewport = projection2.clipExtent();
-      const min3 = [viewport[0][0], viewport[1][1]];
-      const max3 = [viewport[1][0], viewport[0][1]];
-      const bbox = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
-      const sequenceIds = {};
-      let lineStrings = [];
-      _mlyCache.images.rtree.search(bbox).forEach(function(d) {
-        if (d.data.sequence_id) {
-          sequenceIds[d.data.sequence_id] = true;
-        }
-      });
-      Object.keys(sequenceIds).forEach(function(sequenceId) {
-        if (_mlyCache.sequences.lineString[sequenceId]) {
-          lineStrings = lineStrings.concat(_mlyCache.sequences.lineString[sequenceId]);
-        }
-      });
-      return lineStrings;
-    },
-    loadImages: function(projection2) {
-      loadTiles("images", tileUrl, 14, projection2);
-    },
-    loadSigns: function(projection2) {
-      loadTiles("signs", trafficSignTileUrl, 14, projection2);
-    },
-    loadMapFeatures: function(projection2) {
-      loadTiles("points", mapFeatureTileUrl, 14, projection2);
-    },
-    ensureViewerLoaded: function(context) {
-      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;
-      _loadViewerPromise = new Promise((resolve, reject) => {
-        let loadedCount = 0;
-        function loaded() {
-          loadedCount += 1;
-          if (loadedCount === 2)
-            resolve();
+    }
+    autolink(src, mangle2) {
+      const cap = this.rules.inline.autolink.exec(src);
+      if (cap) {
+        let text2, href;
+        if (cap[2] === "@") {
+          text2 = escape4(this.options.mangle ? mangle2(cap[1]) : cap[1]);
+          href = "mailto:" + text2;
+        } else {
+          text2 = escape4(cap[1]);
+          href = text2;
         }
-        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() {
-          reject();
-        });
-        head.selectAll("#ideditor-mapillary-viewerjs").data([0]).enter().append("script").attr("id", "ideditor-mapillary-viewerjs").attr("crossorigin", "anonymous").attr("src", context.asset(viewerjs)).on("load.serviceMapillary", loaded).on("error.serviceMapillary", function() {
-          reject();
-        });
-      }).catch(function() {
-        _loadViewerPromise = null;
-      }).then(function() {
-        that.initViewer(context);
-      });
-      return _loadViewerPromise;
-    },
-    loadSignResources: function(context) {
-      context.ui().svgDefs.addSprites(["mapillary-sprite"], false);
-      return this;
-    },
-    loadObjectResources: function(context) {
-      context.ui().svgDefs.addSprites(["mapillary-object-sprite"], false);
-      return this;
-    },
-    resetTags: function() {
-      if (_mlyViewer && !_mlyFallback) {
-        _mlyViewer.getComponent("tag").removeAll();
+        return {
+          type: "link",
+          raw: cap[0],
+          text: text2,
+          href,
+          tokens: [
+            {
+              type: "text",
+              raw: text2,
+              text: text2
+            }
+          ]
+        };
       }
-    },
-    showFeatureDetections: function(value) {
-      _mlyShowFeatureDetections = value;
-      if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
-        this.resetTags();
+    }
+    url(src, mangle2) {
+      let cap;
+      if (cap = this.rules.inline.url.exec(src)) {
+        let text2, href;
+        if (cap[2] === "@") {
+          text2 = escape4(this.options.mangle ? mangle2(cap[0]) : cap[0]);
+          href = "mailto:" + text2;
+        } else {
+          let prevCapZero;
+          do {
+            prevCapZero = cap[0];
+            cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
+          } while (prevCapZero !== cap[0]);
+          text2 = escape4(cap[0]);
+          if (cap[1] === "www.") {
+            href = "http://" + cap[0];
+          } else {
+            href = cap[0];
+          }
+        }
+        return {
+          type: "link",
+          raw: cap[0],
+          text: text2,
+          href,
+          tokens: [
+            {
+              type: "text",
+              raw: text2,
+              text: text2
+            }
+          ]
+        };
       }
-    },
-    showSignDetections: function(value) {
-      _mlyShowSignDetections = value;
-      if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
-        this.resetTags();
+    }
+    inlineText(src, smartypants2) {
+      const cap = this.rules.inline.text.exec(src);
+      if (cap) {
+        let text2;
+        if (this.lexer.state.inRawBlock) {
+          text2 = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape4(cap[0]) : cap[0];
+        } else {
+          text2 = escape4(this.options.smartypants ? smartypants2(cap[0]) : cap[0]);
+        }
+        return {
+          type: "text",
+          raw: cap[0],
+          text: text2
+        };
       }
+    }
+  };
+  var block = {
+    newline: /^(?: *(?:\n|$))+/,
+    code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
+    fences: /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
+    hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
+    heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
+    blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
+    list: /^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/,
+    html: "^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))",
+    def: /^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,
+    table: noopTest,
+    lheading: /^((?:(?!^bull ).|\n(?!\n|bull ))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
+    // regex template, placeholders will be replaced according to different paragraph
+    // interruption rules of commonmark and the original markdown spec:
+    _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
+    text: /^[^\n]+/
+  };
+  block._label = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
+  block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
+  block.def = edit(block.def).replace("label", block._label).replace("title", block._title).getRegex();
+  block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
+  block.listItemStart = edit(/^( *)(bull) */).replace("bull", block.bullet).getRegex();
+  block.list = edit(block.list).replace(/bull/g, block.bullet).replace("hr", "\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def", "\\n+(?=" + block.def.source + ")").getRegex();
+  block._tag = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
+  block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
+  block.html = edit(block.html, "i").replace("comment", block._comment).replace("tag", block._tag).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
+  block.lheading = edit(block.lheading).replace(/bull/g, block.bullet).getRegex();
+  block.paragraph = edit(block._paragraph).replace("hr", block.hr).replace("heading", " {0,3}#{1,6} ").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", block._tag).getRegex();
+  block.blockquote = edit(block.blockquote).replace("paragraph", block.paragraph).getRegex();
+  block.normal = { ...block };
+  block.gfm = {
+    ...block.normal,
+    table: "^ *([^\\n ].*\\|.*)\\n {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"
+    // Cells
+  };
+  block.gfm.table = edit(block.gfm.table).replace("hr", block.hr).replace("heading", " {0,3}#{1,6} ").replace("blockquote", " {0,3}>").replace("code", " {4}[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", block._tag).getRegex();
+  block.gfm.paragraph = edit(block._paragraph).replace("hr", block.hr).replace("heading", " {0,3}#{1,6} ").replace("|lheading", "").replace("table", block.gfm.table).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", block._tag).getRegex();
+  block.pedantic = {
+    ...block.normal,
+    html: edit(
+      `^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`
+    ).replace("comment", block._comment).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),
+    def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
+    heading: /^(#{1,6})(.*)(?:\n+|$)/,
+    fences: noopTest,
+    // fences not supported
+    lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
+    paragraph: edit(block.normal._paragraph).replace("hr", block.hr).replace("heading", " *#{1,6} *[^\n]").replace("lheading", block.lheading).replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").getRegex()
+  };
+  var inline = {
+    escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
+    autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
+    url: noopTest,
+    tag: "^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",
+    // CDATA section
+    link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
+    reflink: /^!?\[(label)\]\[(ref)\]/,
+    nolink: /^!?\[(ref)\](?:\[\])?/,
+    reflinkSearch: "reflink|nolink(?!\\()",
+    emStrong: {
+      lDelim: /^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,
+      //         (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left.  (5) and (6) can be either Left or Right.
+      //         | Skip orphan inside strong      | Consume to delim | (1) #***              | (2) a***#, a***                    | (3) #***a, ***a                  | (4) ***#                 | (5) #***#                         | (6) a***a
+      rDelimAst: /^[^_*]*?__[^_*]*?\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\*)[punct](\*+)(?=[\s]|$)|[^punct\s](\*+)(?!\*)(?=[punct\s]|$)|(?!\*)[punct\s](\*+)(?=[^punct\s])|[\s](\*+)(?!\*)(?=[punct])|(?!\*)[punct](\*+)(?!\*)(?=[punct])|[^punct\s](\*+)(?=[^punct\s])/,
+      rDelimUnd: /^[^_*]*?\*\*[^_*]*?_[^_*]*?(?=\*\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\s]|$)|[^punct\s](_+)(?!_)(?=[punct\s]|$)|(?!_)[punct\s](_+)(?=[^punct\s])|[\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])/
+      // ^- Not allowed for _
     },
-    filterViewer: function(context) {
-      const showsPano = context.photos().showsPanoramic();
-      const showsFlat = context.photos().showsFlat();
-      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 (fromDate) {
-        filter2.push([">=", "capturedAt", new Date(fromDate).getTime()]);
-      }
-      if (toDate) {
-        filter2.push([">=", "capturedAt", new Date(toDate).getTime()]);
-      }
-      if (_mlyViewer) {
-        _mlyViewer.setFilter(filter2);
-      }
-      _mlyViewerFilter = filter2;
-      return filter2;
+    code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
+    br: /^( {2,}|\\)\n(?!\s*$)/,
+    del: noopTest,
+    text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
+    punctuation: /^((?![*_])[\spunctuation])/
+  };
+  inline._punctuation = "\\p{P}$+<=>`^|~";
+  inline.punctuation = edit(inline.punctuation, "u").replace(/punctuation/g, inline._punctuation).getRegex();
+  inline.blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
+  inline.anyPunctuation = /\\[punct]/g;
+  inline._escapes = /\\([punct])/g;
+  inline._comment = edit(block._comment).replace("(?:-->|$)", "-->").getRegex();
+  inline.emStrong.lDelim = edit(inline.emStrong.lDelim, "u").replace(/punct/g, inline._punctuation).getRegex();
+  inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, "gu").replace(/punct/g, inline._punctuation).getRegex();
+  inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, "gu").replace(/punct/g, inline._punctuation).getRegex();
+  inline.anyPunctuation = edit(inline.anyPunctuation, "gu").replace(/punct/g, inline._punctuation).getRegex();
+  inline._escapes = edit(inline._escapes, "gu").replace(/punct/g, inline._punctuation).getRegex();
+  inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
+  inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
+  inline.autolink = edit(inline.autolink).replace("scheme", inline._scheme).replace("email", inline._email).getRegex();
+  inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
+  inline.tag = edit(inline.tag).replace("comment", inline._comment).replace("attribute", inline._attribute).getRegex();
+  inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
+  inline._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
+  inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
+  inline.link = edit(inline.link).replace("label", inline._label).replace("href", inline._href).replace("title", inline._title).getRegex();
+  inline.reflink = edit(inline.reflink).replace("label", inline._label).replace("ref", block._label).getRegex();
+  inline.nolink = edit(inline.nolink).replace("ref", block._label).getRegex();
+  inline.reflinkSearch = edit(inline.reflinkSearch, "g").replace("reflink", inline.reflink).replace("nolink", inline.nolink).getRegex();
+  inline.normal = { ...inline };
+  inline.pedantic = {
+    ...inline.normal,
+    strong: {
+      start: /^__|\*\*/,
+      middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
+      endAst: /\*\*(?!\*)/g,
+      endUnd: /__(?!_)/g
     },
-    showViewer: function(context) {
-      const wrap2 = context.container().select(".photoviewer").classed("hide", false);
-      const isHidden = wrap2.selectAll(".photo-wrapper.mly-wrapper.hide").size();
-      if (isHidden && _mlyViewer) {
-        wrap2.selectAll(".photo-wrapper:not(.mly-wrapper)").classed("hide", true);
-        wrap2.selectAll(".photo-wrapper.mly-wrapper").classed("hide", false);
-        _mlyViewer.resize();
-      }
-      return this;
+    em: {
+      start: /^_|\*/,
+      middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
+      endAst: /\*(?!\*)/g,
+      endUnd: /_(?!_)/g
     },
-    hideViewer: function(context) {
-      _mlyActiveImage = null;
-      if (!_mlyFallback && _mlyViewer) {
-        _mlyViewer.getComponent("sequence").stop();
+    link: edit(/^!?\[(label)\]\((.*?)\)/).replace("label", inline._label).getRegex(),
+    reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", inline._label).getRegex()
+  };
+  inline.gfm = {
+    ...inline.normal,
+    escape: edit(inline.escape).replace("])", "~|])").getRegex(),
+    _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
+    url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
+    _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
+    del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
+    text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
+  };
+  inline.gfm.url = edit(inline.gfm.url, "i").replace("email", inline.gfm._extended_email).getRegex();
+  inline.breaks = {
+    ...inline.gfm,
+    br: edit(inline.br).replace("{2,}", "*").getRegex(),
+    text: edit(inline.gfm.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex()
+  };
+  function smartypants(text2) {
+    return text2.replace(/---/g, "\u2014").replace(/--/g, "\u2013").replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018").replace(/'/g, "\u2019").replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C").replace(/"/g, "\u201D").replace(/\.{3}/g, "\u2026");
+  }
+  function mangle(text2) {
+    let out = "", i2, ch;
+    const l = text2.length;
+    for (i2 = 0; i2 < l; i2++) {
+      ch = text2.charCodeAt(i2);
+      if (Math.random() > 0.5) {
+        ch = "x" + ch.toString(16);
       }
-      const viewer = context.container().select(".photoviewer");
-      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");
-      return this.setStyles(context, null);
-    },
-    updateUrlImage: function(imageId) {
-      if (!window.mocha) {
-        const hash = utilStringQs(window.location.hash);
-        if (imageId) {
-          hash.photo = "mapillary/" + imageId;
+      out += "&#" + ch + ";";
+    }
+    return out;
+  }
+  var Lexer = class _Lexer {
+    constructor(options2) {
+      this.tokens = [];
+      this.tokens.links = /* @__PURE__ */ Object.create(null);
+      this.options = options2 || defaults;
+      this.options.tokenizer = this.options.tokenizer || new Tokenizer();
+      this.tokenizer = this.options.tokenizer;
+      this.tokenizer.options = this.options;
+      this.tokenizer.lexer = this;
+      this.inlineQueue = [];
+      this.state = {
+        inLink: false,
+        inRawBlock: false,
+        top: true
+      };
+      const rules = {
+        block: block.normal,
+        inline: inline.normal
+      };
+      if (this.options.pedantic) {
+        rules.block = block.pedantic;
+        rules.inline = inline.pedantic;
+      } else if (this.options.gfm) {
+        rules.block = block.gfm;
+        if (this.options.breaks) {
+          rules.inline = inline.breaks;
         } else {
-          delete hash.photo;
+          rules.inline = inline.gfm;
         }
-        window.location.replace("#" + utilQsString(hash, true));
-      }
-    },
-    highlightDetection: function(detection) {
-      if (detection) {
-        _mlyHighlightedDetection = detection.id;
       }
-      return this;
-    },
-    initViewer: function(context) {
-      const that = this;
-      if (!window.mapillary)
-        return;
-      const opts = {
-        accessToken,
-        component: {
-          cover: false,
-          keyboard: false,
-          tag: true
-        },
-        container: "ideditor-mly"
+      this.tokenizer.rules = rules;
+    }
+    /**
+     * Expose Rules
+     */
+    static get rules() {
+      return {
+        block,
+        inline
       };
-      if (!mapillary.isSupported() && mapillary.isFallbackSupported()) {
-        _mlyFallback = true;
-        opts.component = {
-          cover: false,
-          direction: false,
-          imagePlane: false,
-          keyboard: false,
-          mouse: false,
-          sequence: false,
-          tag: false,
-          image: true,
-          navigation: true
-        };
-      }
-      _mlyViewer = new mapillary.Viewer(opts);
-      _mlyViewer.on("image", imageChanged);
-      _mlyViewer.on("bearing", bearingChanged);
-      if (_mlyViewerFilter) {
-        _mlyViewer.setFilter(_mlyViewerFilter);
-      }
-      context.ui().photoviewer.on("resize.mapillary", function() {
-        if (_mlyViewer)
-          _mlyViewer.resize();
-      });
-      function imageChanged(node) {
-        that.resetTags();
-        const image = node.image;
-        that.setActiveImage(image);
-        that.setStyles(context, null);
-        const loc = [image.originalLngLat.lng, image.originalLngLat.lat];
-        context.map().centerEase(loc);
-        that.updateUrlImage(image.id);
-        if (_mlyShowFeatureDetections || _mlyShowSignDetections) {
-          that.updateDetections(image.id, `${apiUrl}/${image.id}/detections?access_token=${accessToken}&fields=id,image,geometry,value`);
-        }
-        dispatch5.call("imageChanged");
-      }
-      function bearingChanged(e) {
-        dispatch5.call("bearingChanged", void 0, e);
-      }
-    },
-    selectImage: function(context, imageId) {
-      if (_mlyViewer && imageId) {
-        _mlyViewer.moveTo(imageId).catch(function(e) {
-          console.error("mly3", e);
-        });
+    }
+    /**
+     * Static Lex Method
+     */
+    static lex(src, options2) {
+      const lexer2 = new _Lexer(options2);
+      return lexer2.lex(src);
+    }
+    /**
+     * Static Lex Inline Method
+     */
+    static lexInline(src, options2) {
+      const lexer2 = new _Lexer(options2);
+      return lexer2.inlineTokens(src);
+    }
+    /**
+     * Preprocessing
+     */
+    lex(src) {
+      src = src.replace(/\r\n|\r/g, "\n");
+      this.blockTokens(src, this.tokens);
+      let next;
+      while (next = this.inlineQueue.shift()) {
+        this.inlineTokens(next.src, next.tokens);
       }
-      return this;
-    },
-    getActiveImage: function() {
-      return _mlyActiveImage;
-    },
-    getDetections: function(id2) {
-      return loadData(`${apiUrl}/${id2}/detections?access_token=${accessToken}&fields=id,value,image`);
-    },
-    setActiveImage: function(image) {
-      if (image) {
-        _mlyActiveImage = {
-          ca: image.originalCompassAngle,
-          id: image.id,
-          loc: [image.originalLngLat.lng, image.originalLngLat.lat],
-          is_pano: image.cameraType === "spherical",
-          sequence_id: image.sequenceId
-        };
+      return this.tokens;
+    }
+    /**
+     * Lexing
+     */
+    blockTokens(src, tokens = []) {
+      if (this.options.pedantic) {
+        src = src.replace(/\t/g, "    ").replace(/^ +$/gm, "");
       } else {
-        _mlyActiveImage = null;
+        src = src.replace(/^( *)(\t+)/gm, (_, leading, tabs) => {
+          return leading + "    ".repeat(tabs.length);
+        });
       }
-    },
-    setStyles: function(context, hovered) {
-      const hoveredImageId = hovered && hovered.id;
-      const hoveredSequenceId = hovered && hovered.sequence_id;
-      const selectedSequenceId = _mlyActiveImage && _mlyActiveImage.sequence_id;
-      context.container().selectAll(".layer-mapillary .viewfield-group").classed("highlighted", function(d) {
-        return d.sequence_id === selectedSequenceId || d.id === hoveredImageId;
-      }).classed("hovered", function(d) {
-        return d.id === hoveredImageId;
-      });
-      context.container().selectAll(".layer-mapillary .sequence").classed("highlighted", function(d) {
-        return d.properties.id === hoveredSequenceId;
-      }).classed("currentView", function(d) {
-        return d.properties.id === selectedSequenceId;
-      });
-      return this;
-    },
-    updateDetections: function(imageId, url) {
-      if (!_mlyViewer || _mlyFallback)
-        return;
-      if (!imageId)
-        return;
-      const cache = _mlyCache.image_detections;
-      if (cache.forImageId[imageId]) {
-        showDetections(_mlyCache.image_detections.forImageId[imageId]);
-      } else {
-        loadData(url).then((detections) => {
-          detections.forEach(function(detection) {
-            if (!cache.forImageId[imageId]) {
-              cache.forImageId[imageId] = [];
+      let token, lastToken, cutSrc, 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)) {
+            src = src.substring(token.raw.length);
+            tokens.push(token);
+            return true;
+          }
+          return false;
+        })) {
+          continue;
+        }
+        if (token = this.tokenizer.space(src)) {
+          src = src.substring(token.raw.length);
+          if (token.raw.length === 1 && tokens.length > 0) {
+            tokens[tokens.length - 1].raw += "\n";
+          } else {
+            tokens.push(token);
+          }
+          continue;
+        }
+        if (token = this.tokenizer.code(src)) {
+          src = src.substring(token.raw.length);
+          lastToken = tokens[tokens.length - 1];
+          if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
+            lastToken.raw += "\n" + token.raw;
+            lastToken.text += "\n" + token.text;
+            this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
+          } else {
+            tokens.push(token);
+          }
+          continue;
+        }
+        if (token = this.tokenizer.fences(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
+        }
+        if (token = this.tokenizer.heading(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
+        }
+        if (token = this.tokenizer.hr(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
+        }
+        if (token = this.tokenizer.blockquote(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
+        }
+        if (token = this.tokenizer.list(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
+        }
+        if (token = this.tokenizer.html(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
+        }
+        if (token = this.tokenizer.def(src)) {
+          src = src.substring(token.raw.length);
+          lastToken = tokens[tokens.length - 1];
+          if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
+            lastToken.raw += "\n" + token.raw;
+            lastToken.text += "\n" + token.raw;
+            this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
+          } else if (!this.tokens.links[token.tag]) {
+            this.tokens.links[token.tag] = {
+              href: token.href,
+              title: token.title
+            };
+          }
+          continue;
+        }
+        if (token = this.tokenizer.table(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
+        }
+        if (token = this.tokenizer.lheading(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
+        }
+        cutSrc = src;
+        if (this.options.extensions && this.options.extensions.startBlock) {
+          let startIndex = Infinity;
+          const tempSrc = src.slice(1);
+          let tempStart;
+          this.options.extensions.startBlock.forEach(function(getStartIndex) {
+            tempStart = getStartIndex.call({ lexer: this }, tempSrc);
+            if (typeof tempStart === "number" && tempStart >= 0) {
+              startIndex = Math.min(startIndex, tempStart);
             }
-            cache.forImageId[imageId].push({
-              geometry: detection.geometry,
-              id: detection.id,
-              image_id: imageId,
-              value: detection.value
-            });
           });
-          showDetections(_mlyCache.image_detections.forImageId[imageId] || []);
-        });
-      }
-      function showDetections(detections) {
-        const tagComponent = _mlyViewer.getComponent("tag");
-        detections.forEach(function(data) {
-          const tag = makeTag(data);
-          if (tag) {
-            tagComponent.add([tag]);
+          if (startIndex < Infinity && startIndex >= 0) {
+            cutSrc = src.substring(0, startIndex + 1);
           }
-        });
-      }
-      function makeTag(data) {
-        const valueParts = data.value.split("--");
-        if (!valueParts.length)
-          return;
-        let tag;
-        let text2;
-        let color2 = 16777215;
-        if (_mlyHighlightedDetection === data.id) {
-          color2 = 16776960;
-          text2 = valueParts[1];
-          if (text2 === "flat" || text2 === "discrete" || text2 === "sign") {
-            text2 = valueParts[2];
+        }
+        if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
+          lastToken = tokens[tokens.length - 1];
+          if (lastParagraphClipped && lastToken.type === "paragraph") {
+            lastToken.raw += "\n" + token.raw;
+            lastToken.text += "\n" + token.text;
+            this.inlineQueue.pop();
+            this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
+          } else {
+            tokens.push(token);
           }
-          text2 = text2.replace(/-/g, " ");
-          text2 = text2.charAt(0).toUpperCase() + text2.slice(1);
-          _mlyHighlightedDetection = null;
+          lastParagraphClipped = cutSrc.length !== src.length;
+          src = src.substring(token.raw.length);
+          continue;
         }
-        var decodedGeometry = window.atob(data.geometry);
-        var uintArray = new Uint8Array(decodedGeometry.length);
-        for (var i2 = 0; i2 < decodedGeometry.length; i2++) {
-          uintArray[i2] = decodedGeometry.charCodeAt(i2);
+        if (token = this.tokenizer.text(src)) {
+          src = src.substring(token.raw.length);
+          lastToken = tokens[tokens.length - 1];
+          if (lastToken && lastToken.type === "text") {
+            lastToken.raw += "\n" + token.raw;
+            lastToken.text += "\n" + token.text;
+            this.inlineQueue.pop();
+            this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
+          } else {
+            tokens.push(token);
+          }
+          continue;
         }
-        const tile = new import_vector_tile.VectorTile(new import_pbf.default(uintArray.buffer));
-        const layer = tile.layers["mpy-or"];
-        const geometries = layer.feature(0).loadGeometry();
-        const polygon2 = geometries.map((ring) => ring.map((point) => [point.x / layer.extent, point.y / layer.extent]));
-        tag = new mapillary.OutlineTag(
-          data.id,
-          new mapillary.PolygonGeometry(polygon2[0]),
-          {
-            text: text2,
-            textColor: color2,
-            lineColor: color2,
-            lineWidth: 2,
-            fillColor: color2,
-            fillOpacity: 0.3
+        if (src) {
+          const errMsg = "Infinite loop on byte: " + src.charCodeAt(0);
+          if (this.options.silent) {
+            console.error(errMsg);
+            break;
+          } else {
+            throw new Error(errMsg);
           }
-        );
-        return tag;
-      }
-    },
-    cache: function() {
-      return _mlyCache;
-    }
-  };
-
-  // modules/core/validation/models.js
-  function validationIssue(attrs) {
-    this.type = attrs.type;
-    this.subtype = attrs.subtype;
-    this.severity = attrs.severity;
-    this.message = attrs.message;
-    this.reference = attrs.reference;
-    this.entityIds = attrs.entityIds;
-    this.loc = attrs.loc;
-    this.data = attrs.data;
-    this.dynamicFixes = attrs.dynamicFixes;
-    this.hash = attrs.hash;
-    this.id = generateID.apply(this);
-    this.key = generateKey.apply(this);
-    this.autoFix = null;
-    function generateID() {
-      var parts = [this.type];
-      if (this.hash) {
-        parts.push(this.hash);
-      }
-      if (this.subtype) {
-        parts.push(this.subtype);
-      }
-      if (this.entityIds) {
-        var entityKeys = this.entityIds.slice().sort();
-        parts.push.apply(parts, entityKeys);
+        }
       }
-      return parts.join(":");
+      this.state.top = true;
+      return tokens;
     }
-    function generateKey() {
-      return this.id + ":" + Date.now().toString();
+    inline(src, tokens = []) {
+      this.inlineQueue.push({ src, tokens });
+      return tokens;
     }
-    this.extent = function(resolver) {
-      if (this.loc) {
-        return geoExtent(this.loc);
-      }
-      if (this.entityIds && this.entityIds.length) {
-        return this.entityIds.reduce(function(extent, entityId) {
-          return extent.extend(resolver.entity(entityId).extent(resolver));
-        }, geoExtent());
-      }
-      return null;
-    };
-    this.fixes = function(context) {
-      var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
-      var issue = this;
-      if (issue.severity === "warning") {
-        fixes.push(new validationIssueFix({
-          title: _t.append("issues.fix.ignore_issue.title"),
-          icon: "iD-icon-close",
-          onClick: function() {
-            context.validator().ignoreIssue(this.issue.id);
+    /**
+     * Lexing/Compiling
+     */
+    inlineTokens(src, tokens = []) {
+      let token, lastToken, cutSrc;
+      let maskedSrc = src;
+      let match;
+      let keepPrevChar, prevChar;
+      if (this.tokens.links) {
+        const links = Object.keys(this.tokens.links);
+        if (links.length > 0) {
+          while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
+            if (links.includes(match[0].slice(match[0].lastIndexOf("[") + 1, -1))) {
+              maskedSrc = maskedSrc.slice(0, match.index) + "[" + "a".repeat(match[0].length - 2) + "]" + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
+            }
           }
-        }));
-      }
-      fixes.forEach(function(fix) {
-        fix.id = fix.title.stringId;
-        fix.issue = issue;
-        if (fix.autoArgs) {
-          issue.autoFix = fix;
         }
-      });
-      return fixes;
-    };
-  }
-  function validationIssueFix(attrs) {
-    this.title = attrs.title;
-    this.onClick = attrs.onClick;
-    this.disabledReason = attrs.disabledReason;
-    this.icon = attrs.icon;
-    this.entityIds = attrs.entityIds || [];
-    this.autoArgs = attrs.autoArgs;
-    this.issue = null;
-  }
-
-  // modules/services/maprules.js
-  var buildRuleChecks = function() {
-    return {
-      equals: function(equals) {
-        return function(tags) {
-          return Object.keys(equals).every(function(k) {
-            return equals[k] === tags[k];
-          });
-        };
-      },
-      notEquals: function(notEquals) {
-        return function(tags) {
-          return Object.keys(notEquals).some(function(k) {
-            return notEquals[k] !== tags[k];
-          });
-        };
-      },
-      absence: function(absence) {
-        return function(tags) {
-          return Object.keys(tags).indexOf(absence) === -1;
-        };
-      },
-      presence: function(presence) {
-        return function(tags) {
-          return Object.keys(tags).indexOf(presence) > -1;
-        };
-      },
-      greaterThan: function(greaterThan) {
-        var key = Object.keys(greaterThan)[0];
-        var value = greaterThan[key];
-        return function(tags) {
-          return tags[key] > value;
-        };
-      },
-      greaterThanEqual: function(greaterThanEqual) {
-        var key = Object.keys(greaterThanEqual)[0];
-        var value = greaterThanEqual[key];
-        return function(tags) {
-          return tags[key] >= value;
-        };
-      },
-      lessThan: function(lessThan) {
-        var key = Object.keys(lessThan)[0];
-        var value = lessThan[key];
-        return function(tags) {
-          return tags[key] < value;
-        };
-      },
-      lessThanEqual: function(lessThanEqual) {
-        var key = Object.keys(lessThanEqual)[0];
-        var value = lessThanEqual[key];
-        return function(tags) {
-          return tags[key] <= value;
-        };
-      },
-      positiveRegex: function(positiveRegex) {
-        var tagKey = Object.keys(positiveRegex)[0];
-        var expression = positiveRegex[tagKey].join("|");
-        var regex = new RegExp(expression);
-        return function(tags) {
-          return regex.test(tags[tagKey]);
-        };
-      },
-      negativeRegex: function(negativeRegex) {
-        var tagKey = Object.keys(negativeRegex)[0];
-        var expression = negativeRegex[tagKey].join("|");
-        var regex = new RegExp(expression);
-        return function(tags) {
-          return !regex.test(tags[tagKey]);
-        };
       }
-    };
-  };
-  var buildLineKeys = function() {
-    return {
-      highway: {
-        rest_area: true,
-        services: true
-      },
-      railway: {
-        roundhouse: true,
-        station: true,
-        traverser: true,
-        turntable: true,
-        wash: true
+      while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
+        maskedSrc = maskedSrc.slice(0, match.index) + "[" + "a".repeat(match[0].length - 2) + "]" + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
       }
-    };
-  };
-  var maprules_default = {
-    init: function() {
-      this._ruleChecks = buildRuleChecks();
-      this._validationRules = [];
-      this._areaKeys = osmAreaKeys;
-      this._lineKeys = buildLineKeys();
-    },
-    filterRuleChecks: function(selector) {
-      var _ruleChecks = this._ruleChecks;
-      return Object.keys(selector).reduce(function(rules, key) {
-        if (["geometry", "error", "warning"].indexOf(key) === -1) {
-          rules.push(_ruleChecks[key](selector[key]));
+      while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {
+        maskedSrc = maskedSrc.slice(0, match.index) + "++" + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
+      }
+      while (src) {
+        if (!keepPrevChar) {
+          prevChar = "";
         }
-        return rules;
-      }, []);
-    },
-    buildTagMap: function(selector) {
-      var getRegexValues = function(regexes) {
-        return regexes.map(function(regex) {
-          return regex.replace(/\$|\^/g, "");
-        });
-      };
-      var tagMap = Object.keys(selector).reduce(function(expectedTags, key) {
-        var values;
-        var isRegex = /regex/gi.test(key);
-        var isEqual = /equals/gi.test(key);
-        if (isRegex || isEqual) {
-          Object.keys(selector[key]).forEach(function(selectorKey) {
-            values = isEqual ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
-            if (expectedTags.hasOwnProperty(selectorKey)) {
-              values = values.concat(expectedTags[selectorKey]);
-            }
-            expectedTags[selectorKey] = values;
-          });
-        } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
-          var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
-          values = [selector[key][tagKey]];
-          if (expectedTags.hasOwnProperty(tagKey)) {
-            values = values.concat(expectedTags[tagKey]);
+        keepPrevChar = false;
+        if (this.options.extensions && this.options.extensions.inline && this.options.extensions.inline.some((extTokenizer) => {
+          if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
+            src = src.substring(token.raw.length);
+            tokens.push(token);
+            return true;
           }
-          expectedTags[tagKey] = values;
-        }
-        return expectedTags;
-      }, {});
-      return tagMap;
-    },
-    inferGeometry: function(tagMap) {
-      var _lineKeys = this._lineKeys;
-      var _areaKeys = this._areaKeys;
-      var keyValueDoesNotImplyArea = function(key2) {
-        return utilArrayIntersection(tagMap[key2], Object.keys(_areaKeys[key2])).length > 0;
-      };
-      var keyValueImpliesLine = function(key2) {
-        return utilArrayIntersection(tagMap[key2], Object.keys(_lineKeys[key2])).length > 0;
-      };
-      if (tagMap.hasOwnProperty("area")) {
-        if (tagMap.area.indexOf("yes") > -1) {
-          return "area";
+          return false;
+        })) {
+          continue;
         }
-        if (tagMap.area.indexOf("no") > -1) {
-          return "line";
+        if (token = this.tokenizer.escape(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-      }
-      for (var key in tagMap) {
-        if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
-          return "area";
+        if (token = this.tokenizer.tag(src)) {
+          src = src.substring(token.raw.length);
+          lastToken = tokens[tokens.length - 1];
+          if (lastToken && token.type === "text" && lastToken.type === "text") {
+            lastToken.raw += token.raw;
+            lastToken.text += token.text;
+          } else {
+            tokens.push(token);
+          }
+          continue;
         }
-        if (key in _lineKeys && keyValueImpliesLine(key)) {
-          return "area";
+        if (token = this.tokenizer.link(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-      }
-      return "line";
-    },
-    addRule: function(selector) {
-      var rule = {
-        checks: this.filterRuleChecks(selector),
-        matches: function(entity) {
-          return this.checks.every(function(check) {
-            return check(entity.tags);
-          });
-        },
-        inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
-        geometryMatches: function(entity, graph) {
-          if (entity.type === "node" || entity.type === "relation") {
-            return selector.geometry === entity.type;
-          } else if (entity.type === "way") {
-            return this.inferredGeometry === entity.geometry(graph);
-          }
-        },
-        findIssues: function(entity, graph, issues) {
-          if (this.geometryMatches(entity, graph) && this.matches(entity)) {
-            var severity = Object.keys(selector).indexOf("error") > -1 ? "error" : "warning";
-            var message = selector[severity];
-            issues.push(new validationIssue({
-              type: "maprules",
-              severity,
-              message: function() {
-                return message;
-              },
-              entityIds: [entity.id]
-            }));
+        if (token = this.tokenizer.reflink(src, this.tokens.links)) {
+          src = src.substring(token.raw.length);
+          lastToken = tokens[tokens.length - 1];
+          if (lastToken && token.type === "text" && lastToken.type === "text") {
+            lastToken.raw += token.raw;
+            lastToken.text += token.text;
+          } else {
+            tokens.push(token);
           }
+          continue;
         }
-      };
-      this._validationRules.push(rule);
-    },
-    clearRules: function() {
-      this._validationRules = [];
-    },
-    validationRules: function() {
-      return this._validationRules;
-    },
-    ruleChecks: function() {
-      return this._ruleChecks;
-    }
-  };
-
-  // modules/services/nominatim.js
-  var import_rbush5 = __toESM(require_rbush_min());
-  var apibase = "https://nominatim.openstreetmap.org/";
-  var _inflight = {};
-  var _nominatimCache;
-  var nominatim_default = {
-    init: function() {
-      _inflight = {};
-      _nominatimCache = new import_rbush5.default();
-    },
-    reset: function() {
-      Object.values(_inflight).forEach(function(controller) {
-        controller.abort();
-      });
-      _inflight = {};
-      _nominatimCache = new import_rbush5.default();
-    },
-    countryCode: function(location, callback) {
-      this.reverse(location, function(err, result) {
-        if (err) {
-          return callback(err);
-        } else if (result.address) {
-          return callback(null, result.address.country_code);
-        } else {
-          return callback("Unable to geocode", null);
+        if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-      });
-    },
-    reverse: function(loc, callback) {
-      var cached = _nominatimCache.search(
-        { minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1] }
-      );
-      if (cached.length > 0) {
-        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;
-      var controller = new AbortController();
-      _inflight[url] = controller;
-      json_default(url, { signal: controller.signal }).then(function(result) {
-        delete _inflight[url];
-        if (result && result.error) {
-          throw new Error(result.error);
+        if (token = this.tokenizer.codespan(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-        var extent = geoExtent(loc).padByMeters(200);
-        _nominatimCache.insert(Object.assign(extent.bbox(), { data: result }));
-        if (callback)
-          callback(null, result);
-      }).catch(function(err) {
-        delete _inflight[url];
-        if (err.name === "AbortError")
-          return;
-        if (callback)
-          callback(err.message);
-      });
-    },
-    search: function(val, callback) {
-      var searchVal = encodeURIComponent(val);
-      var url = apibase + "search/" + searchVal + "?limit=10&format=json";
-      if (_inflight[url])
-        return;
-      var controller = new AbortController();
-      _inflight[url] = controller;
-      json_default(url, { signal: controller.signal }).then(function(result) {
-        delete _inflight[url];
-        if (result && result.error) {
-          throw new Error(result.error);
+        if (token = this.tokenizer.br(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-        if (callback)
-          callback(null, result);
-      }).catch(function(err) {
-        delete _inflight[url];
-        if (err.name === "AbortError")
-          return;
-        if (callback)
-          callback(err.message);
-      });
-    }
-  };
-
-  // node_modules/name-suggestion-index/lib/matcher.js
-  var import_which_polygon3 = __toESM(require_which_polygon(), 1);
-
-  // node_modules/name-suggestion-index/lib/simplify.js
-  var import_diacritics2 = __toESM(require_diacritics(), 1);
-  function simplify(str2) {
-    if (typeof str2 !== "string")
-      return "";
-    return import_diacritics2.default.remove(
-      str2.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()
-    );
-  }
-
-  // node_modules/name-suggestion-index/config/matchGroups.json
-  var matchGroups_default = {
-    matchGroups: {
-      adult_gaming_centre: [
-        "amenity/casino",
-        "amenity/gambling",
-        "leisure/adult_gaming_centre"
-      ],
-      beauty: [
-        "shop/beauty",
-        "shop/hairdresser_supply"
-      ],
-      bed: [
-        "shop/bed",
-        "shop/furniture"
-      ],
-      beverages: [
-        "shop/alcohol",
-        "shop/beer",
-        "shop/beverages",
-        "shop/kiosk",
-        "shop/wine"
-      ],
-      camping: [
-        "tourism/camp_site",
-        "tourism/caravan_site"
-      ],
-      car_parts: [
-        "shop/car_parts",
-        "shop/car_repair",
-        "shop/tires",
-        "shop/tyres"
-      ],
-      clinic: [
-        "amenity/clinic",
-        "amenity/doctors",
-        "healthcare/clinic",
-        "healthcare/laboratory",
-        "healthcare/physiotherapist",
-        "healthcare/sample_collection",
-        "healthcare/dialysis"
-      ],
-      convenience: [
-        "shop/beauty",
-        "shop/chemist",
-        "shop/convenience",
-        "shop/cosmetics",
-        "shop/grocery",
-        "shop/kiosk",
-        "shop/newsagent",
-        "shop/perfumery"
-      ],
-      coworking: [
-        "amenity/coworking_space",
-        "office/coworking",
-        "office/coworking_space"
-      ],
-      dentist: [
-        "amenity/dentist",
-        "amenity/doctors",
-        "healthcare/dentist"
-      ],
-      electronics: [
-        "office/telecommunication",
-        "shop/computer",
-        "shop/electronics",
-        "shop/hifi",
-        "shop/kiosk",
-        "shop/mobile",
-        "shop/mobile_phone",
-        "shop/telecommunication"
-      ],
-      fabric: [
-        "shop/fabric",
-        "shop/haberdashery",
-        "shop/sewing"
-      ],
-      fashion: [
-        "shop/accessories",
-        "shop/bag",
-        "shop/boutique",
-        "shop/clothes",
-        "shop/department_store",
-        "shop/fashion",
-        "shop/fashion_accessories",
-        "shop/sports",
-        "shop/shoes"
-      ],
-      financial: [
-        "amenity/bank",
-        "office/accountant",
-        "office/financial",
-        "office/financial_advisor",
-        "office/tax_advisor",
-        "shop/tax"
-      ],
-      fitness: [
-        "leisure/fitness_centre",
-        "leisure/fitness_center",
-        "leisure/sports_centre",
-        "leisure/sports_center"
-      ],
-      food: [
-        "amenity/bar",
-        "amenity/cafe",
-        "amenity/fast_food",
-        "amenity/ice_cream",
-        "amenity/pub",
-        "amenity/restaurant",
-        "shop/bakery",
-        "shop/candy",
-        "shop/chocolate",
-        "shop/coffee",
-        "shop/confectionary",
-        "shop/confectionery",
-        "shop/food",
-        "shop/kiosk",
-        "shop/ice_cream",
-        "shop/pastry",
-        "shop/tea"
-      ],
-      fuel: [
-        "amenity/fuel",
-        "shop/gas",
-        "shop/convenience;gas",
-        "shop/gas;convenience"
-      ],
-      gift: [
-        "shop/gift",
-        "shop/card",
-        "shop/cards",
-        "shop/kiosk",
-        "shop/stationery"
-      ],
-      hardware: [
-        "shop/bathroom_furnishing",
-        "shop/carpet",
-        "shop/diy",
-        "shop/doityourself",
-        "shop/doors",
-        "shop/electrical",
-        "shop/flooring",
-        "shop/hardware",
-        "shop/hardware_store",
-        "shop/power_tools",
-        "shop/tool_hire",
-        "shop/tools",
-        "shop/trade"
-      ],
-      health_food: [
-        "shop/health",
-        "shop/health_food",
-        "shop/herbalist",
-        "shop/nutrition_supplements"
-      ],
-      hobby: [
-        "shop/electronics",
-        "shop/hobby",
-        "shop/books",
-        "shop/games",
-        "shop/collector",
-        "shop/toys",
-        "shop/model",
-        "shop/video_games",
-        "shop/anime"
-      ],
-      hospital: [
-        "amenity/doctors",
-        "amenity/hospital",
-        "healthcare/hospital"
-      ],
-      houseware: [
-        "shop/houseware",
-        "shop/interior_decoration"
-      ],
-      lifeboat_station: [
-        "amenity/lifeboat_station",
-        "emergency/lifeboat_station",
-        "emergency/marine_rescue"
-      ],
-      lodging: [
-        "tourism/hotel",
-        "tourism/motel"
-      ],
-      money_transfer: [
-        "amenity/money_transfer",
-        "shop/money_transfer"
-      ],
-      office_supplies: [
-        "shop/office_supplies",
-        "shop/stationary",
-        "shop/stationery"
-      ],
-      outdoor: [
-        "shop/clothes",
-        "shop/outdoor",
-        "shop/sports"
-      ],
-      parcel_locker: [
-        "amenity/parcel_locker",
-        "amenity/vending_machine"
-      ],
-      pharmacy: [
-        "amenity/doctors",
-        "amenity/pharmacy",
-        "healthcare/pharmacy"
-      ],
-      playground: [
-        "amenity/theme_park",
-        "leisure/amusement_arcade",
-        "leisure/playground"
-      ],
-      rental: [
-        "amenity/bicycle_rental",
-        "amenity/boat_rental",
-        "amenity/car_rental",
-        "amenity/truck_rental",
-        "amenity/vehicle_rental",
-        "shop/kiosk",
-        "shop/rental"
-      ],
-      school: [
-        "amenity/childcare",
-        "amenity/college",
-        "amenity/kindergarten",
-        "amenity/language_school",
-        "amenity/prep_school",
-        "amenity/school",
-        "amenity/university"
-      ],
-      storage: [
-        "shop/storage_units",
-        "shop/storage_rental"
-      ],
-      substation: [
-        "power/station",
-        "power/substation",
-        "power/sub_station"
-      ],
-      supermarket: [
-        "shop/food",
-        "shop/frozen_food",
-        "shop/greengrocer",
-        "shop/grocery",
-        "shop/supermarket",
-        "shop/wholesale"
-      ],
-      variety_store: [
-        "shop/variety_store",
-        "shop/discount",
-        "shop/convenience"
-      ],
-      vending: [
-        "amenity/vending_machine",
-        "shop/kiosk",
-        "shop/vending_machine"
-      ],
-      weight_loss: [
-        "amenity/clinic",
-        "amenity/doctors",
-        "amenity/weight_clinic",
-        "healthcare/counselling",
-        "leisure/fitness_centre",
-        "office/therapist",
-        "shop/beauty",
-        "shop/diet",
-        "shop/food",
-        "shop/health_food",
-        "shop/herbalist",
-        "shop/nutrition",
-        "shop/nutrition_supplements",
-        "shop/weight_loss"
-      ],
-      wholesale: [
-        "shop/wholesale",
-        "shop/supermarket",
-        "shop/department_store"
-      ]
-    }
-  };
-
-  // node_modules/name-suggestion-index/config/genericWords.json
-  var genericWords_default = {
-    genericWords: [
-      "^(barn|bazaa?r|bench|bou?tique|building|casa|church)$",
-      "^(baseball|basketball|football|soccer|softball|tennis(halle)?)\\s?(field|court)?$",
-      "^(club|green|out|ware)\\s?house$",
-      "^(driveway|el \xE1rbol|fountain|generic|golf|government|graveyard)$",
-      "^(fixme|n\\s?\\/?\\s?a|name|no\\s?name|none|null|temporary|test|unknown)$",
-      "^(hofladen|librairie|magazine?|maison)$",
-      "^(mobile home|skate)?\\s?park$",
-      "^(obuwie|pond|pool|sale|shops?|sklep|stores?)$",
-      "^\\?+$",
-      "^private$",
-      "^tattoo( studio)?$",
-      "^windmill$",
-      "^\u0446\u0435\u0440\u043A\u043E\u0432\u043D\u0430\u044F( \u043B\u0430\u0432\u043A\u0430)?$"
-    ]
-  };
-
-  // node_modules/name-suggestion-index/config/trees.json
-  var trees_default = {
-    trees: {
-      brands: {
-        emoji: "\u{1F354}",
-        mainTag: "brand:wikidata",
-        sourceTags: ["brand", "name"],
-        nameTags: {
-          primary: "^(name|name:\\w+)$",
-          alternate: "^(brand|brand:\\w+|operator|operator:\\w+|\\w+_name|\\w+_name:\\w+)$"
+        if (token = this.tokenizer.del(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-      },
-      flags: {
-        emoji: "\u{1F6A9}",
-        mainTag: "flag:wikidata",
-        nameTags: {
-          primary: "^(flag:name|flag:name:\\w+)$",
-          alternate: "^(country|country:\\w+|flag|flag:\\w+|subject|subject:\\w+)$"
+        if (token = this.tokenizer.autolink(src, mangle)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-      },
-      operators: {
-        emoji: "\u{1F4BC}",
-        mainTag: "operator:wikidata",
-        sourceTags: ["operator"],
-        nameTags: {
-          primary: "^(name|name:\\w+|operator|operator:\\w+)$",
-          alternate: "^(brand|brand:\\w+|\\w+_name|\\w+_name:\\w+)$"
+        if (!this.state.inLink && (token = this.tokenizer.url(src, mangle))) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-      },
-      transit: {
-        emoji: "\u{1F687}",
-        mainTag: "network:wikidata",
-        sourceTags: ["network"],
-        nameTags: {
-          primary: "^network$",
-          alternate: "^(operator|operator:\\w+|network:\\w+|\\w+_name|\\w+_name:\\w+)$"
+        cutSrc = src;
+        if (this.options.extensions && this.options.extensions.startInline) {
+          let startIndex = Infinity;
+          const tempSrc = src.slice(1);
+          let tempStart;
+          this.options.extensions.startInline.forEach(function(getStartIndex) {
+            tempStart = getStartIndex.call({ lexer: this }, tempSrc);
+            if (typeof tempStart === "number" && tempStart >= 0) {
+              startIndex = Math.min(startIndex, tempStart);
+            }
+          });
+          if (startIndex < Infinity && startIndex >= 0) {
+            cutSrc = src.substring(0, startIndex + 1);
+          }
+        }
+        if (token = this.tokenizer.inlineText(cutSrc, smartypants)) {
+          src = src.substring(token.raw.length);
+          if (token.raw.slice(-1) !== "_") {
+            prevChar = token.raw.slice(-1);
+          }
+          keepPrevChar = true;
+          lastToken = tokens[tokens.length - 1];
+          if (lastToken && lastToken.type === "text") {
+            lastToken.raw += token.raw;
+            lastToken.text += token.text;
+          } else {
+            tokens.push(token);
+          }
+          continue;
+        }
+        if (src) {
+          const errMsg = "Infinite loop on byte: " + src.charCodeAt(0);
+          if (this.options.silent) {
+            console.error(errMsg);
+            break;
+          } else {
+            throw new Error(errMsg);
+          }
         }
       }
+      return tokens;
     }
   };
-
-  // node_modules/name-suggestion-index/lib/matcher.js
-  var matchGroups = matchGroups_default.matchGroups;
-  var trees = trees_default.trees;
-  var Matcher = class {
-    constructor() {
-      this.matchIndex = void 0;
-      this.genericWords = /* @__PURE__ */ new Map();
-      (genericWords_default.genericWords || []).forEach((s) => this.genericWords.set(s, new RegExp(s, "i")));
-      this.itemLocation = void 0;
-      this.locationSets = void 0;
-      this.locationIndex = void 0;
-      this.warnings = [];
+  var Renderer = class {
+    constructor(options2) {
+      this.options = options2 || defaults;
     }
-    buildMatchIndex(data) {
-      const that = this;
-      if (that.matchIndex)
-        return;
-      that.matchIndex = /* @__PURE__ */ new Map();
-      const seenTree = /* @__PURE__ */ new Map();
-      Object.keys(data).forEach((tkv) => {
-        const category = data[tkv];
-        const parts = tkv.split("/", 3);
-        const t = parts[0];
-        const k = parts[1];
-        const v = parts[2];
-        const thiskv = `${k}/${v}`;
-        const tree = trees[t];
-        let branch = that.matchIndex.get(thiskv);
-        if (!branch) {
-          branch = {
-            primary: /* @__PURE__ */ new Map(),
-            alternate: /* @__PURE__ */ new Map(),
-            excludeGeneric: /* @__PURE__ */ new Map(),
-            excludeNamed: /* @__PURE__ */ new Map()
-          };
-          that.matchIndex.set(thiskv, branch);
-        }
-        const properties = category.properties || {};
-        const exclude = properties.exclude || {};
-        (exclude.generic || []).forEach((s) => branch.excludeGeneric.set(s, new RegExp(s, "i")));
-        (exclude.named || []).forEach((s) => branch.excludeNamed.set(s, new RegExp(s, "i")));
-        const excludeRegexes = [...branch.excludeGeneric.values(), ...branch.excludeNamed.values()];
-        let items = category.items;
-        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 skipGenericKV = skipGenericKVMatches(t, k, v);
-        const genericKV = /* @__PURE__ */ new Set([`${k}/yes`, `building/yes`]);
-        const matchGroupKV = /* @__PURE__ */ new Set();
-        Object.values(matchGroups).forEach((matchGroup) => {
-          const inGroup = matchGroup.some((otherkv) => otherkv === thiskv);
-          if (!inGroup)
-            return;
-          matchGroup.forEach((otherkv) => {
-            if (otherkv === thiskv)
-              return;
-            matchGroupKV.add(otherkv);
-            const otherk = otherkv.split("/", 2)[0];
-            genericKV.add(`${otherk}/yes`);
-          });
-        });
-        items.forEach((item) => {
-          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;
-          }
-          let kvTags = [`${thiskv}`].concat(item.matchTags || []);
-          if (!skipGenericKV) {
-            kvTags = kvTags.concat(Array.from(genericKV));
-          }
-          Object.keys(item.tags).forEach((osmkey) => {
-            if (notName.test(osmkey))
-              return;
-            const osmvalue = item.tags[osmkey];
-            if (!osmvalue || excludeRegexes.some((regex) => regex.test(osmvalue)))
-              return;
-            if (primaryName.test(osmkey)) {
-              kvTags.forEach((kv) => insertName("primary", t, kv, simplify(osmvalue), item.id));
-            } else if (alternateName.test(osmkey)) {
-              kvTags.forEach((kv) => insertName("alternate", t, kv, simplify(osmvalue), item.id));
-            }
-          });
-          let keepMatchNames = /* @__PURE__ */ new Set();
-          (item.matchNames || []).forEach((matchName) => {
-            const nsimple = simplify(matchName);
-            kvTags.forEach((kv) => {
-              const branch2 = that.matchIndex.get(kv);
-              const primaryLeaf = branch2 && branch2.primary.get(nsimple);
-              const alternateLeaf = branch2 && branch2.alternate.get(nsimple);
-              const inPrimary = primaryLeaf && primaryLeaf.has(item.id);
-              const inAlternate = alternateLeaf && alternateLeaf.has(item.id);
-              if (!inPrimary && !inAlternate) {
-                insertName("alternate", t, kv, nsimple, item.id);
-                keepMatchNames.add(matchName);
-              }
-            });
-          });
-          if (keepMatchNames.size) {
-            item.matchNames = Array.from(keepMatchNames);
-          } else {
-            delete item.matchNames;
-          }
-        });
-      });
-      function insertName(which, t, kv, nsimple, itemID) {
-        if (!nsimple) {
-          that.warnings.push(`Warning: skipping empty ${which} name for item ${t}/${kv}: ${itemID}`);
-          return;
-        }
-        let branch = that.matchIndex.get(kv);
-        if (!branch) {
-          branch = {
-            primary: /* @__PURE__ */ new Map(),
-            alternate: /* @__PURE__ */ new Map(),
-            excludeGeneric: /* @__PURE__ */ new Map(),
-            excludeNamed: /* @__PURE__ */ new Map()
-          };
-          that.matchIndex.set(kv, branch);
-        }
-        let leaf = branch[which].get(nsimple);
-        if (!leaf) {
-          leaf = /* @__PURE__ */ new Set();
-          branch[which].set(nsimple, leaf);
-        }
-        leaf.add(itemID);
-        if (!/yes$/.test(kv)) {
-          const kvnsimple = `${kv}/${nsimple}`;
-          const existing = seenTree.get(kvnsimple);
-          if (existing && existing !== t) {
-            const items = Array.from(leaf);
-            that.warnings.push(`Duplicate cache key "${kvnsimple}" in trees "${t}" and "${existing}", check items: ${items}`);
-            return;
-          }
-          seenTree.set(kvnsimple, t);
+    code(code, infostring, escaped) {
+      const lang = (infostring || "").match(/\S*/)[0];
+      if (this.options.highlight) {
+        const out = this.options.highlight(code, lang);
+        if (out != null && out !== code) {
+          escaped = true;
+          code = out;
         }
       }
-      function skipGenericKVMatches(t, k, v) {
-        return t === "flags" || t === "transit" || k === "landuse" || v === "atm" || v === "bicycle_parking" || v === "car_sharing" || v === "caravan_site" || v === "charging_station" || v === "dog_park" || v === "parking" || v === "phone" || v === "playground" || v === "post_box" || v === "public_bookcase" || v === "recycling" || v === "vending_machine";
+      code = code.replace(/\n$/, "") + "\n";
+      if (!lang) {
+        return "<pre><code>" + (escaped ? code : escape4(code, true)) + "</code></pre>\n";
       }
+      return '<pre><code class="' + this.options.langPrefix + escape4(lang) + '">' + (escaped ? code : escape4(code, true)) + "</code></pre>\n";
     }
-    buildLocationIndex(data, loco) {
-      const that = this;
-      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;
-        items.forEach((item) => {
-          if (that.itemLocation.has(item.id))
-            return;
-          let resolved;
-          try {
-            resolved = loco.resolveLocationSet(item.locationSet);
-          } catch (err) {
-            console.warn(`buildLocationIndex: ${err.message}`);
-          }
-          if (!resolved || !resolved.id)
-            return;
-          that.itemLocation.set(item.id, resolved.id);
-          if (that.locationSets.has(resolved.id))
-            return;
-          let feature3 = _cloneDeep2(resolved.feature);
-          feature3.id = resolved.id;
-          feature3.properties.id = resolved.id;
-          if (!feature3.geometry.coordinates.length || !feature3.properties.area) {
-            console.warn(`buildLocationIndex: locationSet ${resolved.id} for ${item.id} resolves to an empty feature:`);
-            console.warn(JSON.stringify(feature3));
-            return;
-          }
-          that.locationSets.set(resolved.id, feature3);
-        });
-      });
-      that.locationIndex = (0, import_which_polygon3.default)({ type: "FeatureCollection", features: [...that.locationSets.values()] });
-      function _cloneDeep2(obj) {
-        return JSON.parse(JSON.stringify(obj));
+    /**
+     * @param {string} quote
+     */
+    blockquote(quote2) {
+      return `<blockquote>
+${quote2}</blockquote>
+`;
+    }
+    html(html2, block2) {
+      return html2;
+    }
+    /**
+     * @param {string} text
+     * @param {string} level
+     * @param {string} raw
+     * @param {any} slugger
+     */
+    heading(text2, level, raw, slugger) {
+      if (this.options.headerIds) {
+        const id2 = this.options.headerPrefix + slugger.slug(raw);
+        return `<h${level} id="${id2}">${text2}</h${level}>
+`;
       }
+      return `<h${level}>${text2}</h${level}>
+`;
     }
-    match(k, v, n2, loc) {
-      const that = this;
-      if (!that.matchIndex) {
-        throw new Error("match:  matchIndex not built.");
+    hr() {
+      return this.options.xhtml ? "<hr/>\n" : "<hr>\n";
+    }
+    list(body, ordered, start2) {
+      const type2 = ordered ? "ol" : "ul", startatt = ordered && start2 !== 1 ? ' start="' + start2 + '"' : "";
+      return "<" + type2 + startatt + ">\n" + body + "</" + type2 + ">\n";
+    }
+    /**
+     * @param {string} text
+     */
+    listitem(text2) {
+      return `<li>${text2}</li>
+`;
+    }
+    checkbox(checked) {
+      return "<input " + (checked ? 'checked="" ' : "") + 'disabled="" type="checkbox"' + (this.options.xhtml ? " /" : "") + "> ";
+    }
+    /**
+     * @param {string} text
+     */
+    paragraph(text2) {
+      return `<p>${text2}</p>
+`;
+    }
+    /**
+     * @param {string} header
+     * @param {string} body
+     */
+    table(header, body) {
+      if (body)
+        body = `<tbody>${body}</tbody>`;
+      return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n";
+    }
+    /**
+     * @param {string} content
+     */
+    tablerow(content) {
+      return `<tr>
+${content}</tr>
+`;
+    }
+    tablecell(content, flags) {
+      const type2 = flags.header ? "th" : "td";
+      const tag = flags.align ? `<${type2} align="${flags.align}">` : `<${type2}>`;
+      return tag + content + `</${type2}>
+`;
+    }
+    /**
+     * span level renderer
+     * @param {string} text
+     */
+    strong(text2) {
+      return `<strong>${text2}</strong>`;
+    }
+    /**
+     * @param {string} text
+     */
+    em(text2) {
+      return `<em>${text2}</em>`;
+    }
+    /**
+     * @param {string} text
+     */
+    codespan(text2) {
+      return `<code>${text2}</code>`;
+    }
+    br() {
+      return this.options.xhtml ? "<br/>" : "<br>";
+    }
+    /**
+     * @param {string} text
+     */
+    del(text2) {
+      return `<del>${text2}</del>`;
+    }
+    /**
+     * @param {string} href
+     * @param {string} title
+     * @param {string} text
+     */
+    link(href, title, text2) {
+      href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
+      if (href === null) {
+        return text2;
       }
-      let matchLocations;
-      if (Array.isArray(loc) && that.locationIndex) {
-        matchLocations = that.locationIndex([loc[0], loc[1], loc[0], loc[1]], true);
+      let out = '<a href="' + href + '"';
+      if (title) {
+        out += ' title="' + title + '"';
       }
-      const nsimple = simplify(n2);
-      let seen = /* @__PURE__ */ new Set();
-      let results = [];
-      gatherResults("primary");
-      gatherResults("alternate");
-      if (results.length)
-        return results;
-      gatherResults("exclude");
-      return results.length ? results : null;
-      function gatherResults(which) {
-        const kv = `${k}/${v}`;
-        let didMatch = tryMatch(which, kv);
-        if (didMatch)
-          return;
-        for (let mg in matchGroups) {
-          const matchGroup = matchGroups[mg];
-          const inGroup = matchGroup.some((otherkv) => otherkv === kv);
-          if (!inGroup)
-            continue;
-          for (let i2 = 0; i2 < matchGroup.length; i2++) {
-            const otherkv = matchGroup[i2];
-            if (otherkv === kv)
-              continue;
-            didMatch = tryMatch(which, otherkv);
-            if (didMatch)
-              return;
-          }
-        }
-        if (which === "exclude") {
-          const regex = [...that.genericWords.values()].find((regex2) => regex2.test(n2));
-          if (regex) {
-            results.push({ match: "excludeGeneric", pattern: String(regex) });
-            return;
-          }
-        }
+      out += ">" + text2 + "</a>";
+      return out;
+    }
+    /**
+     * @param {string} href
+     * @param {string} title
+     * @param {string} text
+     */
+    image(href, title, text2) {
+      href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
+      if (href === null) {
+        return text2;
       }
-      function tryMatch(which, kv) {
-        const branch = that.matchIndex.get(kv);
-        if (!branch)
-          return;
-        if (which === "exclude") {
-          let regex = [...branch.excludeNamed.values()].find((regex2) => regex2.test(n2));
-          if (regex) {
-            results.push({ match: "excludeNamed", pattern: String(regex), kv });
-            return;
-          }
-          regex = [...branch.excludeGeneric.values()].find((regex2) => regex2.test(n2));
-          if (regex) {
-            results.push({ match: "excludeGeneric", pattern: String(regex), kv });
-            return;
-          }
-          return;
-        }
-        const leaf = branch[which].get(nsimple);
-        if (!leaf || !leaf.size)
-          return;
-        let hits = Array.from(leaf).map((itemID) => {
-          let area = Infinity;
-          if (that.itemLocation && that.locationSets) {
-            const location = that.locationSets.get(that.itemLocation.get(itemID));
-            area = location && location.properties.area || Infinity;
-          }
-          return { match: which, itemID, area, kv, nsimple };
-        });
-        let sortFn = byAreaDescending;
-        if (matchLocations) {
-          hits = hits.filter(isValidLocation);
-          sortFn = byAreaAscending;
-        }
-        if (!hits.length)
-          return;
-        hits.sort(sortFn).forEach((hit) => {
-          if (seen.has(hit.itemID))
-            return;
-          seen.add(hit.itemID);
-          results.push(hit);
-        });
-        return true;
-        function isValidLocation(hit) {
-          if (!that.itemLocation)
-            return true;
-          return matchLocations.find((props) => props.id === that.itemLocation.get(hit.itemID));
-        }
-        function byAreaAscending(hitA, hitB) {
-          return hitA.area - hitB.area;
-        }
-        function byAreaDescending(hitA, hitB) {
-          return hitB.area - hitA.area;
-        }
+      let out = `<img src="${href}" alt="${text2}"`;
+      if (title) {
+        out += ` title="${title}"`;
       }
+      out += this.options.xhtml ? "/>" : ">";
+      return out;
     }
-    getWarnings() {
-      return this.warnings;
+    text(text2) {
+      return text2;
     }
   };
-
-  // modules/services/nsi.js
-  var import_vparse2 = __toESM(require_vparse());
-
-  // modules/core/difference.js
-  var import_fast_deep_equal3 = __toESM(require_fast_deep_equal());
-  function coreDifference(base, head) {
-    var _changes = {};
-    var _didChange = {};
-    var _diff = {};
-    function checkEntityID(id2) {
-      var h = head.entities[id2];
-      var b = base.entities[id2];
-      if (h === b)
-        return;
-      if (_changes[id2])
-        return;
-      if (!h && b) {
-        _changes[id2] = { base: b, head: h };
-        _didChange.deletion = true;
-        return;
-      }
-      if (h && !b) {
-        _changes[id2] = { base: b, head: h };
-        _didChange.addition = true;
-        return;
+  var TextRenderer = class {
+    // no need for block level renderers
+    strong(text2) {
+      return text2;
+    }
+    em(text2) {
+      return text2;
+    }
+    codespan(text2) {
+      return text2;
+    }
+    del(text2) {
+      return text2;
+    }
+    html(text2) {
+      return text2;
+    }
+    text(text2) {
+      return text2;
+    }
+    link(href, title, text2) {
+      return "" + text2;
+    }
+    image(href, title, text2) {
+      return "" + text2;
+    }
+    br() {
+      return "";
+    }
+  };
+  var Slugger = class {
+    constructor() {
+      this.seen = {};
+    }
+    /**
+     * @param {string} value
+     */
+    serialize(value) {
+      return value.toLowerCase().trim().replace(/<[!\/a-z].*?>/ig, "").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, "").replace(/\s/g, "-");
+    }
+    /**
+     * Finds the next safe (unique) slug to use
+     * @param {string} originalSlug
+     * @param {boolean} isDryRun
+     */
+    getNextSafeSlug(originalSlug, isDryRun) {
+      let slug = originalSlug;
+      let occurenceAccumulator = 0;
+      if (this.seen.hasOwnProperty(slug)) {
+        occurenceAccumulator = this.seen[originalSlug];
+        do {
+          occurenceAccumulator++;
+          slug = originalSlug + "-" + occurenceAccumulator;
+        } while (this.seen.hasOwnProperty(slug));
       }
-      if (h && b) {
-        if (h.members && b.members && !(0, import_fast_deep_equal3.default)(h.members, b.members)) {
-          _changes[id2] = { base: b, head: h };
-          _didChange.geometry = true;
-          _didChange.properties = true;
-          return;
-        }
-        if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
-          _changes[id2] = { base: b, head: h };
-          _didChange.geometry = true;
-        }
-        if (h.nodes && b.nodes && !(0, import_fast_deep_equal3.default)(h.nodes, b.nodes)) {
-          _changes[id2] = { base: b, head: h };
-          _didChange.geometry = true;
-        }
-        if (h.tags && b.tags && !(0, import_fast_deep_equal3.default)(h.tags, b.tags)) {
-          _changes[id2] = { base: b, head: h };
-          _didChange.properties = true;
-        }
+      if (!isDryRun) {
+        this.seen[originalSlug] = occurenceAccumulator;
+        this.seen[slug] = 0;
       }
+      return slug;
     }
-    function load() {
-      var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
-      for (var i2 = 0; i2 < ids.length; i2++) {
-        checkEntityID(ids[i2]);
-      }
+    /**
+     * Convert string to unique id
+     * @param {object} [options]
+     * @param {boolean} [options.dryrun] Generates the next unique slug without
+     * updating the internal accumulator.
+     */
+    slug(value, options2 = {}) {
+      const slug = this.serialize(value);
+      return this.getNextSafeSlug(slug, options2.dryrun);
     }
-    load();
-    _diff.length = function length() {
-      return Object.keys(_changes).length;
-    };
-    _diff.changes = function changes() {
-      return _changes;
-    };
-    _diff.didChange = _didChange;
-    _diff.extantIDs = function extantIDs(includeRelMembers) {
-      var result = /* @__PURE__ */ new Set();
-      Object.keys(_changes).forEach(function(id2) {
-        if (_changes[id2].head) {
-          result.add(id2);
+  };
+  var Parser = class _Parser {
+    constructor(options2) {
+      this.options = options2 || defaults;
+      this.options.renderer = this.options.renderer || new Renderer();
+      this.renderer = this.options.renderer;
+      this.renderer.options = this.options;
+      this.textRenderer = new TextRenderer();
+      this.slugger = new Slugger();
+    }
+    /**
+     * Static Parse Method
+     */
+    static parse(tokens, options2) {
+      const parser3 = new _Parser(options2);
+      return parser3.parse(tokens);
+    }
+    /**
+     * Static Parse Inline Method
+     */
+    static parseInline(tokens, options2) {
+      const parser3 = new _Parser(options2);
+      return parser3.parseInline(tokens);
+    }
+    /**
+     * Parse Loop
+     */
+    parse(tokens, top = true) {
+      let out = "", i2, j2, k, l2, l3, row, cell, header, body, token, ordered, start2, loose, itemBody, item, checked, task, checkbox, ret;
+      const l = tokens.length;
+      for (i2 = 0; i2 < l; i2++) {
+        token = tokens[i2];
+        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
+          ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
+          if (ret !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "paragraph", "text"].includes(token.type)) {
+            out += ret || "";
+            continue;
+          }
         }
-        var h = _changes[id2].head;
-        var b = _changes[id2].base;
-        var entity = h || b;
-        if (includeRelMembers && entity.type === "relation") {
-          var mh = h ? h.members.map(function(m) {
-            return m.id;
-          }) : [];
-          var mb = b ? b.members.map(function(m) {
-            return m.id;
-          }) : [];
-          utilArrayUnion(mh, mb).forEach(function(memberID) {
-            if (head.hasEntity(memberID)) {
-              result.add(memberID);
-            }
-          });
-        }
-      });
-      return Array.from(result);
-    };
-    _diff.modified = function modified() {
-      var result = [];
-      Object.values(_changes).forEach(function(change) {
-        if (change.base && change.head) {
-          result.push(change.head);
-        }
-      });
-      return result;
-    };
-    _diff.created = function created() {
-      var result = [];
-      Object.values(_changes).forEach(function(change) {
-        if (!change.base && change.head) {
-          result.push(change.head);
-        }
-      });
-      return result;
-    };
-    _diff.deleted = function deleted() {
-      var result = [];
-      Object.values(_changes).forEach(function(change) {
-        if (change.base && !change.head) {
-          result.push(change.base);
-        }
-      });
-      return result;
-    };
-    _diff.summary = function summary() {
-      var relevant = {};
-      var keys = Object.keys(_changes);
-      for (var i2 = 0; i2 < keys.length; i2++) {
-        var change = _changes[keys[i2]];
-        if (change.head && change.head.geometry(head) !== "vertex") {
-          addEntity(change.head, head, change.base ? "modified" : "created");
-        } else if (change.base && change.base.geometry(base) !== "vertex") {
-          addEntity(change.base, base, "deleted");
-        } else if (change.base && change.head) {
-          var moved = !(0, import_fast_deep_equal3.default)(change.base.loc, change.head.loc);
-          var retagged = !(0, import_fast_deep_equal3.default)(change.base.tags, change.head.tags);
-          if (moved) {
-            addParents(change.head);
+        switch (token.type) {
+          case "space": {
+            continue;
           }
-          if (retagged || moved && change.head.hasInterestingTags()) {
-            addEntity(change.head, head, "modified");
+          case "hr": {
+            out += this.renderer.hr();
+            continue;
           }
-        } else if (change.head && change.head.hasInterestingTags()) {
-          addEntity(change.head, head, "created");
-        } else if (change.base && change.base.hasInterestingTags()) {
-          addEntity(change.base, base, "deleted");
-        }
-      }
-      return Object.values(relevant);
-      function addEntity(entity, graph, changeType) {
-        relevant[entity.id] = {
-          entity,
-          graph,
-          changeType
-        };
-      }
-      function addParents(entity) {
-        var parents = head.parentWays(entity);
-        for (var j2 = parents.length - 1; j2 >= 0; j2--) {
-          var parent = parents[j2];
-          if (!(parent.id in relevant)) {
-            addEntity(parent, head, "modified");
+          case "heading": {
+            out += this.renderer.heading(
+              this.parseInline(token.tokens),
+              token.depth,
+              unescape3(this.parseInline(token.tokens, this.textRenderer)),
+              this.slugger
+            );
+            continue;
           }
-        }
-      }
-    };
-    _diff.complete = function complete(extent) {
-      var result = {};
-      var id2, change;
-      for (id2 in _changes) {
-        change = _changes[id2];
-        var h = change.head;
-        var b = change.base;
-        var entity = h || b;
-        var i2;
-        if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) {
-          continue;
-        }
-        result[id2] = h;
-        if (entity.type === "way") {
-          var nh = h ? h.nodes : [];
-          var nb = b ? b.nodes : [];
-          var diff;
-          diff = utilArrayDifference(nh, nb);
-          for (i2 = 0; i2 < diff.length; i2++) {
-            result[diff[i2]] = head.hasEntity(diff[i2]);
+          case "code": {
+            out += this.renderer.code(
+              token.text,
+              token.lang,
+              token.escaped
+            );
+            continue;
           }
-          diff = utilArrayDifference(nb, nh);
-          for (i2 = 0; i2 < diff.length; i2++) {
-            result[diff[i2]] = head.hasEntity(diff[i2]);
+          case "table": {
+            header = "";
+            cell = "";
+            l2 = token.header.length;
+            for (j2 = 0; j2 < l2; j2++) {
+              cell += this.renderer.tablecell(
+                this.parseInline(token.header[j2].tokens),
+                { header: true, align: token.align[j2] }
+              );
+            }
+            header += this.renderer.tablerow(cell);
+            body = "";
+            l2 = token.rows.length;
+            for (j2 = 0; j2 < l2; j2++) {
+              row = token.rows[j2];
+              cell = "";
+              l3 = row.length;
+              for (k = 0; k < l3; k++) {
+                cell += this.renderer.tablecell(
+                  this.parseInline(row[k].tokens),
+                  { header: false, align: token.align[k] }
+                );
+              }
+              body += this.renderer.tablerow(cell);
+            }
+            out += this.renderer.table(header, body);
+            continue;
           }
-        }
-        if (entity.type === "relation" && entity.isMultipolygon()) {
-          var mh = h ? h.members.map(function(m) {
-            return m.id;
-          }) : [];
-          var mb = b ? b.members.map(function(m) {
-            return m.id;
-          }) : [];
-          var ids = utilArrayUnion(mh, mb);
-          for (i2 = 0; i2 < ids.length; i2++) {
-            var member = head.hasEntity(ids[i2]);
-            if (!member)
-              continue;
-            if (extent && !member.intersects(extent, head))
-              continue;
-            result[ids[i2]] = member;
+          case "blockquote": {
+            body = this.parse(token.tokens);
+            out += this.renderer.blockquote(body);
+            continue;
+          }
+          case "list": {
+            ordered = token.ordered;
+            start2 = token.start;
+            loose = token.loose;
+            l2 = token.items.length;
+            body = "";
+            for (j2 = 0; j2 < l2; j2++) {
+              item = token.items[j2];
+              checked = item.checked;
+              task = item.task;
+              itemBody = "";
+              if (item.task) {
+                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);
+            continue;
+          }
+          case "html": {
+            out += this.renderer.html(token.text, token.block);
+            continue;
+          }
+          case "paragraph": {
+            out += this.renderer.paragraph(this.parseInline(token.tokens));
+            continue;
+          }
+          case "text": {
+            body = token.tokens ? this.parseInline(token.tokens) : token.text;
+            while (i2 + 1 < l && tokens[i2 + 1].type === "text") {
+              token = tokens[++i2];
+              body += "\n" + (token.tokens ? this.parseInline(token.tokens) : token.text);
+            }
+            out += top ? this.renderer.paragraph(body) : body;
+            continue;
+          }
+          default: {
+            const errMsg = 'Token with "' + token.type + '" type was not found.';
+            if (this.options.silent) {
+              console.error(errMsg);
+              return;
+            } else {
+              throw new Error(errMsg);
+            }
           }
         }
-        addParents(head.parentWays(entity), result);
-        addParents(head.parentRelations(entity), result);
       }
-      return result;
-      function addParents(parents, result2) {
-        for (var i3 = 0; i3 < parents.length; i3++) {
-          var parent = parents[i3];
-          if (parent.id in result2)
+      return out;
+    }
+    /**
+     * Parse Inline Tokens
+     */
+    parseInline(tokens, renderer) {
+      renderer = renderer || this.renderer;
+      let out = "", i2, token, ret;
+      const l = tokens.length;
+      for (i2 = 0; i2 < l; i2++) {
+        token = tokens[i2];
+        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
+          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)) {
+            out += ret || "";
             continue;
-          result2[parent.id] = parent;
-          addParents(head.parentRelations(parent), result2);
+          }
+        }
+        switch (token.type) {
+          case "escape": {
+            out += renderer.text(token.text);
+            break;
+          }
+          case "html": {
+            out += renderer.html(token.text);
+            break;
+          }
+          case "link": {
+            out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
+            break;
+          }
+          case "image": {
+            out += renderer.image(token.href, token.title, token.text);
+            break;
+          }
+          case "strong": {
+            out += renderer.strong(this.parseInline(token.tokens, renderer));
+            break;
+          }
+          case "em": {
+            out += renderer.em(this.parseInline(token.tokens, renderer));
+            break;
+          }
+          case "codespan": {
+            out += renderer.codespan(token.text);
+            break;
+          }
+          case "br": {
+            out += renderer.br();
+            break;
+          }
+          case "del": {
+            out += renderer.del(this.parseInline(token.tokens, renderer));
+            break;
+          }
+          case "text": {
+            out += renderer.text(token.text);
+            break;
+          }
+          default: {
+            const errMsg = 'Token with "' + token.type + '" type was not found.';
+            if (this.options.silent) {
+              console.error(errMsg);
+              return;
+            } else {
+              throw new Error(errMsg);
+            }
+          }
         }
       }
-    };
-    return _diff;
-  }
-
-  // modules/core/tree.js
-  var import_rbush6 = __toESM(require_rbush_min());
-  function coreTree(head) {
-    var _rtree = new import_rbush6.default();
-    var _bboxes = {};
-    var _segmentsRTree = new import_rbush6.default();
-    var _segmentsBBoxes = {};
-    var _segmentsByWayId = {};
-    var tree = {};
-    function entityBBox(entity) {
-      var bbox = entity.extent(head).bbox();
-      bbox.id = entity.id;
-      _bboxes[entity.id] = bbox;
-      return bbox;
+      return out;
     }
-    function segmentBBox(segment) {
-      var extent = segment.extent(head);
-      if (!extent)
-        return null;
-      var bbox = extent.bbox();
-      bbox.segment = segment;
-      _segmentsBBoxes[segment.id] = bbox;
-      return bbox;
+  };
+  var Hooks = class {
+    constructor(options2) {
+      this.options = options2 || defaults;
     }
-    function removeEntity(entity) {
-      _rtree.remove(_bboxes[entity.id]);
-      delete _bboxes[entity.id];
-      if (_segmentsByWayId[entity.id]) {
-        _segmentsByWayId[entity.id].forEach(function(segment) {
-          _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
-          delete _segmentsBBoxes[segment.id];
-        });
-        delete _segmentsByWayId[entity.id];
+    static passThroughHooks = /* @__PURE__ */ new Set([
+      "preprocess",
+      "postprocess"
+    ]);
+    /**
+     * Process markdown before marked
+     */
+    preprocess(markdown) {
+      return markdown;
+    }
+    /**
+     * Process HTML after marked is finished
+     */
+    postprocess(html2) {
+      return html2;
+    }
+  };
+  var Marked = class {
+    defaults = getDefaults();
+    options = this.setOptions;
+    parse = this.#parseMarkdown(Lexer.lex, Parser.parse);
+    parseInline = this.#parseMarkdown(Lexer.lexInline, Parser.parseInline);
+    Parser = Parser;
+    parser = Parser.parse;
+    Renderer = Renderer;
+    TextRenderer = TextRenderer;
+    Lexer = Lexer;
+    lexer = Lexer.lex;
+    Tokenizer = Tokenizer;
+    Slugger = Slugger;
+    Hooks = Hooks;
+    constructor(...args) {
+      this.use(...args);
+    }
+    walkTokens(tokens, callback) {
+      let values = [];
+      for (const token of tokens) {
+        values = values.concat(callback.call(this, token));
+        switch (token.type) {
+          case "table": {
+            for (const cell of token.header) {
+              values = values.concat(this.walkTokens(cell.tokens, callback));
+            }
+            for (const row of token.rows) {
+              for (const cell of row) {
+                values = values.concat(this.walkTokens(cell.tokens, callback));
+              }
+            }
+            break;
+          }
+          case "list": {
+            values = values.concat(this.walkTokens(token.items, callback));
+            break;
+          }
+          default: {
+            if (this.defaults.extensions && this.defaults.extensions.childTokens && this.defaults.extensions.childTokens[token.type]) {
+              this.defaults.extensions.childTokens[token.type].forEach((childTokens) => {
+                values = values.concat(this.walkTokens(token[childTokens], callback));
+              });
+            } else if (token.tokens) {
+              values = values.concat(this.walkTokens(token.tokens, callback));
+            }
+          }
+        }
       }
+      return values;
     }
-    function loadEntities(entities) {
-      _rtree.load(entities.map(entityBBox));
-      var segments = [];
-      entities.forEach(function(entity) {
-        if (entity.segments) {
-          var entitySegments = entity.segments(head);
-          _segmentsByWayId[entity.id] = entitySegments;
-          segments = segments.concat(entitySegments);
+    use(...args) {
+      const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };
+      args.forEach((pack) => {
+        const opts = { ...pack };
+        opts.async = this.defaults.async || opts.async || false;
+        if (pack.extensions) {
+          pack.extensions.forEach((ext) => {
+            if (!ext.name) {
+              throw new Error("extension name required");
+            }
+            if (ext.renderer) {
+              const prevRenderer = extensions.renderers[ext.name];
+              if (prevRenderer) {
+                extensions.renderers[ext.name] = function(...args2) {
+                  let ret = ext.renderer.apply(this, args2);
+                  if (ret === false) {
+                    ret = prevRenderer.apply(this, args2);
+                  }
+                  return ret;
+                };
+              } else {
+                extensions.renderers[ext.name] = ext.renderer;
+              }
+            }
+            if (ext.tokenizer) {
+              if (!ext.level || ext.level !== "block" && ext.level !== "inline") {
+                throw new Error("extension level must be 'block' or 'inline'");
+              }
+              if (extensions[ext.level]) {
+                extensions[ext.level].unshift(ext.tokenizer);
+              } else {
+                extensions[ext.level] = [ext.tokenizer];
+              }
+              if (ext.start) {
+                if (ext.level === "block") {
+                  if (extensions.startBlock) {
+                    extensions.startBlock.push(ext.start);
+                  } else {
+                    extensions.startBlock = [ext.start];
+                  }
+                } else if (ext.level === "inline") {
+                  if (extensions.startInline) {
+                    extensions.startInline.push(ext.start);
+                  } else {
+                    extensions.startInline = [ext.start];
+                  }
+                }
+              }
+            }
+            if (ext.childTokens) {
+              extensions.childTokens[ext.name] = ext.childTokens;
+            }
+          });
+          opts.extensions = extensions;
+        }
+        if (pack.renderer) {
+          const renderer = this.defaults.renderer || new Renderer(this.defaults);
+          for (const prop in pack.renderer) {
+            const prevRenderer = renderer[prop];
+            renderer[prop] = (...args2) => {
+              let ret = pack.renderer[prop].apply(renderer, args2);
+              if (ret === false) {
+                ret = prevRenderer.apply(renderer, args2);
+              }
+              return ret;
+            };
+          }
+          opts.renderer = renderer;
+        }
+        if (pack.tokenizer) {
+          const tokenizer = this.defaults.tokenizer || new Tokenizer(this.defaults);
+          for (const prop in pack.tokenizer) {
+            const prevTokenizer = tokenizer[prop];
+            tokenizer[prop] = (...args2) => {
+              let ret = pack.tokenizer[prop].apply(tokenizer, args2);
+              if (ret === false) {
+                ret = prevTokenizer.apply(tokenizer, args2);
+              }
+              return ret;
+            };
+          }
+          opts.tokenizer = tokenizer;
+        }
+        if (pack.hooks) {
+          const hooks = this.defaults.hooks || new Hooks();
+          for (const prop in pack.hooks) {
+            const prevHook = hooks[prop];
+            if (Hooks.passThroughHooks.has(prop)) {
+              hooks[prop] = (arg) => {
+                if (this.defaults.async) {
+                  return Promise.resolve(pack.hooks[prop].call(hooks, arg)).then((ret2) => {
+                    return prevHook.call(hooks, ret2);
+                  });
+                }
+                const ret = pack.hooks[prop].call(hooks, arg);
+                return prevHook.call(hooks, ret);
+              };
+            } else {
+              hooks[prop] = (...args2) => {
+                let ret = pack.hooks[prop].apply(hooks, args2);
+                if (ret === false) {
+                  ret = prevHook.apply(hooks, args2);
+                }
+                return ret;
+              };
+            }
+          }
+          opts.hooks = hooks;
+        }
+        if (pack.walkTokens) {
+          const walkTokens2 = this.defaults.walkTokens;
+          opts.walkTokens = function(token) {
+            let values = [];
+            values.push(pack.walkTokens.call(this, token));
+            if (walkTokens2) {
+              values = values.concat(walkTokens2.call(this, token));
+            }
+            return values;
+          };
         }
+        this.defaults = { ...this.defaults, ...opts };
       });
-      if (segments.length)
-        _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
+      return this;
     }
-    function updateParents(entity, insertions, memo) {
-      head.parentWays(entity).forEach(function(way) {
-        if (_bboxes[way.id]) {
-          removeEntity(way);
-          insertions[way.id] = way;
+    setOptions(opt) {
+      this.defaults = { ...this.defaults, ...opt };
+      return this;
+    }
+    #parseMarkdown(lexer2, parser3) {
+      return (src, opt, callback) => {
+        if (typeof opt === "function") {
+          callback = opt;
+          opt = null;
         }
-        updateParents(way, insertions, memo);
-      });
-      head.parentRelations(entity).forEach(function(relation) {
-        if (memo[entity.id])
+        const origOpt = { ...opt };
+        opt = { ...this.defaults, ...origOpt };
+        const throwError = this.#onError(opt.silent, opt.async, callback);
+        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"));
+        }
+        checkDeprecations(opt, callback);
+        if (opt.hooks) {
+          opt.hooks.options = opt;
+        }
+        if (callback) {
+          const highlight = opt.highlight;
+          let tokens;
+          try {
+            if (opt.hooks) {
+              src = opt.hooks.preprocess(src);
+            }
+            tokens = lexer2(src, opt);
+          } catch (e) {
+            return throwError(e);
+          }
+          const done = (err) => {
+            let out;
+            if (!err) {
+              try {
+                if (opt.walkTokens) {
+                  this.walkTokens(tokens, opt.walkTokens);
+                }
+                out = parser3(tokens, opt);
+                if (opt.hooks) {
+                  out = opt.hooks.postprocess(out);
+                }
+              } catch (e) {
+                err = e;
+              }
+            }
+            opt.highlight = highlight;
+            return err ? throwError(err) : callback(null, out);
+          };
+          if (!highlight || highlight.length < 3) {
+            return done();
+          }
+          delete opt.highlight;
+          if (!tokens.length)
+            return done();
+          let pending = 0;
+          this.walkTokens(tokens, (token) => {
+            if (token.type === "code") {
+              pending++;
+              setTimeout(() => {
+                highlight(token.text, token.lang, (err, code) => {
+                  if (err) {
+                    return done(err);
+                  }
+                  if (code != null && code !== token.text) {
+                    token.text = code;
+                    token.escaped = true;
+                  }
+                  pending--;
+                  if (pending === 0) {
+                    done();
+                  }
+                });
+              }, 0);
+            }
+          });
+          if (pending === 0) {
+            done();
+          }
           return;
-        memo[entity.id] = true;
-        if (_bboxes[relation.id]) {
-          removeEntity(relation);
-          insertions[relation.id] = relation;
         }
-        updateParents(relation, insertions, memo);
-      });
+        if (opt.async) {
+          return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src).then((src2) => lexer2(src2, opt)).then((tokens) => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens).then((tokens) => parser3(tokens, opt)).then((html2) => opt.hooks ? opt.hooks.postprocess(html2) : html2).catch(throwError);
+        }
+        try {
+          if (opt.hooks) {
+            src = opt.hooks.preprocess(src);
+          }
+          const tokens = lexer2(src, opt);
+          if (opt.walkTokens) {
+            this.walkTokens(tokens, opt.walkTokens);
+          }
+          let html2 = parser3(tokens, opt);
+          if (opt.hooks) {
+            html2 = opt.hooks.postprocess(html2);
+          }
+          return html2;
+        } catch (e) {
+          return throwError(e);
+        }
+      };
     }
-    tree.rebase = function(entities, force) {
-      var insertions = {};
-      for (var i2 = 0; i2 < entities.length; i2++) {
-        var entity = entities[i2];
-        if (!entity.visible)
-          continue;
-        if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
-          if (!force) {
-            continue;
-          } else if (_bboxes[entity.id]) {
-            removeEntity(entity);
+    #onError(silent, async, callback) {
+      return (e) => {
+        e.message += "\nPlease report this to https://github.com/markedjs/marked.";
+        if (silent) {
+          const msg = "<p>An error occurred:</p><pre>" + escape4(e.message + "", true) + "</pre>";
+          if (async) {
+            return Promise.resolve(msg);
+          }
+          if (callback) {
+            callback(null, msg);
+            return;
           }
+          return msg;
         }
-        insertions[entity.id] = entity;
-        updateParents(entity, insertions, {});
-      }
-      loadEntities(Object.values(insertions));
-      return tree;
-    };
-    function updateToGraph(graph) {
-      if (graph === head)
-        return;
-      var diff = coreDifference(head, graph);
-      head = graph;
-      var changed = diff.didChange;
-      if (!changed.addition && !changed.deletion && !changed.geometry)
-        return;
-      var insertions = {};
-      if (changed.deletion) {
-        diff.deleted().forEach(function(entity) {
-          removeEntity(entity);
-        });
-      }
-      if (changed.geometry) {
-        diff.modified().forEach(function(entity) {
-          removeEntity(entity);
-          insertions[entity.id] = entity;
-          updateParents(entity, insertions, {});
-        });
-      }
-      if (changed.addition) {
-        diff.created().forEach(function(entity) {
-          insertions[entity.id] = entity;
-        });
-      }
-      loadEntities(Object.values(insertions));
+        if (async) {
+          return Promise.reject(e);
+        }
+        if (callback) {
+          callback(e);
+          return;
+        }
+        throw e;
+      };
     }
-    tree.intersects = function(extent, graph) {
-      updateToGraph(graph);
-      return _rtree.search(extent.bbox()).map(function(bbox) {
-        return graph.entity(bbox.id);
-      });
-    };
-    tree.waySegments = function(extent, graph) {
-      updateToGraph(graph);
-      return _segmentsRTree.search(extent.bbox()).map(function(bbox) {
-        return bbox.segment;
-      });
-    };
-    return tree;
-  }
-
-  // modules/svg/icon.js
-  function svgIcon(name, svgklass, useklass) {
-    return function drawIcon(selection2) {
-      selection2.selectAll("svg.icon" + (svgklass ? "." + svgklass.split(" ")[0] : "")).data([0]).enter().append("svg").attr("class", "icon " + (svgklass || "")).append("use").attr("xlink:href", name).attr("class", useklass);
-    };
+  };
+  var markedInstance = new Marked(defaults);
+  function marked(src, opt, callback) {
+    return markedInstance.parse(src, opt, callback);
   }
-
-  // modules/ui/modal.js
-  function uiModal(selection2, blocking) {
-    let keybinding = utilKeybinding("modal");
-    let previous = selection2.select("div.modal");
-    let animate = previous.empty();
-    previous.transition().duration(200).style("opacity", 0).remove();
-    let shaded = selection2.append("div").attr("class", "shaded").style("opacity", 0);
-    shaded.close = () => {
-      shaded.transition().duration(200).style("opacity", 0).remove();
-      modal.transition().duration(200).style("top", "0px");
-      select_default2(document).call(keybinding.unbind);
-    };
-    let modal = shaded.append("div").attr("class", "modal fillL");
-    modal.append("input").attr("class", "keytrap keytrap-first").on("focus.keytrap", moveFocusToLast);
-    if (!blocking) {
-      shaded.on("click.remove-modal", (d3_event) => {
-        if (d3_event.target === this) {
-          shaded.close();
-        }
-      });
-      modal.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", shaded.close).call(svgIcon("#iD-icon-close"));
-      keybinding.on("\u232B", shaded.close).on("\u238B", shaded.close);
-      select_default2(document).call(keybinding);
-    }
-    modal.append("div").attr("class", "content");
-    modal.append("input").attr("class", "keytrap keytrap-last").on("focus.keytrap", moveFocusToFirst);
-    if (animate) {
-      shaded.transition().style("opacity", 1);
-    } else {
-      shaded.style("opacity", 1);
-    }
-    return shaded;
-    function moveFocusToFirst() {
-      let node = modal.select("a, button, input:not(.keytrap), select, textarea").node();
-      if (node) {
-        node.focus();
-      } else {
-        select_default2(this).node().blur();
-      }
+  marked.options = marked.setOptions = function(opt) {
+    markedInstance.setOptions(opt);
+    marked.defaults = markedInstance.defaults;
+    changeDefaults(marked.defaults);
+    return marked;
+  };
+  marked.getDefaults = getDefaults;
+  marked.defaults = defaults;
+  marked.use = function(...args) {
+    markedInstance.use(...args);
+    marked.defaults = markedInstance.defaults;
+    changeDefaults(marked.defaults);
+    return marked;
+  };
+  marked.walkTokens = function(tokens, callback) {
+    return markedInstance.walkTokens(tokens, callback);
+  };
+  marked.parseInline = markedInstance.parseInline;
+  marked.Parser = Parser;
+  marked.parser = Parser.parse;
+  marked.Renderer = Renderer;
+  marked.TextRenderer = TextRenderer;
+  marked.Lexer = Lexer;
+  marked.lexer = Lexer.lex;
+  marked.Tokenizer = Tokenizer;
+  marked.Slugger = Slugger;
+  marked.Hooks = Hooks;
+  marked.parse = marked;
+  var options = marked.options;
+  var setOptions = marked.setOptions;
+  var use = marked.use;
+  var walkTokens = marked.walkTokens;
+  var parseInline = marked.parseInline;
+  var parser2 = Parser.parse;
+  var lexer = Lexer.lex;
+
+  // modules/services/osmose.js
+  var tiler3 = utilTiler();
+  var dispatch4 = dispatch_default("loaded");
+  var _tileZoom3 = 14;
+  var _osmoseUrlRoot = "https://osmose.openstreetmap.fr/api/0.3";
+  var _osmoseData = { icons: {}, items: [] };
+  var _cache3;
+  function abortRequest3(controller) {
+    if (controller) {
+      controller.abort();
     }
-    function moveFocusToLast() {
-      let nodes = modal.selectAll("a, button, input:not(.keytrap), select, textarea").nodes();
-      if (nodes.length) {
-        nodes[nodes.length - 1].focus();
-      } else {
-        select_default2(this).node().blur();
+  }
+  function abortUnwantedRequests3(cache, tiles) {
+    Object.keys(cache.inflightTile).forEach((k) => {
+      let wanted = tiles.find((tile) => k === tile.id);
+      if (!wanted) {
+        abortRequest3(cache.inflightTile[k]);
+        delete cache.inflightTile[k];
       }
+    });
+  }
+  function encodeIssueRtree3(d) {
+    return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
+  }
+  function updateRtree3(item, replace) {
+    _cache3.rtree.remove(item, (a, b) => a.data.id === b.data.id);
+    if (replace) {
+      _cache3.rtree.insert(item);
     }
   }
-
-  // modules/ui/loading.js
-  function uiLoading(context) {
-    let _modalSelection = select_default2(null);
-    let _message = "";
-    let _blocking = false;
-    let loading = (selection2) => {
-      _modalSelection = uiModal(selection2, _blocking);
-      let loadertext = _modalSelection.select(".content").classed("loading-modal", true).append("div").attr("class", "modal-section fillL");
-      loadertext.append("img").attr("class", "loader").attr("src", context.imagePath("loader-white.gif"));
-      loadertext.append("h3").html(_message);
-      _modalSelection.select("button.close").attr("class", "hide");
-      return loading;
-    };
-    loading.message = function(val) {
-      if (!arguments.length)
-        return _message;
-      _message = val;
-      return loading;
-    };
-    loading.blocking = function(val) {
-      if (!arguments.length)
-        return _blocking;
-      _blocking = val;
-      return loading;
-    };
-    loading.close = () => {
-      _modalSelection.remove();
-    };
-    loading.isShown = () => {
-      return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
-    };
-    return loading;
+  function preventCoincident2(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;
+    } while (coincident);
+    return loc;
   }
-
-  // modules/core/history.js
-  function coreHistory(context) {
-    var dispatch10 = dispatch_default("reset", "change", "merge", "restore", "undone", "redone", "storage_error");
-    var lock = utilSessionMutex("lock");
-    var _hasUnresolvedRestorableChanges = lock.lock() && !!corePreferences(getKey("saved_history"));
-    var duration = 150;
-    var _imageryUsed = [];
-    var _photoOverlaysUsed = [];
-    var _checkpoints = {};
-    var _pausedGraph;
-    var _stack;
-    var _index;
-    var _tree;
-    function _act(actions, t) {
-      actions = Array.prototype.slice.call(actions);
-      var annotation;
-      if (typeof actions[actions.length - 1] !== "function") {
-        annotation = actions.pop();
+  var osmose_default = {
+    title: "osmose",
+    init() {
+      _mainFileFetcher.get("qa_data").then((d) => {
+        _osmoseData = d.osmose;
+        _osmoseData.items = Object.keys(d.osmose.icons).map((s) => s.split("-")[0]).reduce((unique, item) => unique.indexOf(item) !== -1 ? unique : [...unique, item], []);
+      });
+      if (!_cache3) {
+        this.reset();
       }
-      var graph = _stack[_index].graph;
-      for (var i2 = 0; i2 < actions.length; i2++) {
-        graph = actions[i2](graph, t);
+      this.event = utilRebind(this, dispatch4, "on");
+    },
+    reset() {
+      let _strings = {};
+      let _colors = {};
+      if (_cache3) {
+        Object.values(_cache3.inflightTile).forEach(abortRequest3);
+        _strings = _cache3.strings;
+        _colors = _cache3.colors;
       }
-      return {
-        graph,
-        annotation,
-        imageryUsed: _imageryUsed,
-        photoOverlaysUsed: _photoOverlaysUsed,
-        transform: context.projection.transform(),
-        selectedIDs: context.selectedIDs()
+      _cache3 = {
+        data: {},
+        loadedTile: {},
+        inflightTile: {},
+        inflightPost: {},
+        closed: {},
+        rtree: new import_rbush3.default(),
+        strings: _strings,
+        colors: _colors
       };
-    }
-    function _perform(args, t) {
-      var previous = _stack[_index].graph;
-      _stack = _stack.slice(0, _index + 1);
-      var actionResult = _act(args, t);
-      _stack.push(actionResult);
-      _index++;
-      return change(previous);
-    }
-    function _replace(args, t) {
-      var previous = _stack[_index].graph;
-      var actionResult = _act(args, t);
-      _stack[_index] = actionResult;
-      return change(previous);
-    }
-    function _overwrite(args, t) {
-      var previous = _stack[_index].graph;
-      if (_index > 0) {
-        _index--;
-        _stack.pop();
+    },
+    loadIssues(projection2) {
+      let params = {
+        // Tiles return a maximum # of issues
+        // 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);
+      tiles.forEach((tile) => {
+        if (_cache3.loadedTile[tile.id] || _cache3.inflightTile[tile.id])
+          return;
+        let [x, y, z] = tile.xyz;
+        let url = `${_osmoseUrlRoot}/issues/${z}/${x}/${y}.geojson?` + utilQsString(params);
+        let controller = new AbortController();
+        _cache3.inflightTile[tile.id] = controller;
+        json_default(url, { signal: controller.signal }).then((data) => {
+          delete _cache3.inflightTile[tile.id];
+          _cache3.loadedTile[tile.id] = true;
+          if (data.features) {
+            data.features.forEach((issue) => {
+              const { item, class: cl, uuid: id2 } = issue.properties;
+              const itemType = `${item}-${cl}`;
+              if (itemType in _osmoseData.icons) {
+                let loc = issue.geometry.coordinates;
+                loc = preventCoincident2(loc);
+                let d = new QAItem(loc, this, itemType, id2, { item });
+                if (item === 8300 || item === 8360) {
+                  d.elems = [];
+                }
+                _cache3.data[d.id] = d;
+                _cache3.rtree.insert(encodeIssueRtree3(d));
+              }
+            });
+          }
+          dispatch4.call("loaded");
+        }).catch(() => {
+          delete _cache3.inflightTile[tile.id];
+          _cache3.loadedTile[tile.id] = true;
+        });
+      });
+    },
+    loadIssueDetail(issue) {
+      if (issue.elems !== void 0) {
+        return Promise.resolve(issue);
       }
-      _stack = _stack.slice(0, _index + 1);
-      var actionResult = _act(args, t);
-      _stack.push(actionResult);
-      _index++;
-      return change(previous);
+      const url = `${_osmoseUrlRoot}/issue/${issue.id}?langs=${_mainLocalizer.localeCode()}`;
+      const cacheDetails = (data) => {
+        issue.elems = data.elems.map((e) => e.type.substring(0, 1) + e.id);
+        issue.detail = data.subtitle ? marked(data.subtitle.auto) : "";
+        this.replaceItem(issue);
+      };
+      return json_default(url).then(cacheDetails).then(() => issue);
+    },
+    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 _cache3.strings)) {
+        _cache3.strings[locale2] = {};
+      }
+      const allRequests = items.map((itemType) => {
+        if (itemType in _cache3.strings[locale2])
+          return null;
+        const cacheData = (data) => {
+          const [cat = { items: [] }] = data.categories;
+          const [item2 = { class: [] }] = cat.items;
+          const [cl2 = null] = item2.class;
+          if (!cl2) {
+            console.log(`Osmose strings request (${itemType}) had unexpected data`);
+            return;
+          }
+          const { item: itemInt, color: color2 } = item2;
+          if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color2)) {
+            _cache3.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;
+        };
+        const [item, cl] = itemType.split("-");
+        const url = `${_osmoseUrlRoot}/items/${item}/class/${cl}?langs=${locale2}`;
+        return json_default(url).then(cacheData);
+      }).filter(Boolean);
+      return Promise.all(allRequests).then(() => _cache3.strings[locale2]);
+    },
+    getStrings(itemType, locale2 = _mainLocalizer.localeCode()) {
+      return locale2 in _cache3.strings ? _cache3.strings[locale2][itemType] : {};
+    },
+    getColor(itemType) {
+      return itemType in _cache3.colors ? _cache3.colors[itemType] : "#FFFFFF";
+    },
+    postUpdate(issue, callback) {
+      if (_cache3.inflightPost[issue.id]) {
+        return callback({ message: "Issue update already inflight", status: -2 }, issue);
+      }
+      const url = `${_osmoseUrlRoot}/issue/${issue.id}/${issue.newStatus}`;
+      const controller = new AbortController();
+      const after = () => {
+        delete _cache3.inflightPost[issue.id];
+        this.removeItem(issue);
+        if (issue.newStatus === "done") {
+          if (!(issue.item in _cache3.closed)) {
+            _cache3.closed[issue.item] = 0;
+          }
+          _cache3.closed[issue.item] += 1;
+        }
+        if (callback)
+          callback(null, issue);
+      };
+      _cache3.inflightPost[issue.id] = controller;
+      fetch(url, { signal: controller.signal }).then(after).catch((err) => {
+        delete _cache3.inflightPost[issue.id];
+        if (callback)
+          callback(err.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 _cache3.rtree.search(bbox2).map((d) => d.data);
+    },
+    // Get a QAItem from cache
+    // NOTE: Don't change method name until UI v3 is merged
+    getError(id2) {
+      return _cache3.data[id2];
+    },
+    // get the name of the icon to display for this item
+    getIcon(itemType) {
+      return _osmoseData.icons[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);
+      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);
+    },
+    // Used to populate `closed:osmose:*` changeset tags
+    getClosedCounts() {
+      return _cache3.closed;
+    },
+    itemURL(item) {
+      return `https://osmose.openstreetmap.fr/en/error/${item.id}`;
     }
-    function change(previous) {
-      var difference = coreDifference(previous, history.graph());
-      if (!_pausedGraph) {
-        dispatch10.call("change", this, difference);
+  };
+
+  // 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 mapFeatureTileUrl = `${baseTileUrl}/mly_map_feature_point/2/{z}/{x}/{y}?access_token=${accessToken}`;
+  var tileUrl = `${baseTileUrl}/mly1_public/2/{z}/{x}/{y}?access_token=${accessToken}`;
+  var trafficSignTileUrl = `${baseTileUrl}/mly_map_feature_traffic_sign/2/{z}/{x}/{y}?access_token=${accessToken}`;
+  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 _loadViewerPromise;
+  var _mlyActiveImage;
+  var _mlyCache;
+  var _mlyFallback = false;
+  var _mlyHighlightedDetection;
+  var _mlyShowFeatureDetections = false;
+  var _mlyShowSignDetections = false;
+  var _mlyViewer;
+  var _mlyViewerFilter = ["all"];
+  function loadTiles(which, url, maxZoom2, 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 = `${tile.id}-${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) {
+        throw new Error("No Data");
+      }
+      loadTileDataToCache(data, tile, which);
+      if (which === "images") {
+        dispatch5.call("loadedImages");
+      } else if (which === "signs") {
+        dispatch5.call("loadedSigns");
+      } else if (which === "points") {
+        dispatch5.call("loadedMapFeatures");
+      }
+    }).catch(function() {
+      cache.loaded[tileId] = true;
+      delete cache.inflight[tileId];
+    });
+  }
+  function loadTileDataToCache(data, tile, which) {
+    const vectorTile = new import_vector_tile.VectorTile(new import_pbf.default(data));
+    let features, cache, layer, i2, feature3, loc, d;
+    if (vectorTile.layers.hasOwnProperty("image")) {
+      features = [];
+      cache = _mlyCache.images;
+      layer = vectorTile.layers.image;
+      for (i2 = 0; i2 < layer.length; i2++) {
+        feature3 = layer.feature(i2).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        d = {
+          loc,
+          captured_at: feature3.properties.captured_at,
+          ca: feature3.properties.compass_angle,
+          id: feature3.properties.id,
+          is_pano: feature3.properties.is_pano,
+          sequence_id: feature3.properties.sequence_id
+        };
+        cache.forImageId[d.id] = d;
+        features.push({
+          minX: loc[0],
+          minY: loc[1],
+          maxX: loc[0],
+          maxY: loc[1],
+          data: d
+        });
+      }
+      if (cache.rtree) {
+        cache.rtree.load(features);
       }
-      return difference;
     }
-    function getKey(n2) {
-      return "iD_" + window.location.origin + "_" + n2;
+    if (vectorTile.layers.hasOwnProperty("sequence")) {
+      features = [];
+      cache = _mlyCache.sequences;
+      layer = vectorTile.layers.sequence;
+      for (i2 = 0; i2 < layer.length; i2++) {
+        feature3 = layer.feature(i2).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];
+        }
+      }
     }
-    var history = {
-      graph: function() {
-        return _stack[_index].graph;
-      },
-      tree: function() {
-        return _tree;
-      },
-      base: function() {
-        return _stack[0].graph;
-      },
-      merge: function(entities) {
-        var stack = _stack.map(function(state) {
-          return state.graph;
+    if (vectorTile.layers.hasOwnProperty("point")) {
+      features = [];
+      cache = _mlyCache[which];
+      layer = vectorTile.layers.point;
+      for (i2 = 0; i2 < layer.length; i2++) {
+        feature3 = layer.feature(i2).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        d = {
+          loc,
+          id: feature3.properties.id,
+          first_seen_at: feature3.properties.first_seen_at,
+          last_seen_at: feature3.properties.last_seen_at,
+          value: feature3.properties.value
+        };
+        features.push({
+          minX: loc[0],
+          minY: loc[1],
+          maxX: loc[0],
+          maxY: loc[1],
+          data: d
         });
-        _stack[0].graph.rebase(entities, stack, false);
-        _tree.rebase(entities, false);
-        dispatch10.call("merge", this, entities);
+      }
+      if (cache.rtree) {
+        cache.rtree.load(features);
+      }
+    }
+    if (vectorTile.layers.hasOwnProperty("traffic_sign")) {
+      features = [];
+      cache = _mlyCache[which];
+      layer = vectorTile.layers.traffic_sign;
+      for (i2 = 0; i2 < layer.length; i2++) {
+        feature3 = layer.feature(i2).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        d = {
+          loc,
+          id: feature3.properties.id,
+          first_seen_at: feature3.properties.first_seen_at,
+          last_seen_at: feature3.properties.last_seen_at,
+          value: feature3.properties.value
+        };
+        features.push({
+          minX: loc[0],
+          minY: loc[1],
+          maxX: loc[0],
+          maxY: loc[1],
+          data: d
+        });
+      }
+      if (cache.rtree) {
+        cache.rtree.load(features);
+      }
+    }
+  }
+  function loadData(url) {
+    return fetch(url).then(function(response) {
+      if (!response.ok) {
+        throw new Error(response.status + " " + response.statusText);
+      }
+      return response.json();
+    }).then(function(result) {
+      if (!result) {
+        return [];
+      }
+      return result.data || [];
+    });
+  }
+  function partitionViewport(projection2) {
+    const z = geoScaleToZoom(projection2.scale());
+    const z2 = Math.ceil(z * 2) / 2 + 2.5;
+    const tiler8 = utilTiler().zoomExtent([z2, z2]);
+    return tiler8.getTiles(projection2).map(function(tile) {
+      return tile.extent;
+    });
+  }
+  function searchLimited(limit, projection2, rtree) {
+    limit = limit || 5;
+    return partitionViewport(projection2).reduce(function(result, extent) {
+      const found = rtree.search(extent.bbox()).slice(0, limit).map(function(d) {
+        return d.data;
+      });
+      return found.length ? result.concat(found) : result;
+    }, []);
+  }
+  var mapillary_default = {
+    // Initialize Mapillary
+    init: function() {
+      if (!_mlyCache) {
+        this.reset();
+      }
+      this.event = utilRebind(this, dispatch5, "on");
+    },
+    // Reset cache and state
+    reset: function() {
+      if (_mlyCache) {
+        Object.values(_mlyCache.requests.inflight).forEach(function(request3) {
+          request3.abort();
+        });
+      }
+      _mlyCache = {
+        images: { rtree: new import_rbush4.default(), forImageId: {} },
+        image_detections: { forImageId: {} },
+        signs: { rtree: new import_rbush4.default() },
+        points: { rtree: new import_rbush4.default() },
+        sequences: { rtree: new import_rbush4.default(), lineString: {} },
+        requests: { loaded: {}, inflight: {} }
+      };
+      _mlyActiveImage = null;
+    },
+    // Get visible images
+    images: function(projection2) {
+      const limit = 5;
+      return searchLimited(limit, projection2, _mlyCache.images.rtree);
+    },
+    // Get visible traffic signs
+    signs: function(projection2) {
+      const limit = 5;
+      return searchLimited(limit, projection2, _mlyCache.signs.rtree);
+    },
+    // Get visible map (point) features
+    mapFeatures: function(projection2) {
+      const limit = 5;
+      return searchLimited(limit, projection2, _mlyCache.points.rtree);
+    },
+    // Get cached image by id
+    cachedImage: function(imageId) {
+      return _mlyCache.images.forImageId[imageId];
+    },
+    // Get visible sequences
+    sequences: function(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();
+      const sequenceIds = {};
+      let lineStrings = [];
+      _mlyCache.images.rtree.search(bbox2).forEach(function(d) {
+        if (d.data.sequence_id) {
+          sequenceIds[d.data.sequence_id] = true;
+        }
+      });
+      Object.keys(sequenceIds).forEach(function(sequenceId) {
+        if (_mlyCache.sequences.lineString[sequenceId]) {
+          lineStrings = lineStrings.concat(_mlyCache.sequences.lineString[sequenceId]);
+        }
+      });
+      return lineStrings;
+    },
+    // Load images in the visible area
+    loadImages: function(projection2) {
+      loadTiles("images", tileUrl, 14, projection2);
+    },
+    // Load traffic signs in the visible area
+    loadSigns: function(projection2) {
+      loadTiles("signs", trafficSignTileUrl, 14, projection2);
+    },
+    // Load map (point) features in the visible area
+    loadMapFeatures: function(projection2) {
+      loadTiles("points", mapFeatureTileUrl, 14, projection2);
+    },
+    // Return a promise that resolves when the image viewer (Mapillary JS) library has finished loading
+    ensureViewerLoaded: function(context) {
+      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;
+      _loadViewerPromise = new Promise((resolve, reject) => {
+        let loadedCount = 0;
+        function loaded() {
+          loadedCount += 1;
+          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() {
+          reject();
+        });
+        head.selectAll("#ideditor-mapillary-viewerjs").data([0]).enter().append("script").attr("id", "ideditor-mapillary-viewerjs").attr("crossorigin", "anonymous").attr("src", context.asset(viewerjs)).on("load.serviceMapillary", loaded).on("error.serviceMapillary", function() {
+          reject();
+        });
+      }).catch(function() {
+        _loadViewerPromise = null;
+      }).then(function() {
+        that.initViewer(context);
+      });
+      return _loadViewerPromise;
+    },
+    // Load traffic sign image sprites
+    loadSignResources: function(context) {
+      context.ui().svgDefs.addSprites(
+        ["mapillary-sprite"],
+        false
+        /* don't override colors */
+      );
+      return this;
+    },
+    // Load map (point) feature image sprites
+    loadObjectResources: function(context) {
+      context.ui().svgDefs.addSprites(
+        ["mapillary-object-sprite"],
+        false
+        /* don't override colors */
+      );
+      return this;
+    },
+    // Remove previous detections in image viewer
+    resetTags: function() {
+      if (_mlyViewer && !_mlyFallback) {
+        _mlyViewer.getComponent("tag").removeAll();
+      }
+    },
+    // Show map feature detections in image viewer
+    showFeatureDetections: function(value) {
+      _mlyShowFeatureDetections = value;
+      if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
+        this.resetTags();
+      }
+    },
+    // Show traffic sign detections in image viewer
+    showSignDetections: function(value) {
+      _mlyShowSignDetections = value;
+      if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
+        this.resetTags();
+      }
+    },
+    // Apply filter to image viewer
+    filterViewer: function(context) {
+      const showsPano = context.photos().showsPanoramic();
+      const showsFlat = context.photos().showsFlat();
+      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 (fromDate) {
+        filter2.push([">=", "capturedAt", new Date(fromDate).getTime()]);
+      }
+      if (toDate) {
+        filter2.push([">=", "capturedAt", new Date(toDate).getTime()]);
+      }
+      if (_mlyViewer) {
+        _mlyViewer.setFilter(filter2);
+      }
+      _mlyViewerFilter = filter2;
+      return filter2;
+    },
+    // Make the image viewer visible
+    showViewer: function(context) {
+      const wrap2 = context.container().select(".photoviewer").classed("hide", false);
+      const isHidden = wrap2.selectAll(".photo-wrapper.mly-wrapper.hide").size();
+      if (isHidden && _mlyViewer) {
+        wrap2.selectAll(".photo-wrapper:not(.mly-wrapper)").classed("hide", true);
+        wrap2.selectAll(".photo-wrapper.mly-wrapper").classed("hide", false);
+        _mlyViewer.resize();
+      }
+      return this;
+    },
+    // Hide the image viewer and resets map markers
+    hideViewer: function(context) {
+      _mlyActiveImage = null;
+      if (!_mlyFallback && _mlyViewer) {
+        _mlyViewer.getComponent("sequence").stop();
+      }
+      const viewer = context.container().select(".photoviewer");
+      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");
+      return this.setStyles(context, null);
+    },
+    // Update the URL with current image id
+    updateUrlImage: function(imageId) {
+      if (!window.mocha) {
+        const hash = utilStringQs(window.location.hash);
+        if (imageId) {
+          hash.photo = "mapillary/" + imageId;
+        } else {
+          delete hash.photo;
+        }
+        window.location.replace("#" + utilQsString(hash, true));
+      }
+    },
+    // Highlight the detection in the viewer that is related to the clicked map feature
+    highlightDetection: function(detection) {
+      if (detection) {
+        _mlyHighlightedDetection = detection.id;
+      }
+      return this;
+    },
+    // Initialize image viewer (Mapillar JS)
+    initViewer: function(context) {
+      const that = this;
+      if (!window.mapillary)
+        return;
+      const opts = {
+        accessToken,
+        component: {
+          cover: false,
+          keyboard: false,
+          tag: true
+        },
+        container: "ideditor-mly"
+      };
+      if (!mapillary.isSupported() && mapillary.isFallbackSupported()) {
+        _mlyFallback = true;
+        opts.component = {
+          cover: false,
+          direction: false,
+          imagePlane: false,
+          keyboard: false,
+          mouse: false,
+          sequence: false,
+          tag: false,
+          image: true,
+          // fallback
+          navigation: true
+          // fallback
+        };
+      }
+      _mlyViewer = new mapillary.Viewer(opts);
+      _mlyViewer.on("image", imageChanged);
+      _mlyViewer.on("bearing", bearingChanged);
+      if (_mlyViewerFilter) {
+        _mlyViewer.setFilter(_mlyViewerFilter);
+      }
+      context.ui().photoviewer.on("resize.mapillary", function() {
+        if (_mlyViewer)
+          _mlyViewer.resize();
+      });
+      function imageChanged(node) {
+        that.resetTags();
+        const image = node.image;
+        that.setActiveImage(image);
+        that.setStyles(context, null);
+        const loc = [image.originalLngLat.lng, image.originalLngLat.lat];
+        context.map().centerEase(loc);
+        that.updateUrlImage(image.id);
+        if (_mlyShowFeatureDetections || _mlyShowSignDetections) {
+          that.updateDetections(image.id, `${apiUrl}/${image.id}/detections?access_token=${accessToken}&fields=id,image,geometry,value`);
+        }
+        dispatch5.call("imageChanged");
+      }
+      function bearingChanged(e) {
+        dispatch5.call("bearingChanged", void 0, e);
+      }
+    },
+    // Move to an image
+    selectImage: function(context, imageId) {
+      if (_mlyViewer && imageId) {
+        _mlyViewer.moveTo(imageId).catch(function(e) {
+          console.error("mly3", e);
+        });
+      }
+      return this;
+    },
+    // Return the currently displayed image
+    getActiveImage: function() {
+      return _mlyActiveImage;
+    },
+    // Return a list of detection objects for the given id
+    getDetections: function(id2) {
+      return loadData(`${apiUrl}/${id2}/detections?access_token=${accessToken}&fields=id,value,image`);
+    },
+    // Set the currently visible image
+    setActiveImage: function(image) {
+      if (image) {
+        _mlyActiveImage = {
+          ca: image.originalCompassAngle,
+          id: image.id,
+          loc: [image.originalLngLat.lng, image.originalLngLat.lat],
+          is_pano: image.cameraType === "spherical",
+          sequence_id: image.sequenceId
+        };
+      } else {
+        _mlyActiveImage = null;
+      }
+    },
+    // 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 = _mlyActiveImage && _mlyActiveImage.sequence_id;
+      context.container().selectAll(".layer-mapillary .viewfield-group").classed("highlighted", function(d) {
+        return d.sequence_id === selectedSequenceId || d.id === hoveredImageId;
+      }).classed("hovered", function(d) {
+        return d.id === hoveredImageId;
+      });
+      context.container().selectAll(".layer-mapillary .sequence").classed("highlighted", function(d) {
+        return d.properties.id === hoveredSequenceId;
+      }).classed("currentView", function(d) {
+        return d.properties.id === selectedSequenceId;
+      });
+      return this;
+    },
+    // Get detections for the current image and shows them in the image viewer
+    updateDetections: function(imageId, url) {
+      if (!_mlyViewer || _mlyFallback)
+        return;
+      if (!imageId)
+        return;
+      const cache = _mlyCache.image_detections;
+      if (cache.forImageId[imageId]) {
+        showDetections(_mlyCache.image_detections.forImageId[imageId]);
+      } else {
+        loadData(url).then((detections) => {
+          detections.forEach(function(detection) {
+            if (!cache.forImageId[imageId]) {
+              cache.forImageId[imageId] = [];
+            }
+            cache.forImageId[imageId].push({
+              geometry: detection.geometry,
+              id: detection.id,
+              image_id: imageId,
+              value: detection.value
+            });
+          });
+          showDetections(_mlyCache.image_detections.forImageId[imageId] || []);
+        });
+      }
+      function showDetections(detections) {
+        const tagComponent = _mlyViewer.getComponent("tag");
+        detections.forEach(function(data) {
+          const tag = makeTag(data);
+          if (tag) {
+            tagComponent.add([tag]);
+          }
+        });
+      }
+      function makeTag(data) {
+        const valueParts = data.value.split("--");
+        if (!valueParts.length)
+          return;
+        let tag;
+        let text2;
+        let color2 = 16777215;
+        if (_mlyHighlightedDetection === data.id) {
+          color2 = 16776960;
+          text2 = valueParts[1];
+          if (text2 === "flat" || text2 === "discrete" || text2 === "sign") {
+            text2 = valueParts[2];
+          }
+          text2 = text2.replace(/-/g, " ");
+          text2 = text2.charAt(0).toUpperCase() + text2.slice(1);
+          _mlyHighlightedDetection = null;
+        }
+        var decodedGeometry = window.atob(data.geometry);
+        var uintArray = new Uint8Array(decodedGeometry.length);
+        for (var i2 = 0; i2 < decodedGeometry.length; i2++) {
+          uintArray[i2] = decodedGeometry.charCodeAt(i2);
+        }
+        const tile = new import_vector_tile.VectorTile(new import_pbf.default(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]));
+        tag = new mapillary.OutlineTag(
+          data.id,
+          new mapillary.PolygonGeometry(polygon2[0]),
+          {
+            text: text2,
+            textColor: color2,
+            lineColor: color2,
+            lineWidth: 2,
+            fillColor: color2,
+            fillOpacity: 0.3
+          }
+        );
+        return tag;
+      }
+    },
+    // Return the current cache
+    cache: function() {
+      return _mlyCache;
+    }
+  };
+
+  // modules/core/validation/models.js
+  function validationIssue(attrs) {
+    this.type = attrs.type;
+    this.subtype = attrs.subtype;
+    this.severity = attrs.severity;
+    this.message = attrs.message;
+    this.reference = attrs.reference;
+    this.entityIds = attrs.entityIds;
+    this.loc = attrs.loc;
+    this.data = attrs.data;
+    this.dynamicFixes = attrs.dynamicFixes;
+    this.hash = attrs.hash;
+    this.id = generateID.apply(this);
+    this.key = generateKey.apply(this);
+    this.autoFix = null;
+    function generateID() {
+      var parts = [this.type];
+      if (this.hash) {
+        parts.push(this.hash);
+      }
+      if (this.subtype) {
+        parts.push(this.subtype);
+      }
+      if (this.entityIds) {
+        var entityKeys = this.entityIds.slice().sort();
+        parts.push.apply(parts, entityKeys);
+      }
+      return parts.join(":");
+    }
+    function generateKey() {
+      return this.id + ":" + Date.now().toString();
+    }
+    this.extent = function(resolver) {
+      if (this.loc) {
+        return geoExtent(this.loc);
+      }
+      if (this.entityIds && this.entityIds.length) {
+        return this.entityIds.reduce(function(extent, entityId) {
+          return extent.extend(resolver.entity(entityId).extent(resolver));
+        }, geoExtent());
+      }
+      return null;
+    };
+    this.fixes = function(context) {
+      var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
+      var issue = this;
+      if (issue.severity === "warning") {
+        fixes.push(new validationIssueFix({
+          title: _t.append("issues.fix.ignore_issue.title"),
+          icon: "iD-icon-close",
+          onClick: function() {
+            context.validator().ignoreIssue(this.issue.id);
+          }
+        }));
+      }
+      fixes.forEach(function(fix) {
+        fix.id = fix.title.stringId;
+        fix.issue = issue;
+        if (fix.autoArgs) {
+          issue.autoFix = fix;
+        }
+      });
+      return fixes;
+    };
+  }
+  function validationIssueFix(attrs) {
+    this.title = attrs.title;
+    this.onClick = attrs.onClick;
+    this.disabledReason = attrs.disabledReason;
+    this.icon = attrs.icon;
+    this.entityIds = attrs.entityIds || [];
+    this.autoArgs = attrs.autoArgs;
+    this.issue = null;
+  }
+
+  // modules/services/maprules.js
+  var buildRuleChecks = function() {
+    return {
+      equals: function(equals) {
+        return function(tags) {
+          return Object.keys(equals).every(function(k) {
+            return equals[k] === tags[k];
+          });
+        };
+      },
+      notEquals: function(notEquals) {
+        return function(tags) {
+          return Object.keys(notEquals).some(function(k) {
+            return notEquals[k] !== tags[k];
+          });
+        };
+      },
+      absence: function(absence) {
+        return function(tags) {
+          return Object.keys(tags).indexOf(absence) === -1;
+        };
+      },
+      presence: function(presence) {
+        return function(tags) {
+          return Object.keys(tags).indexOf(presence) > -1;
+        };
+      },
+      greaterThan: function(greaterThan) {
+        var key = Object.keys(greaterThan)[0];
+        var value = greaterThan[key];
+        return function(tags) {
+          return tags[key] > value;
+        };
+      },
+      greaterThanEqual: function(greaterThanEqual) {
+        var key = Object.keys(greaterThanEqual)[0];
+        var value = greaterThanEqual[key];
+        return function(tags) {
+          return tags[key] >= value;
+        };
+      },
+      lessThan: function(lessThan) {
+        var key = Object.keys(lessThan)[0];
+        var value = lessThan[key];
+        return function(tags) {
+          return tags[key] < value;
+        };
+      },
+      lessThanEqual: function(lessThanEqual) {
+        var key = Object.keys(lessThanEqual)[0];
+        var value = lessThanEqual[key];
+        return function(tags) {
+          return tags[key] <= value;
+        };
+      },
+      positiveRegex: function(positiveRegex) {
+        var tagKey = Object.keys(positiveRegex)[0];
+        var expression = positiveRegex[tagKey].join("|");
+        var regex = new RegExp(expression);
+        return function(tags) {
+          return regex.test(tags[tagKey]);
+        };
+      },
+      negativeRegex: function(negativeRegex) {
+        var tagKey = Object.keys(negativeRegex)[0];
+        var expression = negativeRegex[tagKey].join("|");
+        var regex = new RegExp(expression);
+        return function(tags) {
+          return !regex.test(tags[tagKey]);
+        };
+      }
+    };
+  };
+  var buildLineKeys = function() {
+    return {
+      highway: {
+        rest_area: true,
+        services: true
+      },
+      railway: {
+        roundhouse: true,
+        station: true,
+        traverser: true,
+        turntable: true,
+        wash: true
+      }
+    };
+  };
+  var maprules_default = {
+    init: function() {
+      this._ruleChecks = buildRuleChecks();
+      this._validationRules = [];
+      this._areaKeys = osmAreaKeys;
+      this._lineKeys = buildLineKeys();
+    },
+    // list of rules only relevant to tag checks...
+    filterRuleChecks: function(selector) {
+      var _ruleChecks = this._ruleChecks;
+      return Object.keys(selector).reduce(function(rules, key) {
+        if (["geometry", "error", "warning"].indexOf(key) === -1) {
+          rules.push(_ruleChecks[key](selector[key]));
+        }
+        return rules;
+      }, []);
+    },
+    // builds tagMap from mapcss-parse selector object...
+    buildTagMap: function(selector) {
+      var getRegexValues = function(regexes) {
+        return regexes.map(function(regex) {
+          return regex.replace(/\$|\^/g, "");
+        });
+      };
+      var tagMap = Object.keys(selector).reduce(function(expectedTags, key) {
+        var values;
+        var isRegex = /regex/gi.test(key);
+        var isEqual4 = /equals/gi.test(key);
+        if (isRegex || isEqual4) {
+          Object.keys(selector[key]).forEach(function(selectorKey) {
+            values = isEqual4 ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
+            if (expectedTags.hasOwnProperty(selectorKey)) {
+              values = values.concat(expectedTags[selectorKey]);
+            }
+            expectedTags[selectorKey] = values;
+          });
+        } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
+          var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
+          values = [selector[key][tagKey]];
+          if (expectedTags.hasOwnProperty(tagKey)) {
+            values = values.concat(expectedTags[tagKey]);
+          }
+          expectedTags[tagKey] = values;
+        }
+        return expectedTags;
+      }, {});
+      return tagMap;
+    },
+    // inspired by osmWay#isArea()
+    inferGeometry: function(tagMap) {
+      var _lineKeys = this._lineKeys;
+      var _areaKeys = this._areaKeys;
+      var keyValueDoesNotImplyArea = function(key2) {
+        return utilArrayIntersection(tagMap[key2], Object.keys(_areaKeys[key2])).length > 0;
+      };
+      var keyValueImpliesLine = function(key2) {
+        return utilArrayIntersection(tagMap[key2], Object.keys(_lineKeys[key2])).length > 0;
+      };
+      if (tagMap.hasOwnProperty("area")) {
+        if (tagMap.area.indexOf("yes") > -1) {
+          return "area";
+        }
+        if (tagMap.area.indexOf("no") > -1) {
+          return "line";
+        }
+      }
+      for (var key in tagMap) {
+        if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
+          return "area";
+        }
+        if (key in _lineKeys && keyValueImpliesLine(key)) {
+          return "area";
+        }
+      }
+      return "line";
+    },
+    // adds from mapcss-parse selector check...
+    addRule: function(selector) {
+      var rule = {
+        // checks relevant to mapcss-selector
+        checks: this.filterRuleChecks(selector),
+        // true if all conditions for a tag error are true..
+        matches: function(entity) {
+          return this.checks.every(function(check) {
+            return check(entity.tags);
+          });
+        },
+        // borrowed from Way#isArea()
+        inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
+        geometryMatches: function(entity, graph) {
+          if (entity.type === "node" || entity.type === "relation") {
+            return selector.geometry === entity.type;
+          } else if (entity.type === "way") {
+            return this.inferredGeometry === entity.geometry(graph);
+          }
+        },
+        // when geometries match and tag matches are present, return a warning...
+        findIssues: function(entity, graph, issues) {
+          if (this.geometryMatches(entity, graph) && this.matches(entity)) {
+            var severity = Object.keys(selector).indexOf("error") > -1 ? "error" : "warning";
+            var message = selector[severity];
+            issues.push(new validationIssue({
+              type: "maprules",
+              severity,
+              message: function() {
+                return message;
+              },
+              entityIds: [entity.id]
+            }));
+          }
+        }
+      };
+      this._validationRules.push(rule);
+    },
+    clearRules: function() {
+      this._validationRules = [];
+    },
+    // returns validationRules...
+    validationRules: function() {
+      return this._validationRules;
+    },
+    // returns ruleChecks
+    ruleChecks: function() {
+      return this._ruleChecks;
+    }
+  };
+
+  // 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) {
+    var _changes = {};
+    var _didChange = {};
+    var _diff = {};
+    function checkEntityID(id2) {
+      var h = head.entities[id2];
+      var b = base.entities[id2];
+      if (h === b)
+        return;
+      if (_changes[id2])
+        return;
+      if (!h && b) {
+        _changes[id2] = { base: b, head: h };
+        _didChange.deletion = true;
+        return;
+      }
+      if (h && !b) {
+        _changes[id2] = { base: b, head: h };
+        _didChange.addition = true;
+        return;
+      }
+      if (h && b) {
+        if (h.members && b.members && !(0, import_fast_deep_equal3.default)(h.members, b.members)) {
+          _changes[id2] = { base: b, head: h };
+          _didChange.geometry = true;
+          _didChange.properties = true;
+          return;
+        }
+        if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
+          _changes[id2] = { base: b, head: h };
+          _didChange.geometry = true;
+        }
+        if (h.nodes && b.nodes && !(0, import_fast_deep_equal3.default)(h.nodes, b.nodes)) {
+          _changes[id2] = { base: b, head: h };
+          _didChange.geometry = true;
+        }
+        if (h.tags && b.tags && !(0, import_fast_deep_equal3.default)(h.tags, b.tags)) {
+          _changes[id2] = { base: b, head: h };
+          _didChange.properties = true;
+        }
+      }
+    }
+    function load() {
+      var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
+      for (var i2 = 0; i2 < ids.length; i2++) {
+        checkEntityID(ids[i2]);
+      }
+    }
+    load();
+    _diff.length = function length() {
+      return Object.keys(_changes).length;
+    };
+    _diff.changes = function changes() {
+      return _changes;
+    };
+    _diff.didChange = _didChange;
+    _diff.extantIDs = function extantIDs(includeRelMembers) {
+      var result = /* @__PURE__ */ new Set();
+      Object.keys(_changes).forEach(function(id2) {
+        if (_changes[id2].head) {
+          result.add(id2);
+        }
+        var h = _changes[id2].head;
+        var b = _changes[id2].base;
+        var entity = h || b;
+        if (includeRelMembers && entity.type === "relation") {
+          var mh = h ? h.members.map(function(m) {
+            return m.id;
+          }) : [];
+          var mb = b ? b.members.map(function(m) {
+            return m.id;
+          }) : [];
+          utilArrayUnion(mh, mb).forEach(function(memberID) {
+            if (head.hasEntity(memberID)) {
+              result.add(memberID);
+            }
+          });
+        }
+      });
+      return Array.from(result);
+    };
+    _diff.modified = function modified() {
+      var result = [];
+      Object.values(_changes).forEach(function(change) {
+        if (change.base && change.head) {
+          result.push(change.head);
+        }
+      });
+      return result;
+    };
+    _diff.created = function created() {
+      var result = [];
+      Object.values(_changes).forEach(function(change) {
+        if (!change.base && change.head) {
+          result.push(change.head);
+        }
+      });
+      return result;
+    };
+    _diff.deleted = function deleted() {
+      var result = [];
+      Object.values(_changes).forEach(function(change) {
+        if (change.base && !change.head) {
+          result.push(change.base);
+        }
+      });
+      return result;
+    };
+    _diff.summary = function summary() {
+      var relevant = {};
+      var keys2 = Object.keys(_changes);
+      for (var i2 = 0; i2 < keys2.length; i2++) {
+        var change = _changes[keys2[i2]];
+        if (change.head && change.head.geometry(head) !== "vertex") {
+          addEntity(change.head, head, change.base ? "modified" : "created");
+        } else if (change.base && change.base.geometry(base) !== "vertex") {
+          addEntity(change.base, base, "deleted");
+        } else if (change.base && change.head) {
+          var moved = !(0, import_fast_deep_equal3.default)(change.base.loc, change.head.loc);
+          var retagged = !(0, import_fast_deep_equal3.default)(change.base.tags, change.head.tags);
+          if (moved) {
+            addParents(change.head);
+          }
+          if (retagged || moved && change.head.hasInterestingTags()) {
+            addEntity(change.head, head, "modified");
+          }
+        } else if (change.head && change.head.hasInterestingTags()) {
+          addEntity(change.head, head, "created");
+        } else if (change.base && change.base.hasInterestingTags()) {
+          addEntity(change.base, base, "deleted");
+        }
+      }
+      return Object.values(relevant);
+      function addEntity(entity, graph, changeType) {
+        relevant[entity.id] = {
+          entity,
+          graph,
+          changeType
+        };
+      }
+      function addParents(entity) {
+        var parents = head.parentWays(entity);
+        for (var j2 = parents.length - 1; j2 >= 0; j2--) {
+          var parent = parents[j2];
+          if (!(parent.id in relevant)) {
+            addEntity(parent, head, "modified");
+          }
+        }
+      }
+    };
+    _diff.complete = function complete(extent) {
+      var result = {};
+      var id2, change;
+      for (id2 in _changes) {
+        change = _changes[id2];
+        var h = change.head;
+        var b = change.base;
+        var entity = h || b;
+        var i2;
+        if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) {
+          continue;
+        }
+        result[id2] = h;
+        if (entity.type === "way") {
+          var nh = h ? h.nodes : [];
+          var nb = b ? b.nodes : [];
+          var diff;
+          diff = utilArrayDifference(nh, nb);
+          for (i2 = 0; i2 < diff.length; i2++) {
+            result[diff[i2]] = head.hasEntity(diff[i2]);
+          }
+          diff = utilArrayDifference(nb, nh);
+          for (i2 = 0; i2 < diff.length; i2++) {
+            result[diff[i2]] = head.hasEntity(diff[i2]);
+          }
+        }
+        if (entity.type === "relation" && entity.isMultipolygon()) {
+          var mh = h ? h.members.map(function(m) {
+            return m.id;
+          }) : [];
+          var mb = b ? b.members.map(function(m) {
+            return m.id;
+          }) : [];
+          var ids = utilArrayUnion(mh, mb);
+          for (i2 = 0; i2 < ids.length; i2++) {
+            var member = head.hasEntity(ids[i2]);
+            if (!member)
+              continue;
+            if (extent && !member.intersects(extent, head))
+              continue;
+            result[ids[i2]] = member;
+          }
+        }
+        addParents(head.parentWays(entity), result);
+        addParents(head.parentRelations(entity), result);
+      }
+      return result;
+      function addParents(parents, result2) {
+        for (var i3 = 0; i3 < parents.length; i3++) {
+          var parent = parents[i3];
+          if (parent.id in result2)
+            continue;
+          result2[parent.id] = parent;
+          addParents(head.parentRelations(parent), result2);
+        }
+      }
+    };
+    return _diff;
+  }
+
+  // modules/core/tree.js
+  var import_rbush5 = __toESM(require_rbush_min());
+  function coreTree(head) {
+    var _rtree = new import_rbush5.default();
+    var _bboxes = {};
+    var _segmentsRTree = new import_rbush5.default();
+    var _segmentsBBoxes = {};
+    var _segmentsByWayId = {};
+    var tree = {};
+    function entityBBox(entity) {
+      var bbox2 = entity.extent(head).bbox();
+      bbox2.id = entity.id;
+      _bboxes[entity.id] = bbox2;
+      return bbox2;
+    }
+    function segmentBBox(segment) {
+      var extent = segment.extent(head);
+      if (!extent)
+        return null;
+      var bbox2 = extent.bbox();
+      bbox2.segment = segment;
+      _segmentsBBoxes[segment.id] = bbox2;
+      return bbox2;
+    }
+    function removeEntity(entity) {
+      _rtree.remove(_bboxes[entity.id]);
+      delete _bboxes[entity.id];
+      if (_segmentsByWayId[entity.id]) {
+        _segmentsByWayId[entity.id].forEach(function(segment) {
+          _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
+          delete _segmentsBBoxes[segment.id];
+        });
+        delete _segmentsByWayId[entity.id];
+      }
+    }
+    function loadEntities(entities) {
+      _rtree.load(entities.map(entityBBox));
+      var segments = [];
+      entities.forEach(function(entity) {
+        if (entity.segments) {
+          var entitySegments = entity.segments(head);
+          _segmentsByWayId[entity.id] = entitySegments;
+          segments = segments.concat(entitySegments);
+        }
+      });
+      if (segments.length)
+        _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
+    }
+    function updateParents(entity, insertions, memo) {
+      head.parentWays(entity).forEach(function(way) {
+        if (_bboxes[way.id]) {
+          removeEntity(way);
+          insertions[way.id] = way;
+        }
+        updateParents(way, insertions, memo);
+      });
+      head.parentRelations(entity).forEach(function(relation) {
+        if (memo[entity.id])
+          return;
+        memo[entity.id] = true;
+        if (_bboxes[relation.id]) {
+          removeEntity(relation);
+          insertions[relation.id] = relation;
+        }
+        updateParents(relation, insertions, memo);
+      });
+    }
+    tree.rebase = function(entities, force) {
+      var insertions = {};
+      for (var i2 = 0; i2 < entities.length; i2++) {
+        var entity = entities[i2];
+        if (!entity.visible)
+          continue;
+        if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
+          if (!force) {
+            continue;
+          } else if (_bboxes[entity.id]) {
+            removeEntity(entity);
+          }
+        }
+        insertions[entity.id] = entity;
+        updateParents(entity, insertions, {});
+      }
+      loadEntities(Object.values(insertions));
+      return tree;
+    };
+    function updateToGraph(graph) {
+      if (graph === head)
+        return;
+      var diff = coreDifference(head, graph);
+      head = graph;
+      var changed = diff.didChange;
+      if (!changed.addition && !changed.deletion && !changed.geometry)
+        return;
+      var insertions = {};
+      if (changed.deletion) {
+        diff.deleted().forEach(function(entity) {
+          removeEntity(entity);
+        });
+      }
+      if (changed.geometry) {
+        diff.modified().forEach(function(entity) {
+          removeEntity(entity);
+          insertions[entity.id] = entity;
+          updateParents(entity, insertions, {});
+        });
+      }
+      if (changed.addition) {
+        diff.created().forEach(function(entity) {
+          insertions[entity.id] = entity;
+        });
+      }
+      loadEntities(Object.values(insertions));
+    }
+    tree.intersects = function(extent, graph) {
+      updateToGraph(graph);
+      return _rtree.search(extent.bbox()).map(function(bbox2) {
+        return graph.entity(bbox2.id);
+      });
+    };
+    tree.waySegments = function(extent, graph) {
+      updateToGraph(graph);
+      return _segmentsRTree.search(extent.bbox()).map(function(bbox2) {
+        return bbox2.segment;
+      });
+    };
+    return tree;
+  }
+
+  // modules/svg/icon.js
+  function svgIcon(name, svgklass, useklass) {
+    return function drawIcon(selection2) {
+      selection2.selectAll("svg.icon" + (svgklass ? "." + svgklass.split(" ")[0] : "")).data([0]).enter().append("svg").attr("class", "icon " + (svgklass || "")).append("use").attr("xlink:href", name).attr("class", useklass);
+    };
+  }
+
+  // modules/ui/modal.js
+  function uiModal(selection2, blocking) {
+    let keybinding = utilKeybinding("modal");
+    let previous = selection2.select("div.modal");
+    let animate = previous.empty();
+    previous.transition().duration(200).style("opacity", 0).remove();
+    let shaded = selection2.append("div").attr("class", "shaded").style("opacity", 0);
+    shaded.close = () => {
+      shaded.transition().duration(200).style("opacity", 0).remove();
+      modal.transition().duration(200).style("top", "0px");
+      select_default2(document).call(keybinding.unbind);
+    };
+    let modal = shaded.append("div").attr("class", "modal fillL");
+    modal.append("input").attr("class", "keytrap keytrap-first").on("focus.keytrap", moveFocusToLast);
+    if (!blocking) {
+      shaded.on("click.remove-modal", (d3_event) => {
+        if (d3_event.target === this) {
+          shaded.close();
+        }
+      });
+      modal.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", shaded.close).call(svgIcon("#iD-icon-close"));
+      keybinding.on("\u232B", shaded.close).on("\u238B", shaded.close);
+      select_default2(document).call(keybinding);
+    }
+    modal.append("div").attr("class", "content");
+    modal.append("input").attr("class", "keytrap keytrap-last").on("focus.keytrap", moveFocusToFirst);
+    if (animate) {
+      shaded.transition().style("opacity", 1);
+    } else {
+      shaded.style("opacity", 1);
+    }
+    return shaded;
+    function moveFocusToFirst() {
+      let node = modal.select("a, button, input:not(.keytrap), select, textarea").node();
+      if (node) {
+        node.focus();
+      } else {
+        select_default2(this).node().blur();
+      }
+    }
+    function moveFocusToLast() {
+      let nodes = modal.selectAll("a, button, input:not(.keytrap), select, textarea").nodes();
+      if (nodes.length) {
+        nodes[nodes.length - 1].focus();
+      } else {
+        select_default2(this).node().blur();
+      }
+    }
+  }
+
+  // modules/ui/loading.js
+  function uiLoading(context) {
+    let _modalSelection = select_default2(null);
+    let _message = "";
+    let _blocking = false;
+    let loading = (selection2) => {
+      _modalSelection = uiModal(selection2, _blocking);
+      let loadertext = _modalSelection.select(".content").classed("loading-modal", true).append("div").attr("class", "modal-section fillL");
+      loadertext.append("img").attr("class", "loader").attr("src", context.imagePath("loader-white.gif"));
+      loadertext.append("h3").html(_message);
+      _modalSelection.select("button.close").attr("class", "hide");
+      return loading;
+    };
+    loading.message = function(val) {
+      if (!arguments.length)
+        return _message;
+      _message = val;
+      return loading;
+    };
+    loading.blocking = function(val) {
+      if (!arguments.length)
+        return _blocking;
+      _blocking = val;
+      return loading;
+    };
+    loading.close = () => {
+      _modalSelection.remove();
+    };
+    loading.isShown = () => {
+      return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
+    };
+    return loading;
+  }
+
+  // modules/core/history.js
+  function coreHistory(context) {
+    var dispatch10 = dispatch_default("reset", "change", "merge", "restore", "undone", "redone", "storage_error");
+    var lock = utilSessionMutex("lock");
+    var _hasUnresolvedRestorableChanges = lock.lock() && !!corePreferences(getKey("saved_history"));
+    var duration = 150;
+    var _imageryUsed = [];
+    var _photoOverlaysUsed = [];
+    var _checkpoints = {};
+    var _pausedGraph;
+    var _stack;
+    var _index;
+    var _tree;
+    function _act(actions, t) {
+      actions = Array.prototype.slice.call(actions);
+      var annotation;
+      if (typeof actions[actions.length - 1] !== "function") {
+        annotation = actions.pop();
+      }
+      var graph = _stack[_index].graph;
+      for (var i2 = 0; i2 < actions.length; i2++) {
+        graph = actions[i2](graph, t);
+      }
+      return {
+        graph,
+        annotation,
+        imageryUsed: _imageryUsed,
+        photoOverlaysUsed: _photoOverlaysUsed,
+        transform: context.projection.transform(),
+        selectedIDs: context.selectedIDs()
+      };
+    }
+    function _perform(args, t) {
+      var previous = _stack[_index].graph;
+      _stack = _stack.slice(0, _index + 1);
+      var actionResult = _act(args, t);
+      _stack.push(actionResult);
+      _index++;
+      return change(previous);
+    }
+    function _replace(args, t) {
+      var previous = _stack[_index].graph;
+      var actionResult = _act(args, t);
+      _stack[_index] = actionResult;
+      return change(previous);
+    }
+    function _overwrite(args, t) {
+      var previous = _stack[_index].graph;
+      if (_index > 0) {
+        _index--;
+        _stack.pop();
+      }
+      _stack = _stack.slice(0, _index + 1);
+      var actionResult = _act(args, t);
+      _stack.push(actionResult);
+      _index++;
+      return change(previous);
+    }
+    function change(previous) {
+      var difference = coreDifference(previous, history.graph());
+      if (!_pausedGraph) {
+        dispatch10.call("change", this, difference);
+      }
+      return difference;
+    }
+    function getKey(n2) {
+      return "iD_" + window.location.origin + "_" + n2;
+    }
+    var history = {
+      graph: function() {
+        return _stack[_index].graph;
+      },
+      tree: function() {
+        return _tree;
+      },
+      base: function() {
+        return _stack[0].graph;
+      },
+      merge: function(entities) {
+        var stack = _stack.map(function(state) {
+          return state.graph;
+        });
+        _stack[0].graph.rebase(entities, stack, false);
+        _tree.rebase(entities, false);
+        dispatch10.call("merge", this, entities);
       },
       perform: function() {
         select_default2(document).interrupt("history.perform");
@@ -39190,6 +40700,7 @@ ${content}</tr>
         select_default2(document).interrupt("history.perform");
         return _replace(arguments, 1);
       },
+      // Same as calling pop and then perform
       overwrite: function() {
         select_default2(document).interrupt("history.perform");
         return _overwrite(arguments, 1);
@@ -39206,6 +40717,7 @@ ${content}</tr>
         }
         return change(previous);
       },
+      // Back to the previous annotated state or _index = 0.
       undo: function() {
         select_default2(document).interrupt("history.perform");
         var previousStack = _stack[_index];
@@ -39218,6 +40730,7 @@ ${content}</tr>
         dispatch10.call("undone", this, _stack[_index], previousStack);
         return change(previous);
       },
+      // Forward to the next annotated state.
       redo: function() {
         select_default2(document).interrupt("history.perform");
         var previousStack = _stack[_index];
@@ -39261,6 +40774,8 @@ ${content}</tr>
           i2++;
         }
       },
+      // Returns the entities from the active graph with bounding boxes
+      // overlapping the given `extent`.
       intersects: function(extent) {
         return _tree.intersects(extent, _stack[_index].graph);
       },
@@ -39317,6 +40832,7 @@ ${content}</tr>
           return Array.from(s);
         }
       },
+      // save the current history state
       checkpoint: function(key) {
         _checkpoints[key] = {
           stack: _stack,
@@ -39324,6 +40840,7 @@ ${content}</tr>
         };
         return history;
       },
+      // restore history state to a given checkpoint or reset completely
       reset: function(key) {
         if (key !== void 0 && _checkpoints.hasOwnProperty(key)) {
           _stack = _checkpoints[key].stack;
@@ -39338,6 +40855,16 @@ ${content}</tr>
         dispatch10.call("change");
         return history;
       },
+      // `toIntroGraph()` is used to export the intro graph used by the walkthrough.
+      //
+      // To use it:
+      //  1. Start the walkthrough.
+      //  2. Get to a "free editing" tutorial step
+      //  3. Make your edits to the walkthrough map
+      //  4. In your browser dev console run:
+      //        `id.history().toIntroGraph()`
+      //  5. This outputs stringified JSON to the browser console
+      //  6. Copy it to `data/intro_graph.json` and prettify it in your code editor
       toIntroGraph: function() {
         var nextID = { n: 0, r: 0, w: 0 };
         var permIDs = {};
@@ -39452,7 +40979,8 @@ ${content}</tr>
           stack: s,
           nextIDs: osmEntity.id.next,
           index: _index,
-          timestamp: new Date().getTime()
+          // note the time the changes were saved
+          timestamp: (/* @__PURE__ */ new Date()).getTime()
         });
       },
       fromJSON: function(json, loadChildNodes) {
@@ -39571,13 +41099,15 @@ ${content}</tr>
         lock.unlock();
       },
       save: function() {
-        if (lock.locked() && !_hasUnresolvedRestorableChanges) {
+        if (lock.locked() && // don't overwrite existing, unresolved changes
+        !_hasUnresolvedRestorableChanges) {
           const success = corePreferences(getKey("saved_history"), history.toJSON() || null);
           if (!success)
             dispatch10.call("storage_error");
         }
         return history;
       },
+      // delete the history version saved in localStorage
       clearSaved: function() {
         context.debouncedSave.cancel();
         if (lock.locked()) {
@@ -39595,6 +41125,7 @@ ${content}</tr>
       hasRestorableChanges: function() {
         return _hasUnresolvedRestorableChanges;
       },
+      // load history from a version stored in localStorage
       restore: function() {
         if (lock.locked()) {
           _hasUnresolvedRestorableChanges = false;
@@ -39632,7 +41163,7 @@ ${content}</tr>
 
   // modules/validations/almost_junction.js
   function validationAlmostJunction(context) {
-    const type3 = "almost_junction";
+    const type2 = "almost_junction";
     const EXTEND_TH_METERS = 5;
     const WELD_TH_METERS = 0.75;
     const CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS;
@@ -39653,7 +41184,7 @@ ${content}</tr>
       let issues = [];
       extendableNodeInfos.forEach((extendableNodeInfo) => {
         issues.push(new validationIssue({
-          type: type3,
+          type: type2,
           subtype: "highway-highway",
           severity: "warning",
           message: function(context2) {
@@ -39871,13 +41402,13 @@ ${content}</tr>
         return null;
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/close_nodes.js
   function validationCloseNodes(context) {
-    var type3 = "close_nodes";
+    var type2 = "close_nodes";
     var pointThresholdMeters = 0.2;
     var validation = function(entity, graph) {
       if (entity.type === "node") {
@@ -39920,8 +41451,8 @@ ${content}</tr>
       function shouldCheckWay(way) {
         if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4)
           return false;
-        var bbox = way.extent(graph).bbox();
-        var hypotenuseMeters = geoSphericalDistance([bbox.minX, bbox.minY], [bbox.maxX, bbox.maxY]);
+        var bbox2 = way.extent(graph).bbox();
+        var hypotenuseMeters = geoSphericalDistance([bbox2.minX, bbox2.minY], [bbox2.maxX, bbox2.maxY]);
         if (hypotenuseMeters < 1.5)
           return false;
         return true;
@@ -40015,7 +41546,7 @@ ${content}</tr>
             if (zAxisDifferentiates)
               continue;
             issues.push(new validationIssue({
-              type: type3,
+              type: type2,
               subtype: "detached",
               severity: "warning",
               message: function(context2) {
@@ -40067,7 +41598,7 @@ ${content}</tr>
             return null;
         }
         return new validationIssue({
-          type: type3,
+          type: type2,
           subtype: "vertices",
           severity: "warning",
           message: function(context2) {
@@ -40101,13 +41632,14 @@ ${content}</tr>
         }
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/crossing_ways.js
+  var import_lodash3 = __toESM(require_lodash());
   function validationCrossingWays(context) {
-    var type3 = "crossing_ways";
+    var type2 = "crossing_ways";
     function getFeatureWithFeatureTypeTagsForWay(way, graph) {
       if (getFeatureType(way, graph) === null) {
         var parentRels = graph.parentRelations(way);
@@ -40205,8 +41737,7 @@ ${content}</tr>
       secondary: true,
       secondary_link: true
     };
-    var nonCrossingHighways = { track: true };
-    function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
+    function tagsForConnectionNodeIfAllowed(entity1, entity2, graph, lessLikelyTags) {
       var featureType1 = getFeatureType(entity1, graph);
       var featureType2 = getFeatureType(entity2, graph);
       var geometry1 = entity1.geometry(graph);
@@ -40218,11 +41749,14 @@ ${content}</tr>
           var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
           if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
             var roadFeature = entity1IsPath ? entity2 : entity1;
-            if (nonCrossingHighways[roadFeature.tags.highway]) {
+            var pathFeature = entity1IsPath ? entity1 : entity2;
+            if (roadFeature.tags.highway === "track") {
               return {};
             }
-            var pathFeature = entity1IsPath ? entity1 : entity2;
-            if (["marked", "unmarked", "traffic_signals"].indexOf(pathFeature.tags.crossing) !== -1) {
+            if (!lessLikelyTags && roadFeature.tags.highway === "service" && pathFeature.tags.highway === "footway" && pathFeature.tags.footway === "sidewalk") {
+              return {};
+            }
+            if (["marked", "unmarked", "traffic_signals", "uncontrolled"].indexOf(pathFeature.tags.crossing) !== -1) {
               return bothLines ? { highway: "crossing", crossing: pathFeature.tags.crossing } : {};
             }
             return bothLines ? { highway: "crossing" } : {};
@@ -40324,8 +41858,8 @@ ${content}</tr>
             continue;
           segment1 = [n1.loc, n2.loc];
           segment2 = [nA.loc, nB.loc];
-          var point = geoLineIntersection(segment1, segment2);
-          if (point) {
+          var point2 = geoLineIntersection(segment1, segment2);
+          if (point2) {
             edgeCrossInfos.push({
               wayInfos: [
                 {
@@ -40339,7 +41873,7 @@ ${content}</tr>
                   edge: [nA.id, nB.id]
                 }
               ],
-              crossPoint: point
+              crossPoint: point2
             });
             if (oneOnly) {
               checkedSingleCrossingWays[way2.id] = true;
@@ -40358,7 +41892,8 @@ ${content}</tr>
         return [entity];
       } else if (entity.type === "relation") {
         return entity.members.reduce(function(array2, member) {
-          if (member.type === "way" && (!member.role || member.role === "outer" || member.role === "inner")) {
+          if (member.type === "way" && // only look at geometry ways
+          (!member.role || member.role === "outer" || member.role === "inner")) {
             var entity2 = graph.hasEntity(member.id);
             if (entity2 && array2.indexOf(entity2) === -1) {
               array2.push(entity2);
@@ -40420,7 +41955,7 @@ ${content}</tr>
       }
       var uniqueID = crossing.crossPoint[0].toFixed(4) + "," + crossing.crossPoint[1].toFixed(4);
       return new validationIssue({
-        type: type3,
+        type: type2,
         subtype,
         severity: "warning",
         message: function(context2) {
@@ -40452,6 +41987,10 @@ ${content}</tr>
           var fixes = [];
           if (connectionTags) {
             fixes.push(makeConnectWaysFix(this.data.connectionTags));
+            let lessLikelyConnectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph, true);
+            if (lessLikelyConnectionTags && !(0, import_lodash3.isEqual)(connectionTags, lessLikelyConnectionTags)) {
+              fixes.push(makeConnectWaysFix(lessLikelyConnectionTags));
+            }
           }
           if (isCrossingIndoors) {
             fixes.push(new validationIssueFix({
@@ -40511,7 +42050,7 @@ ${content}</tr>
           var action = function actionAddStructure(graph) {
             var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
             var crossedWay = graph.hasEntity(crossedWayID);
-            var structLengthMeters = crossedWay && crossedWay.tags.width && parseFloat(crossedWay.tags.width);
+            var structLengthMeters = crossedWay && isFinite(crossedWay.tags.width) && Number(crossedWay.tags.width);
             if (!structLengthMeters) {
               structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
             }
@@ -40630,19 +42169,24 @@ ${content}</tr>
     }
     function makeConnectWaysFix(connectionTags) {
       var fixTitleID = "connect_features";
+      var fixIcon = "iD-icon-crossing";
+      if (connectionTags.highway === "crossing") {
+        fixTitleID = "connect_using_crossing";
+        fixIcon = "temaki-pedestrian";
+      }
       if (connectionTags.ford) {
         fixTitleID = "connect_using_ford";
+        fixIcon = "roentgen-ford";
       }
-      return new validationIssueFix({
-        icon: "iD-icon-crossing",
+      const fix = new validationIssueFix({
+        icon: fixIcon,
         title: _t.append("issues.fix." + fixTitleID + ".title"),
         onClick: function(context2) {
           var loc = this.issue.loc;
-          var connectionTags2 = this.issue.data.connectionTags;
           var edges = this.issue.data.edges;
           context2.perform(
             function actionConnectCrossingWays(graph) {
-              var node = osmNode({ loc, tags: connectionTags2 });
+              var node = osmNode({ loc, tags: connectionTags });
               graph = graph.replace(node);
               var nodesToMerge = [node.id];
               var mergeThresholdInMeters = 0.75;
@@ -40664,6 +42208,8 @@ ${content}</tr>
           );
         }
       });
+      fix._connectionTags = connectionTags;
+      return fix;
     }
     function makeChangeLayerFix(higherOrLower) {
       return new validationIssueFix({
@@ -40707,7 +42253,7 @@ ${content}</tr>
         }
       });
     }
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
@@ -40782,7 +42328,10 @@ ${content}</tr>
       }
       context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
       _drawNode = context.entity(_drawNode.id);
-      checkGeometry(true);
+      checkGeometry(
+        true
+        /* includeDrawNode */
+      );
     }
     function checkGeometry(includeDrawNode) {
       var nopeDisabled = context.surface().classed("nope-disabled");
@@ -40895,7 +42444,10 @@ ${content}</tr>
       } else {
         createDrawNode(loc);
       }
-      checkGeometry(true);
+      checkGeometry(
+        true
+        /* includeDrawNode */
+      );
       if (d && d.properties && d.properties.nope || context.surface().classed("nope")) {
         if (!_pointerHasMoved) {
           removeDrawNode();
@@ -40922,7 +42474,8 @@ ${content}</tr>
       });
     };
     drawWay.addNode = function(node, d) {
-      if (node.id === _headNodeID || _origWay.isClosed() && node.id === _origWay.first()) {
+      if (node.id === _headNodeID || // or the first node when drawing an area
+      _origWay.isClosed() && node.id === _origWay.first()) {
         drawWay.finish();
         return;
       }
@@ -40985,7 +42538,10 @@ ${content}</tr>
     keybinding.on(_t("operations.follow.key"), followMode);
     select_default2(document).call(keybinding);
     drawWay.finish = function() {
-      checkGeometry(false);
+      checkGeometry(
+        false
+        /* includeDrawNode */
+      );
       if (context.surface().classed("nope")) {
         dispatch10.call("rejectedSelfIntersection", this);
         return;
@@ -41058,7 +42614,7 @@ ${content}</tr>
 
   // modules/validations/disconnected_way.js
   function validationDisconnectedWay() {
-    var type3 = "disconnected_way";
+    var type2 = "disconnected_way";
     function isTaggedAsHighway(entity) {
       return osmRoutableHighwayTagValues[entity.tags.highway];
     }
@@ -41067,7 +42623,7 @@ ${content}</tr>
       if (!routingIslandWays)
         return [];
       return [new validationIssue({
-        type: type3,
+        type: type2,
         subtype: "highway",
         severity: "warning",
         message: function(context) {
@@ -41126,7 +42682,8 @@ ${content}</tr>
         var waysToCheck = [];
         function queueParentWays(node) {
           graph.parentWays(node).forEach(function(parentWay) {
-            if (!routingIsland.has(parentWay) && isRoutableWay(parentWay, false)) {
+            if (!routingIsland.has(parentWay) && // only check each feature once
+            isRoutableWay(parentWay, false)) {
               routingIsland.add(parentWay);
               waysToCheck.push(parentWay);
             }
@@ -41210,13 +42767,13 @@ ${content}</tr>
         });
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/invalid_format.js
   function validationFormatting() {
-    var type3 = "invalid_format";
+    var type2 = "invalid_format";
     var validation = function(entity) {
       var issues = [];
       function isValidEmail(email) {
@@ -41234,7 +42791,7 @@ ${content}</tr>
         });
         if (emails.length) {
           issues.push(new validationIssue({
-            type: type3,
+            type: type2,
             subtype: "email",
             severity: "warning",
             message: function(context) {
@@ -41253,13 +42810,13 @@ ${content}</tr>
       }
       return issues;
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/help_request.js
   function validationHelpRequest(context) {
-    var type3 = "help_request";
+    var type2 = "help_request";
     var validation = function checkFixmeTag(entity) {
       if (!entity.tags.fixme)
         return [];
@@ -41271,13 +42828,18 @@ ${content}</tr>
           return [];
       }
       return [new validationIssue({
-        type: type3,
+        type: type2,
         subtype: "fixme_tag",
         severity: "warning",
         message: function(context2) {
           var entity2 = context2.hasEntity(this.entityIds[0]);
           return entity2 ? _t.append("issues.fixme_tag.message", {
-            feature: utilDisplayLabel(entity2, context2.graph(), true)
+            feature: utilDisplayLabel(
+              entity2,
+              context2.graph(),
+              true
+              /* verbose */
+            )
           }) : "";
         },
         dynamicFixes: function() {
@@ -41294,13 +42856,13 @@ ${content}</tr>
         selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.fixme_tag.reference"));
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/impossible_oneway.js
   function validationImpossibleOneway() {
-    var type3 = "impossible_oneway";
+    var type2 = "impossible_oneway";
     var validation = function checkImpossibleOneway(entity, graph) {
       if (entity.type !== "way" || entity.geometry(graph) !== "line")
         return [];
@@ -41426,7 +42988,7 @@ ${content}</tr>
           referenceID += placement;
         }
         return [new validationIssue({
-          type: type3,
+          type: type2,
           subtype: wayType,
           severity: "warning",
           message: function(context) {
@@ -41485,13 +43047,13 @@ ${content}</tr>
         modeDrawLine(context, way.id, context.graph(), "line", way.affix(vertex.id), true)
       );
     }
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/incompatible_source.js
   function validationIncompatibleSource() {
-    const type3 = "incompatible_source";
+    const type2 = "incompatible_source";
     const incompatibleRules = [
       {
         id: "amap",
@@ -41523,12 +43085,17 @@ ${content}</tr>
         if (!matchRule)
           return null;
         return new validationIssue({
-          type: type3,
+          type: type2,
           severity: "warning",
           message: (context) => {
             const entity2 = context.hasEntity(entityID);
             return entity2 ? _t.append("issues.incompatible_source.feature.message", {
-              feature: utilDisplayLabel(entity2, context.graph(), true),
+              feature: utilDisplayLabel(
+                entity2,
+                context.graph(),
+                true
+                /* verbose */
+              ),
               value: source
             }) : "";
           },
@@ -41548,13 +43115,13 @@ ${content}</tr>
         };
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/maprules.js
   function validationMaprules() {
-    var type3 = "maprules";
+    var type2 = "maprules";
     var validation = function checkMaprules(entity, graph) {
       if (!services.maprules)
         return [];
@@ -41566,14 +43133,14 @@ ${content}</tr>
       }
       return issues;
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/mismatched_geometry.js
   var import_fast_deep_equal4 = __toESM(require_fast_deep_equal());
   function validationMismatchedGeometry() {
-    var type3 = "mismatched_geometry";
+    var type2 = "mismatched_geometry";
     function tagSuggestingLineIsArea(entity) {
       if (entity.type !== "way" || entity.isClosed())
         return null;
@@ -41626,14 +43193,31 @@ ${content}</tr>
       var tagSuggestingArea = tagSuggestingLineIsArea(entity);
       if (!tagSuggestingArea)
         return null;
+      var validAsLine = false;
+      var presetAsLine = _mainPresetIndex.matchTags(entity.tags, "line");
+      if (presetAsLine) {
+        validAsLine = true;
+        var key = Object.keys(tagSuggestingArea)[0];
+        if (presetAsLine.tags[key] && presetAsLine.tags[key] === "*") {
+          validAsLine = false;
+        }
+        if (Object.keys(presetAsLine.tags).length === 0) {
+          validAsLine = false;
+        }
+      }
       return new validationIssue({
-        type: type3,
+        type: type2,
         subtype: "area_as_line",
         severity: "warning",
         message: function(context) {
           var entity2 = context.hasEntity(this.entityIds[0]);
           return entity2 ? _t.append("issues.tag_suggests_area.message", {
-            feature: utilDisplayLabel(entity2, "area", true),
+            feature: utilDisplayLabel(
+              entity2,
+              "area",
+              true
+              /* verbose */
+            ),
             tag: utilTagText({ tags: tagSuggestingArea })
           }) : "";
         },
@@ -41644,10 +43228,12 @@ ${content}</tr>
           var fixes = [];
           var entity2 = context.entity(this.entityIds[0]);
           var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity2, context.graph());
-          fixes.push(new validationIssueFix({
-            title: _t.append("issues.fix.connect_endpoints.title"),
-            onClick: connectEndsOnClick
-          }));
+          if (!validAsLine) {
+            fixes.push(new validationIssueFix({
+              title: _t.append("issues.fix.connect_endpoints.title"),
+              onClick: connectEndsOnClick
+            }));
+          }
           fixes.push(new validationIssueFix({
             icon: "iD-operation-delete",
             title: _t.append("issues.fix.remove_tag.title"),
@@ -41655,8 +43241,8 @@ ${content}</tr>
               var entityId = this.issue.entityIds[0];
               var entity3 = context2.entity(entityId);
               var tags = Object.assign({}, entity3.tags);
-              for (var key in tagSuggestingArea) {
-                delete tags[key];
+              for (var key2 in tagSuggestingArea) {
+                delete tags[key2];
               }
               context2.perform(
                 actionChangeTags(entityId, tags),
@@ -41682,13 +43268,18 @@ ${content}</tr>
       var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
       if (geometry === "point" && !allowedGeometries.point && allowedGeometries.vertex) {
         return new validationIssue({
-          type: type3,
+          type: type2,
           subtype: "vertex_as_point",
           severity: "warning",
           message: function(context) {
             var entity2 = context.hasEntity(this.entityIds[0]);
             return entity2 ? _t.append("issues.vertex_as_point.message", {
-              feature: utilDisplayLabel(entity2, "vertex", true)
+              feature: utilDisplayLabel(
+                entity2,
+                "vertex",
+                true
+                /* verbose */
+              )
             }) : "";
           },
           reference: function showReference(selection2) {
@@ -41698,13 +43289,18 @@ ${content}</tr>
         });
       } else if (geometry === "vertex" && !allowedGeometries.vertex && allowedGeometries.point) {
         return new validationIssue({
-          type: type3,
+          type: type2,
           subtype: "point_as_vertex",
           severity: "warning",
           message: function(context) {
             var entity2 = context.hasEntity(this.entityIds[0]);
             return entity2 ? _t.append("issues.point_as_vertex.message", {
-              feature: utilDisplayLabel(entity2, "point", true)
+              feature: utilDisplayLabel(
+                entity2,
+                "point",
+                true
+                /* verbose */
+              )
             }) : "";
           },
           reference: function showReference(selection2) {
@@ -41730,7 +43326,8 @@ ${content}</tr>
       var asSource = _mainPresetIndex.match(entity, graph);
       var targetGeom = targetGeoms.find((nodeGeom) => {
         var asTarget = _mainPresetIndex.matchTags(entity.tags, nodeGeom);
-        if (!asSource || !asTarget || asSource === asTarget || (0, import_fast_deep_equal4.default)(asSource.tags, asTarget.tags))
+        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;
@@ -41756,13 +43353,18 @@ ${content}</tr>
         dynamicFixes = lineToAreaDynamicFixes;
       }
       return new validationIssue({
-        type: type3,
+        type: type2,
         subtype,
         severity: "warning",
         message: function(context) {
           var entity2 = context.hasEntity(this.entityIds[0]);
           return entity2 ? _t.append("issues." + referenceId + ".message", {
-            feature: utilDisplayLabel(entity2, targetGeom, true)
+            feature: utilDisplayLabel(
+              entity2,
+              targetGeom,
+              true
+              /* verbose */
+            )
           }) : "";
         },
         reference: function showReference(selection2) {
@@ -41823,7 +43425,8 @@ ${content}</tr>
       ];
     }
     function unclosedMultipolygonPartIssues(entity, graph) {
-      if (entity.type !== "relation" || !entity.isMultipolygon() || entity.isDegenerate() || !entity.isComplete(graph))
+      if (entity.type !== "relation" || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
+      !entity.isComplete(graph))
         return [];
       var sequences = osmJoinWays(entity.members, graph);
       var issues = [];
@@ -41836,13 +43439,18 @@ ${content}</tr>
         if (firstNode === lastNode)
           continue;
         var issue = new validationIssue({
-          type: type3,
+          type: type2,
           subtype: "unclosed_multipolygon_part",
           severity: "warning",
           message: function(context) {
             var entity2 = context.hasEntity(this.entityIds[0]);
             return entity2 ? _t.append("issues.unclosed_multipolygon_part.message", {
-              feature: utilDisplayLabel(entity2, context.graph(), true)
+              feature: utilDisplayLabel(
+                entity2,
+                context.graph(),
+                true
+                /* verbose */
+              )
             }) : "";
           },
           reference: showReference,
@@ -41871,13 +43479,13 @@ ${content}</tr>
         return [mismatch];
       return unclosedMultipolygonPartIssues(entity, graph);
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/missing_role.js
   function validationMissingRole() {
-    var type3 = "missing_role";
+    var type2 = "missing_role";
     var validation = function checkMissingRole(entity, graph) {
       var issues = [];
       if (entity.type === "way") {
@@ -41904,7 +43512,7 @@ ${content}</tr>
     }
     function makeIssue(way, relation, member) {
       return new validationIssue({
-        type: type3,
+        type: type2,
         severity: "warning",
         message: function(context) {
           var member2 = context.hasEntity(this.entityIds[1]), relation2 = context.hasEntity(this.entityIds[0]);
@@ -41957,13 +43565,13 @@ ${content}</tr>
         }
       });
     }
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/missing_tag.js
   function validationMissingTag(context) {
-    var type3 = "missing_tag";
+    var type2 = "missing_tag";
     function hasDescriptiveTags(entity, graph) {
       var onlyAttributeKeys = ["description", "name", "note", "start_date"];
       var entityDescriptiveKeys = Object.keys(entity.tags).filter(function(k) {
@@ -41988,7 +43596,9 @@ ${content}</tr>
       var subtype;
       var osm = context.connection();
       var isUnloadedNode = entity.type === "node" && osm && !osm.isDataLoaded(entity.loc);
-      if (!isUnloadedNode && entity.geometry(graph) !== "vertex" && !entity.hasParentRelations(graph)) {
+      if (!isUnloadedNode && // allow untagged nodes that are part of ways
+      entity.geometry(graph) !== "vertex" && // allow untagged entities that are part of relations
+      !entity.hasParentRelations(graph)) {
         if (Object.keys(entity.tags).length === 0) {
           subtype = "any";
         } else if (!hasDescriptiveTags(entity, graph)) {
@@ -42007,7 +43617,7 @@ ${content}</tr>
       var canDelete = entity.version === void 0 || entity.v !== void 0;
       var severity = canDelete && subtype !== "highway_classification" ? "error" : "warning";
       return [new validationIssue({
-        type: type3,
+        type: type2,
         subtype,
         severity,
         message: function(context2) {
@@ -42056,28 +43666,34 @@ ${content}</tr>
         selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues." + referenceID + ".reference"));
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/outdated_tags.js
   function validationOutdatedTags() {
-    const type3 = "outdated_tags";
+    const type2 = "outdated_tags";
     let _waitingForDeprecated = true;
     let _dataDeprecated;
     _mainFileFetcher.get("deprecated").then((d) => _dataDeprecated = d).catch(() => {
     }).finally(() => _waitingForDeprecated = false);
     function oldTagIssues(entity, graph) {
-      const oldTags = Object.assign({}, entity.tags);
+      if (!entity.hasInterestingTags())
+        return [];
       let preset = _mainPresetIndex.match(entity, graph);
-      let subtype = "deprecated_tags";
       if (!preset)
         return [];
-      if (!entity.hasInterestingTags())
-        return [];
+      const oldTags = Object.assign({}, entity.tags);
+      let subtype = "deprecated_tags";
       if (preset.replacement) {
         const newPreset = _mainPresetIndex.item(preset.replacement);
-        graph = actionChangePreset(entity.id, preset, newPreset, true)(graph);
+        graph = actionChangePreset(
+          entity.id,
+          preset,
+          newPreset,
+          true
+          /* skip field defaults */
+        )(graph);
         entity = graph.entity(entity.id);
         preset = newPreset;
       }
@@ -42131,7 +43747,7 @@ ${content}</tr>
       }
       let autoArgs = subtype !== "noncanonical_brand" ? [doUpgrade, _t("issues.fix.upgrade_tags.annotation")] : null;
       issues.push(new validationIssue({
-        type: type3,
+        type: type2,
         subtype,
         severity: "warning",
         message: showMessage,
@@ -42205,7 +43821,12 @@ ${content}</tr>
           messageID += "_incomplete";
         }
         return _t.append(messageID, {
-          feature: utilDisplayLabel(currEntity, context.graph(), true)
+          feature: utilDisplayLabel(
+            currEntity,
+            context.graph(),
+            true
+            /* verbose */
+          )
         });
       }
       function showReference(selection2) {
@@ -42232,7 +43853,7 @@ ${content}</tr>
       if (!multipolygon || !outerWay)
         return [];
       return [new validationIssue({
-        type: type3,
+        type: type2,
         subtype: "old_multipolygon",
         severity: "warning",
         message: showMessage,
@@ -42265,7 +43886,12 @@ ${content}</tr>
           return "";
         return _t.append(
           "issues.old_multipolygon.message",
-          { multipolygon: utilDisplayLabel(currMultipolygon, context.graph(), true) }
+          { multipolygon: utilDisplayLabel(
+            currMultipolygon,
+            context.graph(),
+            true
+            /* verbose */
+          ) }
         );
       }
       function showReference(selection2) {
@@ -42278,13 +43904,13 @@ ${content}</tr>
         issues = oldTagIssues(entity, graph);
       return issues;
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/private_data.js
   function validationPrivateData() {
-    var type3 = "private_data";
+    var type2 = "private_data";
     var privateBuildingValues = {
       detached: true,
       farm: true,
@@ -42328,7 +43954,7 @@ ${content}</tr>
         return [];
       var fixID = tagDiff.length === 1 ? "remove_tag" : "remove_tags";
       return [new validationIssue({
-        type: type3,
+        type: type2,
         severity: "warning",
         message: showMessage,
         reference: showReference,
@@ -42380,13 +44006,13 @@ ${content}</tr>
         });
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/suspicious_name.js
   function validationSuspiciousName() {
-    const type3 = "suspicious_name";
+    const type2 = "suspicious_name";
     const keysToTestForGenericValues = [
       "aerialway",
       "aeroway",
@@ -42432,7 +44058,7 @@ ${content}</tr>
     }
     function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
       return new validationIssue({
-        type: type3,
+        type: type2,
         subtype: "generic_name",
         severity: "warning",
         message: function(context) {
@@ -42474,7 +44100,7 @@ ${content}</tr>
     }
     function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
       return new validationIssue({
-        type: type3,
+        type: type2,
         subtype: "not_name",
         severity: "warning",
         message: function(context) {
@@ -42543,13 +44169,13 @@ ${content}</tr>
       }
       return issues;
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
   // modules/validations/unsquare_way.js
   function validationUnsquareWay(context) {
-    var type3 = "unsquare_way";
+    var type2 = "unsquare_way";
     var DEFAULT_DEG_THRESHOLD = 5;
     var epsilon3 = 0.05;
     var nodeThreshold = 10;
@@ -42588,7 +44214,7 @@ ${content}</tr>
       if (hasConnectedSquarableWays)
         return [];
       var storedDegreeThreshold = corePreferences("validate-square-degrees");
-      var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
+      var degreeThreshold = isFinite(storedDegreeThreshold) ? Number(storedDegreeThreshold) : DEFAULT_DEG_THRESHOLD;
       var points = nodes.map(function(node) {
         return context.projection(node.loc);
       });
@@ -42601,7 +44227,7 @@ ${content}</tr>
         autoArgs = [autoAction, _t("operations.orthogonalize.annotation.feature", { n: 1 })];
       }
       return [new validationIssue({
-        type: type3,
+        type: type2,
         subtype: "building",
         severity: "warning",
         message: function(context2) {
@@ -42630,6 +44256,21 @@ ${content}</tr>
                 }, 175);
               }
             })
+            /*
+            new validationIssueFix({
+                title: t.append('issues.fix.tag_as_unsquare.title'),
+                onClick: function(context) {
+                    var entityId = this.issue.entityIds[0];
+                    var entity = context.entity(entityId);
+                    var tags = Object.assign({}, entity.tags);  // shallow copy
+                    tags.nonsquare = 'yes';
+                    context.perform(
+                        actionChangeTags(entityId, tags),
+                        t('issues.fix.tag_as_unsquare.annotation')
+                    );
+                }
+            })
+            */
           ];
         }
       })];
@@ -42637,7 +44278,7 @@ ${content}</tr>
         selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.unsquare_way.buildings.reference"));
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
@@ -42666,11 +44307,11 @@ ${content}</tr>
       rules.forEach((rule) => {
         rule = rule.trim();
         const parts = rule.split("/", 2);
-        const type3 = parts[0];
+        const type2 = parts[0];
         const subtype = parts[1] || "*";
-        if (!type3 || !subtype)
+        if (!type2 || !subtype)
           return;
-        result.push({ type: makeRegExp(type3), subtype: makeRegExp(subtype) });
+        result.push({ type: makeRegExp(type2), subtype: makeRegExp(subtype) });
       });
       return result;
       function makeRegExp(str2) {
@@ -42830,14 +44471,19 @@ ${content}</tr>
     };
     validator.getSharedEntityIssues = (entityIDs, options2) => {
       const orderedIssueTypes = [
+        // Show some issue types in a particular order:
         "missing_tag",
         "missing_role",
+        // - missing data first
         "outdated_tags",
         "mismatched_geometry",
+        // - identity issues
         "crossing_ways",
         "almost_junction",
+        // - geometry issues where fixing them might solve connectivity issues
         "disconnected_way",
         "impossible_oneway"
+        // - finally connectivity issues
       ];
       const allIssues = validator.getIssues(options2);
       const forEntityIDs = new Set(entityIDs);
@@ -42874,9 +44520,9 @@ ${content}</tr>
       corePreferences("validate-disabledRules", Object.keys(_disabledRules).join(","));
       validator.validate();
     };
-    validator.disableRules = (keys) => {
+    validator.disableRules = (keys2) => {
       _disabledRules = {};
-      keys.forEach((k) => _disabledRules[k] = true);
+      keys2.forEach((k) => _disabledRules[k] = true);
       corePreferences("validate-disabledRules", Object.keys(_disabledRules).join(","));
       validator.validate();
     };
@@ -42952,23 +44598,23 @@ ${content}</tr>
         detected = detected.filter(applySeverityOverrides);
         result.issues = result.issues.concat(detected);
         function applySeverityOverrides(issue) {
-          const type3 = issue.type;
+          const type2 = issue.type;
           const subtype = issue.subtype || "";
           let i2;
           for (i2 = 0; i2 < _errorOverrides.length; i2++) {
-            if (_errorOverrides[i2].type.test(type3) && _errorOverrides[i2].subtype.test(subtype)) {
+            if (_errorOverrides[i2].type.test(type2) && _errorOverrides[i2].subtype.test(subtype)) {
               issue.severity = "error";
               return true;
             }
           }
           for (i2 = 0; i2 < _warningOverrides.length; i2++) {
-            if (_warningOverrides[i2].type.test(type3) && _warningOverrides[i2].subtype.test(subtype)) {
+            if (_warningOverrides[i2].type.test(type2) && _warningOverrides[i2].subtype.test(subtype)) {
               issue.severity = "warning";
               return true;
             }
           }
           for (i2 = 0; i2 < _disableOverrides.length; i2++) {
-            if (_disableOverrides[i2].type.test(type3) && _disableOverrides[i2].subtype.test(subtype)) {
+            if (_disableOverrides[i2].type.test(type2) && _disableOverrides[i2].subtype.test(subtype)) {
               return false;
             }
           }
@@ -43058,7 +44704,9 @@ ${content}</tr>
       queuedEntityIDs: /* @__PURE__ */ new Set(),
       provisionalEntityIDs: /* @__PURE__ */ new Set(),
       issuesByIssueID: {},
+      // issue.id -> issue
       issuesByEntityID: {}
+      // entity.id -> Set(issue.id)
     };
     cache.cacheIssue = (issue) => {
       (issue.entityIds || []).forEach((entityID) => {
@@ -43083,8 +44731,8 @@ ${content}</tr>
     cache.uncacheIssues = (issues) => {
       issues.forEach(cache.uncacheIssue);
     };
-    cache.uncacheIssuesOfType = (type3) => {
-      const issuesOfType = Object.values(cache.issuesByIssueID).filter((issue) => issue.type === type3);
+    cache.uncacheIssuesOfType = (type2) => {
+      const issuesOfType = Object.values(cache.issuesByIssueID).filter((issue) => issue.type === type2);
       cache.uncacheIssues(issuesOfType);
     };
     cache.uncacheEntityID = (entityID) => {
@@ -43126,14 +44774,23 @@ ${content}</tr>
   // modules/core/uploader.js
   function coreUploader(context) {
     var dispatch10 = dispatch_default(
+      // Start and end events are dispatched exactly once each per legitimate outside call to `save`
       "saveStarted",
+      // dispatched as soon as a call to `save` has been deemed legitimate
       "saveEnded",
+      // dispatched after the result event has been dispatched
       "willAttemptUpload",
+      // dispatched before the actual upload call occurs, if it will
       "progressChanged",
+      // Each save results in one of these outcomes:
       "resultNoChanges",
+      // upload wasn't attempted since there were no edits
       "resultErrors",
+      // upload failed due to errors
       "resultConflicts",
+      // upload failed due to data conflicts
       "resultSuccess"
+      // upload completed without errors
     );
     var _isSaving = false;
     var _conflicts = [];
@@ -43309,9 +44966,9 @@ ${content}</tr>
           var remote = remoteGraph.entity(id2);
           if (sameVersions(local, remote))
             return;
-          var merge3 = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags, formatUser);
-          history.replace(merge3);
-          var mergeConflicts = merge3.conflicts();
+          var merge2 = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags, formatUser);
+          history.replace(merge2);
+          var mergeConflicts = merge2.conflicts();
           if (!mergeConflicts.length)
             return;
           var forceLocal = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags).withOption("force_local");
@@ -43420,10 +45077,16 @@ ${content}</tr>
   }
 
   // modules/renderer/background_source.js
-  var import_lodash2 = __toESM(require_lodash());
+  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 = [];
@@ -43497,15 +45160,20 @@ ${content}</tr>
     };
     source.name = function() {
       var id_safe = source.id.replace(/\./g, "<TX_DOT>");
-      return _t("imagery." + id_safe + ".name", { default: (0, import_lodash2.escape)(_name) });
+      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_lodash2.escape)(_name) });
+      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_lodash2.escape)(_description) });
+      return _t.append("imagery." + id_safe + ".description", { default: (0, import_lodash4.escape)(_description) });
     };
     source.best = function() {
       return _best;
@@ -43574,7 +45242,8 @@ ${content}</tr>
             case "wkid":
               return projection2.replace(/^EPSG:/, "");
             case "bbox":
-              if (projection2 === "EPSG:4326" && /VERSION=1.3|CRS={proj}/.test(source.template().toUpperCase())) {
+              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;
@@ -43799,8 +45468,8 @@ ${content}</tr>
           vintage,
           source: clean2(result.NICE_NAME),
           description: clean2(result.NICE_DESC),
-          resolution: clean2(+parseFloat(result.SRC_RES).toFixed(4)),
-          accuracy: clean2(+parseFloat(result.SRC_ACC).toFixed(4))
+          resolution: clean2(+Number(result.SRC_RES).toFixed(4)),
+          accuracy: clean2(+Number(result.SRC_ACC).toFixed(4))
         };
         if (isFinite(metadata.resolution)) {
           metadata.resolution += " m";
@@ -43867,8 +45536,375 @@ ${content}</tr>
     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.");
+        }
+      }
+    }
+    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");
+    }
+    var geom = {
+      type: "LineString",
+      coordinates
+    };
+    return feature2(geom, properties, options2);
+  }
+  function multiLineString(coordinates, properties, options2) {
+    if (options2 === void 0) {
+      options2 = {};
+    }
+    var geom = {
+      type: "MultiLineString",
+      coordinates
+    };
+    return feature2(geom, properties, options2);
+  }
+  function multiPolygon(coordinates, properties, options2) {
+    if (options2 === void 0) {
+      options2 = {};
+    }
+    var geom = {
+      type: "MultiPolygon",
+      coordinates
+    };
+    return feature2(geom, properties, options2);
+  }
+
+  // node_modules/@turf/invariant/dist/es/index.js
+  function getGeom(geojson) {
+    if (geojson.type === "Feature") {
+      return geojson.geometry;
+    }
+    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 = [], i2, codeB, lastCode;
+    var a;
+    var b;
+    if (!result)
+      result = [];
+    for (i2 = 1; i2 < len; i2++) {
+      a = points[i2 - 1];
+      b = points[i2];
+      codeB = lastCode = bitCode(b, bbox2);
+      while (true) {
+        if (!(codeA | codeB)) {
+          part.push(a);
+          if (codeB !== lastCode) {
+            part.push(b);
+            if (i2 < len - 1) {
+              result.push(part);
+              part = [];
+            }
+          } else if (i2 === len - 1) {
+            part.push(b);
+          }
+          break;
+        } else if (codeA & codeB) {
+          break;
+        } else if (codeA) {
+          a = intersect(a, b, codeA, bbox2);
+          codeA = bitCode(a, bbox2);
+        } else {
+          b = intersect(a, b, codeB, bbox2);
+          codeB = bitCode(b, bbox2);
+        }
+      }
+      codeA = lastCode;
+    }
+    if (part.length)
+      result.push(part);
+    return result;
+  }
+  function polygonclip(points, bbox2) {
+    var result, edge, prev, prevInside, i2, p, inside;
+    for (edge = 1; edge <= 8; edge *= 2) {
+      result = [];
+      prev = points[points.length - 1];
+      prevInside = !(bitCode(prev, bbox2) & edge);
+      for (i2 = 0; i2 < points.length; i2++) {
+        p = points[i2];
+        inside = !(bitCode(p, bbox2) & edge);
+        if (inside !== prevInside)
+          result.push(intersect(prev, p, edge, bbox2));
+        if (inside)
+          result.push(p);
+        prev = p;
+        prevInside = inside;
+      }
+      points = result;
+      if (!points.length)
+        break;
+    }
+    return result;
+  }
+  function intersect(a, b, edge, bbox2) {
+    return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox2[3] - a[1]) / (b[1] - a[1]), bbox2[3]] : edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox2[1] - a[1]) / (b[1] - a[1]), bbox2[1]] : edge & 2 ? [bbox2[2], a[1] + (b[1] - a[1]) * (bbox2[2] - a[0]) / (b[0] - a[0])] : edge & 1 ? [bbox2[0], a[1] + (b[1] - a[1]) * (bbox2[0] - a[0]) / (b[0] - a[0])] : null;
+  }
+  function bitCode(p, bbox2) {
+    var code = 0;
+    if (p[0] < bbox2[0])
+      code |= 1;
+    else if (p[0] > bbox2[2])
+      code |= 2;
+    if (p[1] < bbox2[1])
+      code |= 4;
+    else if (p[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);
+        }
+        return multiLineString(lines_1, properties);
+      }
+      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);
+        }
+      }
+    }
+    return outRings;
+  }
+
+  // node_modules/@turf/meta/dist/es/index.js
+  function coordEach(geojson, callback, excludeWrapCoord) {
+    if (geojson === null)
+      return;
+    var j2, k, l, 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 (k = 0; k < coords[j2].length - wrapShrink; k++) {
+                if (callback(
+                  coords[j2][k],
+                  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 (k = 0; k < coords[j2].length; k++) {
+                for (l = 0; l < coords[j2][k].length - wrapShrink; l++) {
+                  if (callback(
+                    coords[j2][k][l],
+                    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");
+        }
+      }
+    }
+  }
+
+  // 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];
+      }
+      if (result[1] > coord2[1]) {
+        result[1] = coord2[1];
+      }
+      if (result[2] < coord2[0]) {
+        result[2] = coord2[0];
+      }
+      if (result[3] < coord2[1]) {
+        result[3] = coord2[1];
+      }
+    });
+    return result;
+  }
+  bbox["default"] = bbox;
+  var es_default = bbox;
+
   // modules/renderer/background.js
-  var import_which_polygon4 = __toESM(require_which_polygon());
+  var import_which_polygon3 = __toESM(require_which_polygon());
 
   // modules/renderer/tile_layer.js
   function rendererTileLayer(context) {
@@ -44033,6 +46069,7 @@ ${content}</tr>
             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"));
@@ -44085,7 +46122,7 @@ ${content}</tr>
           imagery: sources,
           features: {}
         };
-        const features2 = sources.map((source) => {
+        const features = sources.map((source) => {
           if (!source.polygon)
             return null;
           const rings = source.polygon.map((ring) => [ring]);
@@ -44097,7 +46134,7 @@ ${content}</tr>
           _imageryIndex.features[source.id] = feature3;
           return feature3;
         }).filter(Boolean);
-        _imageryIndex.query = (0, import_which_polygon4.default)({ type: "FeatureCollection", features: features2 });
+        _imageryIndex.query = (0, import_which_polygon3.default)({ type: "FeatureCollection", features });
         _imageryIndex.backgrounds = sources.map((source) => {
           if (source.type === "bing") {
             return rendererBackgroundSource.Bing(source, dispatch10);
@@ -44390,7 +46427,17 @@ ${content}</tr>
         const isLastUsedValid = !!validBackgrounds.find((d) => d.id && d.id === lastUsedBackground);
         let best;
         if (!requestedBackground && extent) {
-          best = validBackgrounds.find((s) => s.best());
+          const viewArea = extent.area();
+          best = validBackgrounds.find((s) => {
+            if (!s.best() || s.overlay)
+              return false;
+            let bbox2 = es_default(bboxClip(
+              { type: "MultiPolygon", coordinates: [s.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:/, "");
@@ -44435,7 +46482,7 @@ ${content}</tr>
   // modules/renderer/features.js
   function rendererFeatures(context) {
     var dispatch10 = dispatch_default("change", "redraw");
-    var features2 = utilRebind({}, dispatch10, "on");
+    var features = utilRebind({}, dispatch10, "on");
     var _deferred2 = /* @__PURE__ */ new Set();
     var traffic_roads = {
       "motorway": true,
@@ -44450,7 +46497,8 @@ ${content}</tr>
       "tertiary_link": true,
       "residential": true,
       "unclassified": true,
-      "living_street": true
+      "living_street": true,
+      "busway": true
     };
     var service_roads = {
       "service": true,
@@ -44475,7 +46523,7 @@ ${content}</tr>
     function update() {
       if (!window.mocha) {
         var hash = utilStringQs(window.location.hash);
-        var disabled = features2.disabled();
+        var disabled = features.disabled();
         if (disabled.length) {
           hash.disable_features = disabled.join(",");
         } else {
@@ -44484,7 +46532,7 @@ ${content}</tr>
         window.location.replace("#" + utilQsString(hash, true));
         corePreferences("disabled-features", disabled.join(","));
       }
-      _hidden = features2.hidden();
+      _hidden = features.hidden();
       dispatch10.call("change");
       dispatch10.call("redraw");
     }
@@ -44494,6 +46542,7 @@ ${content}</tr>
       _rules[k] = {
         filter: filter2,
         enabled: isEnabled,
+        // whether the user wants it enabled..
         count: 0,
         currentMax: max3 || Infinity,
         defaultMax: max3 || Infinity,
@@ -44570,13 +46619,13 @@ ${content}</tr>
     defineRule("others", function isOther(tags, geometry) {
       return geometry === "line" || geometry === "area";
     });
-    features2.features = function() {
+    features.features = function() {
       return _rules;
     };
-    features2.keys = function() {
+    features.keys = function() {
       return _keys;
     };
-    features2.enabled = function(k) {
+    features.enabled = function(k) {
       if (!arguments.length) {
         return _keys.filter(function(k2) {
           return _rules[k2].enabled;
@@ -44584,7 +46633,7 @@ ${content}</tr>
       }
       return _rules[k] && _rules[k].enabled;
     };
-    features2.disabled = function(k) {
+    features.disabled = function(k) {
       if (!arguments.length) {
         return _keys.filter(function(k2) {
           return !_rules[k2].enabled;
@@ -44592,7 +46641,7 @@ ${content}</tr>
       }
       return _rules[k] && !_rules[k].enabled;
     };
-    features2.hidden = function(k) {
+    features.hidden = function(k) {
       if (!arguments.length) {
         return _keys.filter(function(k2) {
           return _rules[k2].hidden();
@@ -44600,7 +46649,7 @@ ${content}</tr>
       }
       return _rules[k] && _rules[k].hidden();
     };
-    features2.autoHidden = function(k) {
+    features.autoHidden = function(k) {
       if (!arguments.length) {
         return _keys.filter(function(k2) {
           return _rules[k2].autoHidden();
@@ -44608,13 +46657,13 @@ ${content}</tr>
       }
       return _rules[k] && _rules[k].autoHidden();
     };
-    features2.enable = function(k) {
+    features.enable = function(k) {
       if (_rules[k] && !_rules[k].enabled) {
         _rules[k].enable();
         update();
       }
     };
-    features2.enableAll = function() {
+    features.enableAll = function() {
       var didEnable = false;
       for (var k in _rules) {
         if (!_rules[k].enabled) {
@@ -44625,13 +46674,13 @@ ${content}</tr>
       if (didEnable)
         update();
     };
-    features2.disable = function(k) {
+    features.disable = function(k) {
       if (_rules[k] && _rules[k].enabled) {
         _rules[k].disable();
         update();
       }
     };
-    features2.disableAll = function() {
+    features.disableAll = function() {
       var didDisable = false;
       for (var k in _rules) {
         if (_rules[k].enabled) {
@@ -44642,7 +46691,7 @@ ${content}</tr>
       if (didDisable)
         update();
     };
-    features2.toggle = function(k) {
+    features.toggle = function(k) {
       if (_rules[k]) {
         (function(f2) {
           return f2.enabled ? f2.disable() : f2.enable();
@@ -44650,13 +46699,13 @@ ${content}</tr>
         update();
       }
     };
-    features2.resetStats = function() {
+    features.resetStats = function() {
       for (var i2 = 0; i2 < _keys.length; i2++) {
         _rules[_keys[i2]].count = 0;
       }
       dispatch10.call("change");
     };
-    features2.gatherStats = function(d, resolver, dimensions) {
+    features.gatherStats = function(d, resolver, dimensions) {
       var needsRedraw = false;
       var types = utilArrayGroupBy(d, "type");
       var entities = [].concat(types.relation || [], types.way || [], types.node || []);
@@ -44667,12 +46716,12 @@ ${content}</tr>
       _cullFactor = dimensions[0] * dimensions[1] / 1e6;
       for (i2 = 0; i2 < entities.length; i2++) {
         geometry = entities[i2].geometry(resolver);
-        matches = Object.keys(features2.getMatches(entities[i2], resolver, geometry));
+        matches = Object.keys(features.getMatches(entities[i2], resolver, geometry));
         for (j2 = 0; j2 < matches.length; j2++) {
           _rules[matches[j2]].count++;
         }
       }
-      currHidden = features2.hidden();
+      currHidden = features.hidden();
       if (currHidden !== _hidden) {
         _hidden = currHidden;
         needsRedraw = true;
@@ -44680,21 +46729,21 @@ ${content}</tr>
       }
       return needsRedraw;
     };
-    features2.stats = function() {
+    features.stats = function() {
       for (var i2 = 0; i2 < _keys.length; i2++) {
         _stats[_keys[i2]] = _rules[_keys[i2]].count;
       }
       return _stats;
     };
-    features2.clear = function(d) {
+    features.clear = function(d) {
       for (var i2 = 0; i2 < d.length; i2++) {
-        features2.clearEntity(d[i2]);
+        features.clearEntity(d[i2]);
       }
     };
-    features2.clearEntity = function(entity) {
+    features.clearEntity = function(entity) {
       delete _cache4[osmEntity.key(entity)];
     };
-    features2.reset = function() {
+    features.reset = function() {
       Array.from(_deferred2).forEach(function(handle) {
         window.cancelIdleCallback(handle);
         _deferred2.delete(handle);
@@ -44704,7 +46753,7 @@ ${content}</tr>
     function relationShouldBeChecked(relation) {
       return relation.tags.type === "boundary";
     }
-    features2.getMatches = function(entity, resolver, geometry) {
+    features.getMatches = function(entity, resolver, geometry) {
       if (geometry === "vertex" || geometry === "relation" && !relationShouldBeChecked(entity))
         return {};
       var ent = osmEntity.key(entity);
@@ -44719,8 +46768,9 @@ ${content}</tr>
             if (hasMatch)
               continue;
             if (entity.type === "way") {
-              var parents = features2.getParents(entity, resolver, geometry);
-              if (parents.length === 1 && parents[0].isMultipolygon() || parents.length > 0 && parents.every(function(parent) {
+              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]);
@@ -44739,7 +46789,7 @@ ${content}</tr>
       }
       return _cache4[ent].matches;
     };
-    features2.getParents = function(entity, resolver, geometry) {
+    features.getParents = function(entity, resolver, geometry) {
       if (geometry === "point")
         return [];
       var ent = osmEntity.key(entity);
@@ -44757,7 +46807,7 @@ ${content}</tr>
       }
       return _cache4[ent].parents;
     };
-    features2.isHiddenPreset = function(preset, geometry) {
+    features.isHiddenPreset = function(preset, geometry) {
       if (!_hidden.length)
         return false;
       if (!preset.tags)
@@ -44773,36 +46823,36 @@ ${content}</tr>
       }
       return false;
     };
-    features2.isHiddenFeature = function(entity, resolver, geometry) {
+    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(features2.getMatches(entity, resolver, geometry));
+      var matches = Object.keys(features.getMatches(entity, resolver, geometry));
       return matches.length && matches.every(function(k) {
-        return features2.hidden(k);
+        return features.hidden(k);
       });
     };
-    features2.isHiddenChild = function(entity, resolver, geometry) {
+    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 = features2.getParents(entity, resolver, geometry);
+      var parents = features.getParents(entity, resolver, geometry);
       if (!parents.length)
         return false;
       for (var i2 = 0; i2 < parents.length; i2++) {
-        if (!features2.isHidden(parents[i2], resolver, parents[i2].geometry(resolver))) {
+        if (!features.isHidden(parents[i2], resolver, parents[i2].geometry(resolver))) {
           return false;
         }
       }
       return true;
     };
-    features2.hasHiddenConnections = function(entity, resolver) {
+    features.hasHiddenConnections = function(entity, resolver) {
       if (!_hidden.length)
         return false;
       var childNodes, connections;
@@ -44811,36 +46861,36 @@ ${content}</tr>
         connections = [];
       } else {
         childNodes = entity.nodes ? resolver.childNodes(entity) : [];
-        connections = features2.getParents(entity, resolver, entity.geometry(resolver));
+        connections = features.getParents(entity, resolver, entity.geometry(resolver));
       }
       connections = childNodes.reduce(function(result, e) {
         return resolver.isShared(e) ? utilArrayUnion(result, resolver.parentWays(e)) : result;
       }, connections);
       return connections.some(function(e) {
-        return features2.isHidden(e, resolver, e.geometry(resolver));
+        return features.isHidden(e, resolver, e.geometry(resolver));
       });
     };
-    features2.isHidden = function(entity, resolver, geometry) {
+    features.isHidden = function(entity, resolver, geometry) {
       if (!_hidden.length)
         return false;
       if (!entity.version)
         return false;
-      var fn = geometry === "vertex" ? features2.isHiddenChild : features2.isHiddenFeature;
+      var fn = geometry === "vertex" ? features.isHiddenChild : features.isHiddenFeature;
       return fn(entity, resolver, geometry);
     };
-    features2.filter = function(d, resolver) {
+    features.filter = function(d, resolver) {
       if (!_hidden.length)
         return d;
       var result = [];
       for (var i2 = 0; i2 < d.length; i2++) {
         var entity = d[i2];
-        if (!features2.isHidden(entity, resolver, entity.geometry(resolver))) {
+        if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
           result.push(entity);
         }
       }
       return result;
     };
-    features2.forceVisible = function(entityIDs) {
+    features.forceVisible = function(entityIDs) {
       if (!arguments.length)
         return Object.keys(_forceVisible);
       _forceVisible = {};
@@ -44853,18 +46903,18 @@ ${content}</tr>
           }
         }
       }
-      return features2;
+      return features;
     };
-    features2.init = function() {
+    features.init = function() {
       var storage = corePreferences("disabled-features");
       if (storage) {
         var storageDisabled = storage.replace(/;/g, ",").split(",");
-        storageDisabled.forEach(features2.disable);
+        storageDisabled.forEach(features.disable);
       }
       var hash = utilStringQs(window.location.hash);
       if (hash.disable_features) {
         var hashDisabled = hash.disable_features.replace(/;/g, ",").split(",");
-        hashDisabled.forEach(features2.disable);
+        hashDisabled.forEach(features.disable);
       }
     };
     context.history().on("merge.features", function(newEntities) {
@@ -44876,12 +46926,12 @@ ${content}</tr>
         var entities = [].concat(types.relation || [], types.way || [], types.node || []);
         for (var i2 = 0; i2 < entities.length; i2++) {
           var geometry = entities[i2].geometry(graph);
-          features2.getMatches(entities[i2], graph, geometry);
+          features.getMatches(entities[i2], graph, geometry);
         }
       });
       _deferred2.add(handle);
     });
-    return features2;
+    return features;
   }
 
   // modules/svg/areas.js
@@ -45040,8 +47090,8 @@ ${content}</tr>
       var tags = entity.tags;
       var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
       graph.parentRelations(entity).forEach(function(relation) {
-        var type3 = relation.tags.type;
-        if (type3 === "multipolygon" && shouldCopyMultipolygonTags || type3 === "boundary") {
+        var type2 = relation.tags.type;
+        if (type2 === "multipolygon" && shouldCopyMultipolygonTags || type2 === "boundary") {
           tags = Object.assign({}, relation.tags, tags);
         }
       });
@@ -45056,14 +47106,14 @@ ${content}</tr>
     }
     function getWaySegments() {
       var isActiveWay = way.nodes.indexOf(activeID) !== -1;
-      var features2 = { passive: [], active: [] };
+      var features = { passive: [], active: [] };
       var start2 = {};
       var end = {};
-      var node, type3;
+      var node, type2;
       for (var i2 = 0; i2 < way.nodes.length; i2++) {
         node = graph.entity(way.nodes[i2]);
-        type3 = svgPassiveVertex(node, graph, activeID);
-        end = { node, type: type3 };
+        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)) {
@@ -45076,9 +47126,9 @@ ${content}</tr>
         }
         start2 = end;
       }
-      return features2;
+      return features;
       function pushActive(start3, end2, index) {
-        features2.active.push({
+        features.active.push({
           type: "Feature",
           id: way.id + "-" + index + "-nope",
           properties: {
@@ -45095,7 +47145,7 @@ ${content}</tr>
         });
       }
       function pushPassive(start3, end2, index) {
-        features2.passive.push({
+        features.passive.push({
           type: "Feature",
           id: way.id + "-" + index,
           properties: {
@@ -45272,7 +47322,7 @@ ${content}</tr>
       if (qid) {
         classes.push("tag-wikidata");
       }
-      return classes.join(" ").trim();
+      return classes.filter((klass) => /^[-_a-z0-9]+$/.test(klass)).join(" ").trim();
     };
     tagClasses.tags = function(val) {
       if (!arguments.length)
@@ -45285,6 +47335,12 @@ ${content}</tr>
 
   // modules/svg/tag_pattern.js
   var patterns = {
+    // tag - pattern name
+    // -or-
+    // tag - value - pattern name
+    // -or-
+    // tag - value - rules (optional tag-values, pattern name)
+    // (matches earlier rules first, so fallback should be last entry)
     amenity: {
       grave_yard: "cemetery",
       fountain: "water_standing"
@@ -45305,6 +47361,7 @@ ${content}</tr>
         { leaf_type: "needleleaved", pattern: "forest_needleleaved" },
         { leaf_type: "leafless", pattern: "forest_leafless" },
         { pattern: "forest" }
+        // same as 'leaf_type:mixed'
       ],
       grave_yard: "cemetery",
       grass: "grass",
@@ -45340,6 +47397,7 @@ ${content}</tr>
         { leaf_type: "needleleaved", pattern: "forest_needleleaved" },
         { leaf_type: "leafless", pattern: "forest_leafless" },
         { pattern: "forest" }
+        // same as 'leaf_type:mixed'
       ]
     },
     golf: {
@@ -45411,9 +47469,9 @@ ${content}</tr>
       var base = context.history().base();
       var data = { targets: [], nopes: [] };
       entities.forEach(function(way) {
-        var features2 = svgSegmentWay(way, graph, activeID);
-        data.targets.push.apply(data.targets, features2.passive);
-        data.nopes.push.apply(data.nopes, features2.active);
+        var features = svgSegmentWay(way, graph, activeID);
+        data.targets.push.apply(data.targets, features.passive);
+        data.nopes.push.apply(data.nopes, features.active);
       });
       var targetData = data.targets.filter(getPath);
       var targets = selection2.selectAll(".area.target-allowed").filter(function(d) {
@@ -45583,7 +47641,7 @@ ${content}</tr>
     const val = parseFloat(nodeVal(get1(node, tagName)));
     if (isNaN(val))
       return void 0;
-    if (val && callback)
+    if (callback)
       callback(val);
     return val;
   }
@@ -45794,9 +47852,9 @@ ${content}</tr>
         yield feature3;
     }
     for (const waypoint of $(node, "wpt")) {
-      const point = getPoint(waypoint);
-      if (point)
-        yield point;
+      const point2 = getPoint(waypoint);
+      if (point2)
+        yield point2;
     }
   }
   function gpx(node) {
@@ -45829,6 +47887,14 @@ ${content}</tr>
   function getColor(node, output) {
     return get3(node, "color", (elem) => fixColor(nodeVal(elem), output));
   }
+  function extractIconHref(node) {
+    return get3(node, "Icon", (icon2, properties) => {
+      val1(icon2, "href", (href) => {
+        properties.icon = href;
+      });
+      return properties;
+    });
+  }
   function extractIcon(node) {
     return get3(node, "IconStyle", (iconStyle) => {
       return Object.assign(getColor(iconStyle, "icon"), numericProperty(iconStyle, "scale", "icon-scale"), numericProperty(iconStyle, "heading", "icon-heading"), get3(iconStyle, "hotSpot", (hotspot) => {
@@ -45842,12 +47908,7 @@ ${content}</tr>
             "icon-offset-units": [xunits, yunits]
           };
         return {};
-      }), get3(iconStyle, "Icon", (icon2, properties) => {
-        val1(icon2, "href", (href) => {
-          properties.icon = href;
-        });
-        return properties;
-      }));
+      }), extractIconHref(iconStyle));
     });
   }
   function extractLabel(node) {
@@ -45874,6 +47935,68 @@ ${content}</tr>
   function extractStyle(node) {
     return Object.assign({}, extractPoly(node), extractLine(node), extractLabel(node), extractIcon(node));
   }
+  var toNumber2 = (x) => Number(x);
+  var typeConverters = {
+    string: (x) => x,
+    int: toNumber2,
+    uint: toNumber2,
+    short: toNumber2,
+    ushort: toNumber2,
+    float: toNumber2,
+    double: toNumber2,
+    bool: (x) => Boolean(x)
+  };
+  function extractExtendedData(node, schema) {
+    return get3(node, "ExtendedData", (extendedData, properties) => {
+      for (const data of $(extendedData, "Data")) {
+        properties[data.getAttribute("name") || ""] = nodeVal(get1(data, "value"));
+      }
+      for (const simpleData of $(extendedData, "SimpleData")) {
+        const name = simpleData.getAttribute("name") || "";
+        const typeConverter = schema[name] || typeConverters.string;
+        properties[name] = typeConverter(nodeVal(simpleData));
+      }
+      return properties;
+    });
+  }
+  function getMaybeHTMLDescription(node) {
+    const descriptionNode = get1(node, "description");
+    for (const c of Array.from(descriptionNode?.childNodes || [])) {
+      if (c.nodeType === 4) {
+        return {
+          description: {
+            "@type": "html",
+            value: nodeVal(c)
+          }
+        };
+      }
+    }
+    return {};
+  }
+  function extractTimeSpan(node) {
+    return get3(node, "TimeSpan", (timeSpan) => {
+      return {
+        timespan: {
+          begin: nodeVal(get1(timeSpan, "begin")),
+          end: nodeVal(get1(timeSpan, "end"))
+        }
+      };
+    });
+  }
+  function extractTimeStamp(node) {
+    return get3(node, "TimeStamp", (timeStamp) => {
+      return { timestamp: nodeVal(get1(timeStamp, "when")) };
+    });
+  }
+  function extractCascadedStyle(node, styleMap) {
+    return val1(node, "styleUrl", (styleUrl) => {
+      styleUrl = normalizeId(styleUrl);
+      if (styleMap[styleUrl]) {
+        return Object.assign({ styleUrl }, styleMap[styleUrl]);
+      }
+      return { styleUrl };
+    });
+  }
   var removeSpace = /\s*/g;
   var trimSpace = /^\s*|\s*$/g;
   var splitSpace = /\s+/;
@@ -45924,30 +48047,26 @@ ${content}</tr>
     }
     return ring;
   }
-  var GEO_TYPES = [
-    "Polygon",
-    "LineString",
-    "Point",
-    "Track",
-    "gx:Track"
-  ];
   function getCoordinates(node) {
     return nodeVal(get1(node, "coordinates"));
   }
   function getGeometry(node) {
-    const geometries = [];
-    const coordTimes = [];
-    for (const t of ["MultiGeometry", "MultiTrack", "gx:MultiTrack"]) {
-      const elem = get1(node, t);
-      if (elem) {
-        return getGeometry(elem);
-      }
-    }
-    for (const geoType of GEO_TYPES) {
-      for (const geomNode of $(node, geoType)) {
-        switch (geoType) {
+    let geometries = [];
+    let coordTimes = [];
+    for (let i2 = 0; i2 < node.childNodes.length; i2++) {
+      const child = node.childNodes.item(i2);
+      if (isElement(child)) {
+        switch (child.tagName) {
+          case "MultiGeometry":
+          case "MultiTrack":
+          case "gx:MultiTrack": {
+            const childGeometries = getGeometry(child);
+            geometries = geometries.concat(childGeometries.geometries);
+            coordTimes = coordTimes.concat(childGeometries.coordTimes);
+            break;
+          }
           case "Point": {
-            const coordinates = coord1(getCoordinates(geomNode));
+            const coordinates = coord1(getCoordinates(child));
             if (coordinates.length >= 2) {
               geometries.push({
                 type: "Point",
@@ -45956,8 +48075,9 @@ ${content}</tr>
             }
             break;
           }
+          case "LinearRing":
           case "LineString": {
-            const coordinates = coord(getCoordinates(geomNode));
+            const coordinates = coord(getCoordinates(child));
             if (coordinates.length >= 2) {
               geometries.push({
                 type: "LineString",
@@ -45968,7 +48088,7 @@ ${content}</tr>
           }
           case "Polygon": {
             const coords = [];
-            for (const linearRing of $(geomNode, "LinearRing")) {
+            for (const linearRing of $(child, "LinearRing")) {
               const ring = fixRing(coord(getCoordinates(linearRing)));
               if (ring.length >= 4) {
                 coords.push(ring);
@@ -45984,7 +48104,7 @@ ${content}</tr>
           }
           case "Track":
           case "gx:Track": {
-            const gx = gxCoords(geomNode);
+            const gx = gxCoords(child);
             if (!gx)
               break;
             const { times, geometry } = gx;
@@ -46001,62 +48121,13 @@ ${content}</tr>
       coordTimes
     };
   }
-  function extractExtendedData(node) {
-    return get3(node, "ExtendedData", (extendedData, properties) => {
-      for (const data of $(extendedData, "Data")) {
-        properties[data.getAttribute("name") || ""] = nodeVal(get1(data, "value"));
-      }
-      for (const simpleData of $(extendedData, "SimpleData")) {
-        properties[simpleData.getAttribute("name") || ""] = nodeVal(simpleData);
-      }
-      return properties;
-    });
-  }
   function geometryListToGeometry(geometries) {
     return geometries.length === 0 ? null : geometries.length === 1 ? geometries[0] : {
       type: "GeometryCollection",
       geometries
     };
   }
-  function extractTimeSpan(node) {
-    return get3(node, "TimeSpan", (timeSpan) => {
-      return {
-        timespan: {
-          begin: nodeVal(get1(timeSpan, "begin")),
-          end: nodeVal(get1(timeSpan, "end"))
-        }
-      };
-    });
-  }
-  function extractTimeStamp(node) {
-    return get3(node, "TimeStamp", (timeStamp) => {
-      return { timestamp: nodeVal(get1(timeStamp, "when")) };
-    });
-  }
-  function extractCascadedStyle(node, styleMap) {
-    return val1(node, "styleUrl", (styleUrl) => {
-      styleUrl = normalizeId(styleUrl);
-      if (styleMap[styleUrl]) {
-        return Object.assign({ styleUrl }, styleMap[styleUrl]);
-      }
-      return { styleUrl };
-    });
-  }
-  function getMaybeHTMLDescription(node) {
-    const descriptionNode = get1(node, "description");
-    for (const c of Array.from(descriptionNode?.childNodes || [])) {
-      if (c.nodeType === 4) {
-        return {
-          description: {
-            "@type": "html",
-            value: nodeVal(c)
-          }
-        };
-      }
-    }
-    return {};
-  }
-  function getPlacemark(node, styleMap) {
+  function getPlacemark(node, styleMap, schema) {
     const { coordTimes, geometries } = getGeometry(node);
     const feature3 = {
       type: "Feature",
@@ -46068,7 +48139,7 @@ ${content}</tr>
         "open",
         "phoneNumber",
         "description"
-      ]), getMaybeHTMLDescription(node), extractCascadedStyle(node, styleMap), extractStyle(node), extractExtendedData(node), extractTimeSpan(node), extractTimeStamp(node), coordTimes.length ? {
+      ]), getMaybeHTMLDescription(node), extractCascadedStyle(node, styleMap), extractStyle(node), extractExtendedData(node, schema), extractTimeSpan(node), extractTimeStamp(node), coordTimes.length ? {
         coordinateProperties: {
           times: coordTimes.length === 1 ? coordTimes[0] : coordTimes
         }
@@ -46082,6 +48153,100 @@ ${content}</tr>
       feature3.id = id2;
     return feature3;
   }
+  function getGroundOverlayBox(node) {
+    const latLonQuad = get1(node, "gx:LatLonQuad");
+    if (latLonQuad) {
+      const ring = fixRing(coord(getCoordinates(node)));
+      return {
+        type: "Polygon",
+        coordinates: [ring]
+      };
+    }
+    return getLatLonBox(node);
+  }
+  var DEGREES_TO_RADIANS = Math.PI / 180;
+  function rotateBox(bbox2, coordinates, rotation) {
+    const center = [(bbox2[0] + bbox2[2]) / 2, (bbox2[1] + bbox2[3]) / 2];
+    return [
+      coordinates[0].map((coordinate) => {
+        const dy = coordinate[1] - center[1];
+        const dx = coordinate[0] - center[0];
+        const distance = Math.sqrt(Math.pow(dy, 2) + Math.pow(dx, 2));
+        const angle2 = Math.atan2(dy, dx) - rotation * DEGREES_TO_RADIANS;
+        return [
+          center[0] + Math.cos(angle2) * distance,
+          center[1] + Math.sin(angle2) * distance
+        ];
+      })
+    ];
+  }
+  function getLatLonBox(node) {
+    const latLonBox = get1(node, "LatLonBox");
+    if (latLonBox) {
+      const north = num1(latLonBox, "north");
+      const west = num1(latLonBox, "west");
+      const east = num1(latLonBox, "east");
+      const south = num1(latLonBox, "south");
+      const rotation = num1(latLonBox, "rotation");
+      if (typeof north === "number" && typeof south === "number" && typeof west === "number" && typeof east === "number") {
+        const bbox2 = [west, south, east, north];
+        let coordinates = [
+          [
+            [west, north],
+            [east, north],
+            [east, south],
+            [west, south],
+            [west, north]
+            // top left (again)
+          ]
+        ];
+        if (typeof rotation === "number") {
+          coordinates = rotateBox(bbox2, coordinates, rotation);
+        }
+        return {
+          type: "Polygon",
+          coordinates
+        };
+      }
+    }
+    return null;
+  }
+  function getGroundOverlay(node, styleMap, schema) {
+    const geometry = getGroundOverlayBox(node);
+    const feature3 = {
+      type: "Feature",
+      geometry,
+      properties: Object.assign(
+        /**
+         * Related to
+         * https://gist.github.com/tmcw/037a1cb6660d74a392e9da7446540f46
+         */
+        { "@geometry-type": "groundoverlay" },
+        getMulti(node, [
+          "name",
+          "address",
+          "visibility",
+          "open",
+          "phoneNumber",
+          "description"
+        ]),
+        getMaybeHTMLDescription(node),
+        extractCascadedStyle(node, styleMap),
+        extractStyle(node),
+        extractIconHref(node),
+        extractExtendedData(node, schema),
+        extractTimeSpan(node),
+        extractTimeStamp(node)
+      )
+    };
+    if (feature3.properties?.visibility !== void 0) {
+      feature3.properties.visibility = feature3.properties.visibility !== "0";
+    }
+    const id2 = node.getAttribute("id");
+    if (id2 !== null && id2 !== "")
+      feature3.id = id2;
+    return feature3;
+  }
   function getStyleId(style) {
     let id2 = style.getAttribute("id");
     const parentNode = style.parentNode;
@@ -46106,10 +48271,23 @@ ${content}</tr>
     }
     return styleMap;
   }
+  function buildSchema(node) {
+    const schema = {};
+    for (const field of $(node, "SimpleField")) {
+      schema[field.getAttribute("name") || ""] = typeConverters[field.getAttribute("type") || ""] || typeConverters["string"];
+    }
+    return schema;
+  }
   function* kmlGen(node) {
     const styleMap = buildStyleMap(node);
+    const schema = buildSchema(node);
     for (const placemark of $(node, "Placemark")) {
-      const feature3 = getPlacemark(placemark, styleMap);
+      const feature3 = getPlacemark(placemark, styleMap, schema);
+      if (feature3)
+        yield feature3;
+    }
+    for (const groundOverlay of $(node, "GroundOverlay")) {
+      const feature3 = getGroundOverlay(groundOverlay, styleMap, schema);
       if (feature3)
         yield feature3;
     }
@@ -46457,12 +48635,12 @@ ${content}</tr>
       return _src || "";
     };
     drawData.fitZoom = function() {
-      var features2 = getFeatures(_geojson);
-      if (!features2.length)
+      var features = getFeatures(_geojson);
+      if (!features.length)
         return;
       var map2 = context.map();
       var viewport = map2.trimmedExtent().polygon();
-      var coords = features2.reduce(function(coords2, feature3) {
+      var coords = features.reduce(function(coords2, feature3) {
         var geom = feature3.geometry;
         if (!geom)
           return coords2;
@@ -46528,8 +48706,8 @@ ${content}</tr>
       const extent = context.map().extent();
       _mainFileFetcher.get("imagery").then((d) => {
         const hits = showImagery && d.query.bbox(extent.rectangle(), true) || [];
-        const features2 = hits.map((d2) => d2.features[d2.id]);
-        let imagery = layer.selectAll("path.debug-imagery").data(features2);
+        const features = hits.map((d2) => d2.features[d2.id]);
+        let imagery = layer.selectAll("path.debug-imagery").data(features);
         imagery.exit().remove();
         imagery.enter().append("path").attr("class", "debug-imagery debug orange");
       }).catch(() => {
@@ -46538,18 +48716,18 @@ ${content}</tr>
       let dataDownloaded = [];
       if (osm && showDownloaded) {
         const rtree = osm.caches("get").tile.rtree;
-        dataDownloaded = rtree.all().map((bbox) => {
+        dataDownloaded = rtree.all().map((bbox2) => {
           return {
             type: "Feature",
-            properties: { id: bbox.id },
+            properties: { id: bbox2.id },
             geometry: {
               type: "Polygon",
               coordinates: [[
-                [bbox.minX, bbox.minY],
-                [bbox.minX, bbox.maxY],
-                [bbox.maxX, bbox.maxY],
-                [bbox.maxX, bbox.minY],
-                [bbox.minX, bbox.minY]
+                [bbox2.minX, bbox2.minY],
+                [bbox2.minX, bbox2.maxY],
+                [bbox2.maxX, bbox2.maxY],
+                [bbox2.maxX, bbox2.minY],
+                [bbox2.minX, bbox2.minY]
               ]]
             }
           };
@@ -46578,6 +48756,7 @@ ${content}</tr>
       "maki-sprite",
       "temaki-sprite",
       "fa-sprite",
+      "roentgen-sprite",
       "community-sprite"
     ];
     function drawDefs(selection2) {
@@ -46594,6 +48773,7 @@ ${content}</tr>
       _defsSelection.append("marker").attr("id", "ideditor-viewfield-marker").attr("viewBox", "0 0 16 16").attr("refX", 8).attr("refY", 16).attr("markerWidth", 4).attr("markerHeight", 4).attr("markerUnits", "strokeWidth").attr("orient", "auto").append("path").attr("class", "viewfield-marker-path").attr("d", "M 6,14 C 8,13.4 8,13.4 10,14 L 16,3 C 12,0 4,0 0,3 z").attr("fill", "#333").attr("fill-opacity", "0.75").attr("stroke", "#fff").attr("stroke-width", "0.5px").attr("stroke-opacity", "0.75");
       _defsSelection.append("marker").attr("id", "ideditor-viewfield-marker-wireframe").attr("viewBox", "0 0 16 16").attr("refX", 8).attr("refY", 16).attr("markerWidth", 4).attr("markerHeight", 4).attr("markerUnits", "strokeWidth").attr("orient", "auto").append("path").attr("class", "viewfield-marker-path").attr("d", "M 6,14 C 8,13.4 8,13.4 10,14 L 16,3 C 12,0 4,0 0,3 z").attr("fill", "none").attr("stroke", "#fff").attr("stroke-width", "0.5px").attr("stroke-opacity", "0.75");
       var patterns2 = _defsSelection.selectAll("pattern").data([
+        // pattern name, pattern image name
         ["beach", "dots"],
         ["construction", "construction"],
         ["cemetery", "cemetery"],
@@ -46845,13 +49025,13 @@ ${content}</tr>
   }
 
   // modules/svg/labels.js
-  var import_rbush7 = __toESM(require_rbush_min());
+  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_rbush7.default();
-    var _rskipped = new import_rbush7.default();
+    var _rdrawn = new import_rbush6.default();
+    var _rskipped = new import_rbush6.default();
     var _textWidthCache = {};
     var _entitybboxes = {};
     var labelStack = [
@@ -47019,13 +49199,13 @@ ${content}</tr>
           }
           var coord2 = projection2(entity.loc);
           var nodePadding = 10;
-          var bbox = {
+          var bbox2 = {
             minX: coord2[0] - nodePadding,
             minY: coord2[1] - nodePadding - markerPadding,
             maxX: coord2[0] + nodePadding,
             maxY: coord2[1] + nodePadding
           };
-          doInsert(bbox, entity.id + "P");
+          doInsert(bbox2, entity.id + "P");
         }
         if (geometry === "vertex") {
           geometry = "point";
@@ -47109,23 +49289,23 @@ ${content}</tr>
           y: coord3[1] + offset[1],
           textAnchor: offset[2]
         };
-        var bbox2;
+        var bbox3;
         if (textDirection === "rtl") {
-          bbox2 = {
+          bbox3 = {
             minX: p2.x - width2 - textPadding,
             minY: p2.y - height / 2 - textPadding,
             maxX: p2.x + textPadding,
             maxY: p2.y + height / 2 + textPadding
           };
         } else {
-          bbox2 = {
+          bbox3 = {
             minX: p2.x - textPadding,
             minY: p2.y - height / 2 - textPadding,
             maxX: p2.x + width2 + textPadding,
             maxY: p2.y + height / 2 + textPadding
           };
         }
-        if (tryInsert([bbox2], entity2.id, true)) {
+        if (tryInsert([bbox3], entity2.id, true)) {
           return p2;
         }
       }
@@ -47264,13 +49444,13 @@ ${content}</tr>
         function addIcon() {
           var iconX = centroid[0] - iconSize / 2;
           var iconY = centroid[1] - iconSize / 2;
-          var bbox2 = {
+          var bbox3 = {
             minX: iconX,
             minY: iconY,
             maxX: iconX + iconSize,
             maxY: iconY + iconSize
           };
-          if (tryInsert([bbox2], entity2.id + "I", true)) {
+          if (tryInsert([bbox3], entity2.id + "I", true)) {
             p2.transform = "translate(" + iconX + "," + iconY + ")";
             return true;
           }
@@ -47280,13 +49460,13 @@ ${content}</tr>
           if (width2 && areaWidth >= width2 + 20) {
             var labelX = centroid[0];
             var labelY = centroid[1] + yOffset;
-            var bbox2 = {
+            var bbox3 = {
               minX: labelX - width2 / 2 - padding,
               minY: labelY - height / 2 - padding,
               maxX: labelX + width2 / 2 + padding,
               maxY: labelY + height / 2 + padding
             };
-            if (tryInsert([bbox2], entity2.id, true)) {
+            if (tryInsert([bbox3], entity2.id, true)) {
               p2.x = labelX;
               p2.y = labelY;
               p2.textAnchor = "middle";
@@ -47297,25 +49477,25 @@ ${content}</tr>
           return false;
         }
       }
-      function doInsert(bbox2, id2) {
-        bbox2.id = id2;
+      function doInsert(bbox3, id2) {
+        bbox3.id = id2;
         var oldbox = _entitybboxes[id2];
         if (oldbox) {
           _rdrawn.remove(oldbox);
         }
-        _entitybboxes[id2] = bbox2;
-        _rdrawn.insert(bbox2);
+        _entitybboxes[id2] = bbox3;
+        _rdrawn.insert(bbox3);
       }
       function tryInsert(bboxes, id2, saveSkipped) {
         var skipped = false;
         for (var i3 = 0; i3 < bboxes.length; i3++) {
-          var bbox2 = bboxes[i3];
-          bbox2.id = id2;
-          if (bbox2.minX < 0 || bbox2.minY < 0 || bbox2.maxX > dimensions[0] || bbox2.maxY > dimensions[1]) {
+          var bbox3 = bboxes[i3];
+          bbox3.id = id2;
+          if (bbox3.minX < 0 || bbox3.minY < 0 || bbox3.maxX > dimensions[0] || bbox3.maxY > dimensions[1]) {
             skipped = true;
             break;
           }
-          if (_rdrawn.collides(bbox2)) {
+          if (_rdrawn.collides(bbox3)) {
             skipped = true;
             break;
           }
@@ -47358,11 +49538,11 @@ ${content}</tr>
       var graph = context.graph();
       var selectedIDs = context.selectedIDs();
       var ids = [];
-      var pad2, bbox;
+      var pad2, bbox2;
       if (mouse) {
         pad2 = 20;
-        bbox = { minX: mouse[0] - pad2, minY: mouse[1] - pad2, maxX: mouse[0] + pad2, maxY: mouse[1] + pad2 };
-        var nearMouse = _rdrawn.search(bbox).map(function(entity2) {
+        bbox2 = { minX: mouse[0] - pad2, minY: mouse[1] - pad2, maxX: mouse[0] + pad2, maxY: mouse[1] + pad2 };
+        var nearMouse = _rdrawn.search(bbox2).map(function(entity2) {
           return entity2.id;
         });
         ids.push.apply(ids, nearMouse);
@@ -47377,14 +49557,14 @@ ${content}</tr>
       var debug2 = selection2.selectAll(".labels-group.debug");
       var gj = [];
       if (context.getDebug("collision")) {
-        gj = bbox ? [{
+        gj = bbox2 ? [{
           type: "Polygon",
           coordinates: [[
-            [bbox.minX, bbox.minY],
-            [bbox.maxX, bbox.minY],
-            [bbox.maxX, bbox.maxY],
-            [bbox.minX, bbox.maxY],
-            [bbox.minX, bbox.minY]
+            [bbox2.minX, bbox2.minY],
+            [bbox2.maxX, bbox2.minY],
+            [bbox2.maxX, bbox2.maxY],
+            [bbox2.minX, bbox2.maxY],
+            [bbox2.minX, bbox2.minY]
           ]]
         }] : [];
       }
@@ -48927,9 +51107,9 @@ ${content}</tr>
       var base = context.history().base();
       var data = { targets: [], nopes: [] };
       entities.forEach(function(way) {
-        var features2 = svgSegmentWay(way, graph, activeID);
-        data.targets.push.apply(data.targets, features2.passive);
-        data.nopes.push.apply(data.nopes, features2.active);
+        var features = svgSegmentWay(way, graph, activeID);
+        data.targets.push.apply(data.targets, features.passive);
+        data.nopes.push.apply(data.nopes, features.active);
       });
       var targetData = data.targets.filter(getPath);
       var targets = selection2.selectAll(".line.target-allowed").filter(function(d) {
@@ -48988,7 +51168,8 @@ ${content}</tr>
             var parentMultipolygons = parentRelations.filter(function(relation) {
               return relation.isMultipolygon();
             });
-            if (parentMultipolygons.length > 0 && parentRelations.length === parentMultipolygons.length) {
+            if (parentMultipolygons.length > 0 && // and only multipolygon relations
+            parentRelations.length === parentMultipolygons.length) {
               prefix = "relation area";
             }
           }
@@ -49181,15 +51362,15 @@ ${content}</tr>
           if (midpoints[id2]) {
             midpoints[id2].parents.push(entity);
           } else if (geoVecLength(projection2(a.loc), projection2(b.loc)) > 40) {
-            var point = geoVecInterp(a.loc, b.loc, 0.5);
+            var point2 = geoVecInterp(a.loc, b.loc, 0.5);
             var loc = null;
-            if (extent.intersects(point)) {
-              loc = point;
+            if (extent.intersects(point2)) {
+              loc = point2;
             } else {
               for (var k = 0; k < 4; k++) {
-                point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
-                if (point && geoVecLength(projection2(a.loc), projection2(point)) > 20 && geoVecLength(projection2(b.loc), projection2(point)) > 20) {
-                  loc = point;
+                point2 = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
+                if (point2 && geoVecLength(projection2(a.loc), projection2(point2)) > 20 && geoVecLength(projection2(b.loc), projection2(point2)) > 20) {
+                  loc = point2;
                   break;
                 }
               }
@@ -49401,6 +51582,7 @@ ${content}</tr>
   var import_fast_deep_equal8 = __toESM(require_fast_deep_equal());
   function svgVertices(projection2, context) {
     var radiuses = {
+      //       z16-, z17,   z18+,  w/icon
       shadow: [6, 7.5, 7.5, 12],
       stroke: [2.5, 3.5, 3.5, 8],
       fill: [1, 1.5, 1.5, 1.5]
@@ -49645,8 +51827,11 @@ ${content}</tr>
       }
       var sets2 = {
         persistent: _currPersistent,
+        // persistent = important vertices (render always)
         selected: _currSelected,
+        // selected + siblings of selected (render always)
         hovered: _currHover
+        // hovered + siblings of hovered (render only in draw modes)
       };
       var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent);
       var filterRendered = function(d) {
@@ -49709,8 +51894,8 @@ ${content}</tr>
   }
 
   // modules/util/bind_once.js
-  function utilBindOnce(target, type3, listener, capture) {
-    var typeOnce = type3 + ".once";
+  function utilBindOnce(target, type2, listener, capture) {
+    var typeOnce = type2 + ".once";
     function one2() {
       target.on(typeOnce, null);
       listener.apply(this, arguments);
@@ -49751,10 +51936,10 @@ ${content}</tr>
       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, point) {
+    zoom.transform = function(collection, transform2, point2) {
       var selection2 = collection.selection ? collection.selection() : collection;
       if (collection !== selection2) {
-        schedule(collection, transform2, point);
+        schedule(collection, transform2, point2);
       } else {
         selection2.interrupt().each(function() {
           gesture(this, arguments).start(null).zoom(null, null, typeof transform2 === "function" ? transform2.apply(this, arguments) : transform2).end(null);
@@ -49801,13 +51986,13 @@ ${content}</tr>
     function centroid(extent2) {
       return [(+extent2[0][0] + +extent2[1][0]) / 2, (+extent2[0][1] + +extent2[1][1]) / 2];
     }
-    function schedule(transition2, transform2, point) {
+    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, g = gesture(that, args), e = extent.apply(that, args), p = !point ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point, w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a = _transform, b = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i2 = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
+        var that = this, args = arguments, g = gesture(that, args), e = extent.apply(that, args), p = !point2 ? centroid(e) : typeof point2 === "function" ? point2.apply(that, args) : point2, w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a = _transform, b = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i2 = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
         return function(t) {
           if (t === 1) {
             t = b;
@@ -49996,7 +52181,8 @@ ${content}</tr>
     var _maxDistance = 20;
     var _pointer;
     function pointerIsValidFor(loc) {
-      return new Date().getTime() - _pointer.startTime <= _maxTimespan && geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
+      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 pointerdown(d3_event) {
       if (d3_event.ctrlKey || d3_event.button === 2)
@@ -50008,7 +52194,7 @@ ${content}</tr>
       if (!_pointer) {
         _pointer = {
           startLoc: loc,
-          startTime: new Date().getTime(),
+          startTime: (/* @__PURE__ */ new Date()).getTime(),
           upCount: 0,
           pointerId: d3_event.pointerId
         };
@@ -50161,7 +52347,9 @@ ${content}</tr>
         }
       });
       var detected = utilDetect();
-      if ("GestureEvent" in window && !detected.isMobileWebKit) {
+      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();
@@ -50171,7 +52359,8 @@ ${content}</tr>
       _doubleUpHandler.on("doubleUp.map", function(d3_event, p02) {
         if (!_dblClickZoomEnabled)
           return;
-        if (typeof d3_event.target.__data__ === "object" && !select_default2(d3_event.target).classed("fill"))
+        if (typeof d3_event.target.__data__ === "object" && // or area fills
+        !select_default2(d3_event.target).classed("fill"))
           return;
         var zoomOut2 = d3_event.shiftKey;
         var t = projection2.transform();
@@ -50182,7 +52371,10 @@ ${content}</tr>
         map2.transformEase(t);
       });
       context.on("enter.map", function() {
-        if (!map2.editableDataEnabled(true))
+        if (!map2.editableDataEnabled(
+          true
+          /* skip zoom check */
+        ))
           return;
         if (_isTransformed)
           return;
@@ -50241,7 +52433,7 @@ ${content}</tr>
     function drawEditable(difference, extent) {
       var mode = context.mode();
       var graph = context.graph();
-      var features2 = context.features();
+      var features = context.features();
       var all = context.history().intersects(map2.extent());
       var fullRedraw = false;
       var data;
@@ -50265,9 +52457,9 @@ ${content}</tr>
         filter2 = function(d) {
           return set3.has(d.id);
         };
-        features2.clear(data);
+        features.clear(data);
       } else {
-        if (features2.gatherStats(all, graph, _dimensions)) {
+        if (features.gatherStats(all, graph, _dimensions)) {
           extent = void 0;
         }
         if (extent) {
@@ -50285,7 +52477,7 @@ ${content}</tr>
         }
       }
       if (applyFeatureLayerFilters) {
-        data = features2.filter(data, graph);
+        data = features.filter(data, graph);
       } else {
         context.features().resetStats();
       }
@@ -50326,7 +52518,9 @@ ${content}</tr>
       e.preventDefault();
       var props = {
         deltaMode: 0,
+        // dummy values to ignore in zoomPan
         deltaY: 1,
+        // dummy values to ignore in zoomPan
         clientX: e.clientX,
         clientY: e.clientY,
         screenX: e.screenX,
@@ -50361,7 +52555,9 @@ ${content}</tr>
           dY = sign2 * clamp(
             Math.exp((lines - 1) * 0.75) * 4.000244140625,
             4.000244140625,
+            // min
             350.000244140625
+            // max
           );
           if (detected.os !== "mac") {
             dY *= 5;
@@ -50557,10 +52753,10 @@ ${content}</tr>
       var k2 = clamp(geoZoomToScale(z2, TILESIZE), kMin, kMax);
       proj.scale(k2);
       var t = proj.translate();
-      var point = proj(loc2);
+      var point2 = proj(loc2);
       var center = pxCenter();
-      t[0] += center[0] - point[0];
-      t[1] += center[1] - point[1];
+      t[0] += center[0] - point2[0];
+      t[1] += center[1] - point2[1];
       return setTransform(identity2.translate(t[0], t[1]).scale(k2), duration, force);
     }
     map2.pan = function(delta, duration) {
@@ -50688,7 +52884,12 @@ ${content}</tr>
     };
     map2.transformEase = function(t2, duration) {
       duration = duration || 250;
-      setTransform(t2, duration, false);
+      setTransform(
+        t2,
+        duration,
+        false
+        /* don't force */
+      );
       return map2;
     };
     map2.zoomToEase = function(obj, duration) {
@@ -50868,20 +53069,20 @@ ${content}</tr>
     photos.dateFilterValue = function(val) {
       return val === _dateFilters[0] ? _fromDate : _toDate;
     };
-    photos.setDateFilter = function(type3, val, updateUrl) {
+    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 (type3 === _dateFilters[0]) {
+      if (type2 === _dateFilters[0]) {
         _fromDate = val;
         if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
           _toDate = _fromDate;
         }
       }
-      if (type3 === _dateFilters[1]) {
+      if (type2 === _dateFilters[1]) {
         _toDate = val;
         if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
           _fromDate = _toDate;
@@ -51482,7 +53683,7 @@ ${content}</tr>
     tooltip.content(function() {
       var heading = _heading.apply(this, arguments);
       var text2 = _title.apply(this, arguments);
-      var keys = _keys.apply(this, arguments);
+      var keys2 = _keys.apply(this, arguments);
       var headingCallback = typeof heading === "function" ? heading : (s) => s.text(heading);
       var textCallback = typeof text2 === "function" ? text2 : (s) => s.text(text2);
       return function(selection2) {
@@ -51492,12 +53693,12 @@ ${content}</tr>
         var textSelect = selection2.selectAll(".tooltip-text").data(text2 ? [text2] : []);
         textSelect.exit().remove();
         textSelect.enter().append("div").attr("class", "tooltip-text").merge(textSelect).text("").call(textCallback);
-        var keyhintWrap = selection2.selectAll(".keyhint-wrap").data(keys && keys.length ? [0] : []);
+        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(keys && keys.length ? keys : []).enter().append("kbd").attr("class", "shortcut").text(function(d) {
+        keyhintWrap.selectAll("kbd.shortcut").data(keys2 && keys2.length ? keys2 : []).enter().append("kbd").attr("class", "shortcut").text(function(d) {
           return d;
         });
       };
@@ -51563,8 +53764,8 @@ ${content}</tr>
         select_default2(this).call(tooltip).append("div").attr("class", "icon-wrap").call(svgIcon(d.icon && d.icon() || "#iD-operation-" + d.id, "operation"));
       });
       if (showLabels) {
-        buttonsEnter.append("span").attr("class", "label").html(function(d) {
-          return d.title;
+        buttonsEnter.append("span").attr("class", "label").each(function(d) {
+          select_default2(this).call(d.title);
         });
       }
       buttonsEnter.merge(buttons).classed("disabled", function(d) {
@@ -51699,10 +53900,10 @@ ${content}</tr>
   // modules/ui/feature_info.js
   function uiFeatureInfo(context) {
     function update(selection2) {
-      var features2 = context.features();
-      var stats = features2.stats();
+      var features = context.features();
+      var stats = features.stats();
       var count = 0;
-      var hiddenList = features2.hidden().map(function(k) {
+      var hiddenList = features.hidden().map(function(k) {
         if (stats[k]) {
           count += stats[k];
           return _t.append("inspector.title_count", {
@@ -51841,16 +54042,19 @@ ${content}</tr>
       if (!isSupported())
         return;
       var detected = utilDetect();
-      var keys = detected.os === "mac" ? [uiCmd("\u2303\u2318F"), "f11"] : ["f11"];
-      context.keybinding().on(keys, fullScreen);
+      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");
@@ -51862,7 +54066,11 @@ ${content}</tr>
       if (context.inIntro())
         return;
       if (!_layer.enabled() && !_locating.isShown()) {
-        _timeoutID = setTimeout(error, 1e4);
+        _timeoutID = setTimeout(
+          error,
+          1e4
+          /* 10sec */
+        );
         context.container().call(_locating);
         navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
       } else {
@@ -52557,10 +54765,10 @@ ${content}</tr>
   // modules/ui/intro/helper.js
   function pointBox(loc, context) {
     var rect = context.surfaceRect();
-    var point = context.curtainProjection(loc);
+    var point2 = context.curtainProjection(loc);
     return {
-      left: point[0] + rect.left - 40,
-      top: point[1] + rect.top - 60,
+      left: point2[0] + rect.left - 40,
+      top: point2[1] + rect.top - 60,
       width: 80,
       height: 90
     };
@@ -52569,10 +54777,10 @@ ${content}</tr>
     var box;
     if (locOrBox instanceof Array) {
       var rect = context.surfaceRect();
-      var point = context.curtainProjection(locOrBox);
+      var point2 = context.curtainProjection(locOrBox);
       box = {
-        left: point[0] + rect.left,
-        top: point[1] + rect.top
+        left: point2[0] + rect.left,
+        top: point2[1] + rect.top
       };
     } else {
       box = locOrBox;
@@ -52591,6 +54799,7 @@ ${content}</tr>
   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"),
@@ -52604,6 +54813,7 @@ ${content}</tr>
         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"),
@@ -52621,6 +54831,7 @@ ${content}</tr>
         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"),
@@ -52629,6 +54840,7 @@ ${content}</tr>
         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"),
@@ -52637,6 +54849,7 @@ ${content}</tr>
         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"),
@@ -53067,7 +55280,7 @@ ${content}</tr>
         if (context.map().zoom() !== zoomStart) {
           context.map().on("move.intro", null);
           timeout2(function() {
-            continueTo(features2);
+            continueTo(features);
           }, 3e3);
         }
       });
@@ -53076,7 +55289,7 @@ ${content}</tr>
         nextStep();
       }
     }
-    function features2() {
+    function features() {
       var onClick = function() {
         continueTo(pointsLinesAreas);
       };
@@ -56153,10 +58366,10 @@ ${content}</tr>
         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 point2 = 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];
+        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) {
@@ -56203,10 +58416,10 @@ ${content}</tr>
         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 bbox = { type: "Polygon", coordinates: [context.map().extent().polygon()] };
+          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([bbox]);
+          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(d) {
             return getPath.area(d) < 30;
           });
@@ -56621,7 +58834,7 @@ ${content}</tr>
   // modules/ui/combobox.js
   var _comboHideTimerID;
   function uiCombobox(context, klass) {
-    var dispatch10 = dispatch_default("accept", "cancel");
+    var dispatch10 = dispatch_default("accept", "cancel", "update");
     var container = context.container();
     var _suggestions = [];
     var _data = [];
@@ -56637,6 +58850,9 @@ ${content}</tr>
       cb(_data.filter(function(d) {
         var terms = d.terms || [];
         terms.push(d.value);
+        if (d.key) {
+          terms.push(d.key);
+        }
         return terms.some(function(term) {
           return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
         });
@@ -56666,7 +58882,7 @@ ${content}</tr>
           return;
         if (input.classed("disabled"))
           return;
-        _tDown = +new Date();
+        _tDown = +/* @__PURE__ */ new Date();
         var start2 = input.property("selectionStart");
         var end = input.property("selectionEnd");
         if (start2 !== end) {
@@ -56737,6 +58953,7 @@ ${content}</tr>
               var start2 = input.property("selectionStart");
               input.node().setSelectionRange(start2, start2);
               input.on("input.combo-input", change);
+              change(false);
             });
             break;
           case 9:
@@ -56745,6 +58962,7 @@ ${content}</tr>
           case 13:
             d3_event.preventDefault();
             d3_event.stopPropagation();
+            accept(d3_event);
             break;
           case 38:
             if (tagName === "textarea" && !shown)
@@ -56771,17 +58989,16 @@ ${content}</tr>
           case 27:
             cancel();
             break;
-          case 13:
-            accept(d3_event);
-            break;
         }
       }
-      function change() {
+      function change(doAutoComplete) {
+        if (doAutoComplete === void 0)
+          doAutoComplete = true;
         fetchComboData(value(), function() {
           _selected = null;
           var val = input.property("value");
           if (_suggestions.length) {
-            if (input.property("selectionEnd") === val.length) {
+            if (doAutoComplete && input.property("selectionEnd") === val.length) {
               _selected = tryAutocomplete();
             }
             if (!_selected) {
@@ -56810,7 +59027,8 @@ ${content}</tr>
           }
           index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
           _selected = _suggestions[index].value;
-          input.property("value", _selected);
+          utilGetSetValue(input, _selected);
+          dispatch10.call("update");
         }
         render();
         ensureVisible();
@@ -56860,11 +59078,18 @@ ${content}</tr>
         var val = _caseSensitive ? value() : value().toLowerCase();
         if (!val)
           return;
-        if (!isNaN(parseFloat(val)) && isFinite(val))
+        if (isFinite(val))
           return;
+        const suggestionValues = [];
+        _suggestions.forEach((s) => {
+          suggestionValues.push(s.value);
+          if (s.key && s.key !== s.value) {
+            suggestionValues.push(s.key);
+          }
+        });
         var bestIndex = -1;
-        for (var i2 = 0; i2 < _suggestions.length; i2++) {
-          var suggestion = _suggestions[i2].value;
+        for (var i2 = 0; i2 < suggestionValues.length; i2++) {
+          var suggestion = suggestionValues[i2];
           var compare = _caseSensitive ? suggestion : suggestion.toLowerCase();
           if (compare === val) {
             bestIndex = i2;
@@ -56874,9 +59099,10 @@ ${content}</tr>
           }
         }
         if (bestIndex !== -1) {
-          var bestVal = _suggestions[bestIndex].value;
+          var bestVal = suggestionValues[bestIndex];
           input.property("value", bestVal);
           input.node().setSelectionRange(val.length, bestVal.length);
+          dispatch10.call("update");
           return bestVal;
         }
       }
@@ -56904,7 +59130,7 @@ ${content}</tr>
             select_default2(this).text(d.value);
           }
         }).on("mouseenter", _mouseEnterHandler).on("mouseleave", _mouseLeaveHandler).merge(options2).classed("selected", function(d) {
-          return d.value === _selected;
+          return d.value === _selected || d.key === _selected;
         }).on("click.combo-option", accept).order();
         var node = attachTo ? attachTo.node() : input.node();
         var containerRect = container.node().getBoundingClientRect();
@@ -57427,11 +59653,15 @@ ${content}</tr>
     var _impliedYes;
     var _entityIDs = [];
     var _value;
+    var stringsField = field.resolveReference("stringsCrossReference");
+    if (!options2 && stringsField.options) {
+      options2 = stringsField.options;
+    }
     if (options2) {
       for (var i2 in options2) {
         var v = options2[i2];
         values.push(v === "undefined" ? void 0 : v);
-        texts.push(field.t.html("options." + v, { "default": v }));
+        texts.push(stringsField.t.html("options." + v, { "default": v }));
       }
     } else {
       values = [void 0, "yes"];
@@ -57554,20 +59784,55 @@ ${content}</tr>
     return utilRebind(check, dispatch10, "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);
+    };
+    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", (d) => d > maxChars).style("border-right-width", (d) => `${Math.abs(maxChars - d) * 2}px`).style("margin-right", (d) => d > maxChars ? `${(maxChars - d) * 2}px` : 0).style("opacity", (d) => d > maxChars * 0.8 ? Math.min(1, (d / maxChars - 0.8) / (1 - 0.8)) : 0).style("pointer-events", (d) => d > maxChars * 0.8 ? null : "none");
+      if (_silent)
+        return;
+      if (strLen > maxChars) {
+        _tooltip.show();
+      } else {
+        _tooltip.hide();
+      }
+    };
+    lengthIndicator.silent = function(val) {
+      if (!arguments.length)
+        return _silent;
+      _silent = val;
+      return lengthIndicator;
+    };
+    return lengthIndicator;
+  }
+
   // modules/ui/fields/combo.js
   function uiFieldCombo(field, context) {
     var dispatch10 = dispatch_default("change");
     var _isMulti = field.type === "multiCombo" || field.type === "manyCombo";
     var _isNetwork = field.type === "networkCombo";
     var _isSemi = field.type === "semiCombo";
-    var _optarray = field.options;
     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(_isMulti || _isSemi ? 1 : 2);
+    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 = [];
@@ -57583,7 +59848,7 @@ ${content}</tr>
       field.key += ":";
     }
     function snake(s) {
-      return s.replace(/\s+/g, "_").toLowerCase();
+      return s.replace(/\s+/g, "_");
     }
     function clean2(s) {
       return s.split(";").map(function(s2) {
@@ -57592,7 +59857,7 @@ ${content}</tr>
     }
     function tagValue(dval) {
       dval = clean2(dval || "");
-      var found = _comboData.find(function(o) {
+      var found = getOptions(true).find(function(o) {
         return o.key && clean2(o.value) === dval;
       });
       if (found)
@@ -57600,12 +59865,26 @@ ${content}</tr>
       if (field.type === "typeCombo" && !dval) {
         return "yes";
       }
-      return (_snake_case ? snake(dval) : dval) || void 0;
+      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, v) {
+      return field2.hasTextForStringId(`options.${v}.title`) ? `options.${v}.title` : `options.${v}`;
     }
     function displayValue(tval) {
       tval = tval || "";
-      if (field.hasTextForStringId("options." + tval)) {
-        return field.t("options." + tval, { default: 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 "";
@@ -57614,8 +59893,10 @@ ${content}</tr>
     }
     function renderValue(tval) {
       tval = tval || "";
-      if (field.hasTextForStringId("options." + tval)) {
-        return field.t.append("options." + tval, { default: 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 = "";
@@ -57625,7 +59906,7 @@ ${content}</tr>
     function objectDifference(a, b) {
       return a.filter(function(d1) {
         return !b.some(function(d2) {
-          return !d2.isMixed && d1.value === d2.value;
+          return d1.value === d2.value;
         });
       });
     }
@@ -57638,26 +59919,44 @@ ${content}</tr>
         setTaginfoValues("", setPlaceholder);
       } else {
         selection2.call(_combobox, attachTo);
-        setStaticValues(setPlaceholder);
+        setTimeout(() => setStaticValues(setPlaceholder), 0);
       }
     }
-    function setStaticValues(callback) {
-      if (!_optarray)
-        return;
-      _comboData = _optarray.map(function(v) {
+    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(v) {
+        const labelId = getLabelId(stringsField, v);
         return {
           key: v,
-          value: field.t("options." + v, { default: v }),
-          title: v,
-          display: field.t.append("options." + v, { default: v }),
-          klass: field.hasTextForStringId("options." + v) ? "" : "raw-option"
+          value: stringsField.t(labelId, { default: v }),
+          title: stringsField.t(`options.${v}.description`, { default: v }),
+          display: addComboboxIcons(stringsField.t.append(labelId, { default: v }), v),
+          klass: stringsField.hasTextForStringId(labelId) ? "" : "raw-option"
         };
       });
-      _combobox.data(objectDifference(_comboData, _multiData));
+    }
+    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 setTaginfoValues(q, callback) {
+      var queryFilter = (d) => d.value.toLowerCase().includes(q.toLowerCase()) || d.key.toLowerCase().includes(q.toLowerCase());
+      setStaticValues(callback, queryFilter);
+      var stringsField = field.resolveReference("stringsCrossReference");
       var fn = _isMulti ? "multikeys" : "values";
       var query = (_isMulti ? field.key : "") + q;
       var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
@@ -57675,39 +59974,57 @@ ${content}</tr>
       services.taginfo[fn](params, function(err, data) {
         if (err)
           return;
-        data = data.filter(function(d) {
-          return field.type !== "typeCombo" || d.value !== "yes";
+        data = data.filter((d) => field.type !== "typeCombo" || d.value !== "yes");
+        data = data.filter((d) => {
+          var value = d.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(function(d) {
-            return deprecatedValues.indexOf(d.value) === -1;
-          });
+          data = data.filter((d) => !deprecatedValues.includes(d.value));
         }
         if (hasCountryPrefix) {
-          data = data.filter(function(d) {
-            return d.value.toLowerCase().indexOf(_countryCode + ":") === 0;
-          });
+          data = data.filter((d) => d.value.toLowerCase().indexOf(_countryCode + ":") === 0);
         }
+        const additionalOptions = (field.options || stringsField.options || []).filter((v) => !data.some((dv) => dv.value === (_isMulti ? field.key + v : v))).map((v) => ({ value: v }));
         _container.classed("empty-combobox", data.length === 0);
-        _comboData = data.map(function(d) {
-          var k = d.value;
+        _comboData = data.concat(additionalOptions).map(function(d) {
+          var v = d.value;
           if (_isMulti)
-            k = k.replace(field.key, "");
-          var label = field.t("options." + k, { default: k });
+            v = v.replace(field.key, "");
+          const labelId = getLabelId(stringsField, v);
+          var isLocalizable = stringsField.hasTextForStringId(labelId);
+          var label = stringsField.t(labelId, { default: v });
           return {
-            key: k,
-            value: _isMulti ? k : label,
-            display: field.t.append("options." + k, { default: k }),
-            title: d.title || label,
-            klass: field.hasTextForStringId("options." + k) ? "" : "raw-option"
+            key: v,
+            value: label,
+            title: stringsField.t(`options.${v}.description`, { default: isLocalizable ? v : d.title !== label ? d.title : "" }),
+            display: addComboboxIcons(stringsField.t.append(labelId, { default: v }), v),
+            klass: isLocalizable ? "" : "raw-option"
           };
         });
+        _comboData = _comboData.filter(queryFilter);
         _comboData = objectDifference(_comboData, _multiData);
         if (callback)
           callback(_comboData);
       });
     }
+    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(`#${iconsField.icons[value]}`));
+          }
+          disp.call(this, selection2);
+        };
+      }
+      return disp;
+    }
     function setPlaceholder(values) {
       if (_isMulti || _isSemi) {
         _staticPlaceholder = field.placeholder() || _t("inspector.add");
@@ -57732,17 +60049,26 @@ ${content}</tr>
         ph = _staticPlaceholder;
       }
       _container.selectAll("input").attr("placeholder", ph);
+      var hideAdd = !_allowCustomValues && !values.length;
+      _container.selectAll(".chiplist .input-wrap").style("display", hideAdd ? "none" : null);
     }
     function change() {
       var t = {};
       var val;
       if (_isMulti || _isSemi) {
-        val = tagValue(utilGetSetValue(_input).replace(/,/g, ";")) || "";
-        _container.classed("active", false);
-        utilGetSetValue(_input, "");
-        var vals = val.split(";").filter(Boolean);
+        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(v) {
             var key = (field.key || "") + v;
@@ -57786,13 +60112,23 @@ ${content}</tr>
         }).filter(Boolean);
         arr = utilArrayUniq(arr);
         t[field.key] = arr.length ? arr.join(";") : void 0;
+        _lengthIndicator.update(t[field.key]);
+      }
+      dispatch10.call("change", this, t);
+    }
+    function invertMultikey(d3_event, d) {
+      d3_event.preventDefault();
+      d3_event.stopPropagation();
+      var t = {};
+      if (_isMulti) {
+        t[d.key] = _tags[d.key] === "yes" ? "no" : "yes";
       }
       dispatch10.call("change", this, t);
     }
     function combo(selection2) {
       _container = selection2.selectAll(".form-field-input-wrap").data([0]);
-      var type3 = _isMulti || _isSemi ? "multicombo" : "combo";
-      _container = _container.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + type3).merge(_container);
+      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";
@@ -57806,17 +60142,31 @@ ${content}</tr>
         }).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, selection2).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);
+      _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);
+      });
       _input.on("keydown.field", function(d3_event) {
         switch (d3_event.keyCode) {
           case 13:
@@ -57834,9 +60184,34 @@ ${content}</tr>
           _container.classed("active", true);
         });
       }
+      _combobox.on("cancel", function() {
+        _input.node().blur();
+      }).on("update", function() {
+        updateIcon(utilGetSetValue(_input));
+      });
+    }
+    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(`#${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.${value}`) && !stringsField.hasTextForStringId(`options.${value}.title`);
+      var isKnownValue = (value) => showsValue(value) && !isRawValue(value);
+      var isReadOnly = !_allowCustomValues;
       if (_isMulti || _isSemi) {
         _multiData = [];
         var maxLength;
@@ -57847,13 +60222,12 @@ ${content}</tr>
             if (!field.key && field.keys.indexOf(k) === -1)
               continue;
             var v = tags[k];
-            if (!v || typeof v === "string" && v.toLowerCase() === "no")
-              continue;
             var suffix = field.key ? k.slice(field.key.length) : k;
             _multiData.push({
               key: k,
               value: displayValue(suffix),
-              display: renderValue(suffix),
+              display: addComboboxIcons(renderValue(suffix), suffix),
+              state: typeof v === "string" ? v.toLowerCase() : "",
               isMixed: Array.isArray(v)
             });
           }
@@ -57887,7 +60261,7 @@ ${content}</tr>
             return {
               key: v2,
               value: displayValue(v2),
-              display: renderValue(v2),
+              display: addComboboxIcons(renderValue(v2), v2),
               isMixed: !commonValues.includes(v2)
             };
           });
@@ -57898,11 +60272,9 @@ ${content}</tr>
           }
         }
         maxLength = Math.max(0, maxLength);
-        var allowDragAndDrop = _isSemi && !Array.isArray(tags[field.key]);
-        var available = objectDifference(_comboData, _multiData);
-        _combobox.data(available);
-        var hideAdd = !_allowCustomValues && !available.length || maxLength <= 0;
+        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");
@@ -57912,12 +60284,22 @@ ${content}</tr>
           var k2 = d.key;
           if (_isMulti)
             k2 = k2.replace(field.key, "");
-          return !field.hasTextForStringId("options." + k2);
+          return !stringsField.hasTextForStringId("options." + k2);
         }).classed("draggable", allowDragAndDrop).classed("mixed", function(d) {
           return d.isMixed;
         }).attr("title", function(d) {
-          return d.isMixed ? _t("inspector.unshared_value_tooltip") : null;
-        });
+          if (d.isMixed) {
+            return _t("inspector.unshared_value_tooltip");
+          }
+          if (!["yes", "no"].includes(d.state)) {
+            return d.state;
+          }
+          return null;
+        }).classed("negated", (d) => d.state === "no");
+        if (!_isSemi) {
+          chips.selectAll("input[type=checkbox]").remove();
+          chips.insert("input", "span").attr("type", "checkbox").property("checked", (d) => d.state === "yes").property("indeterminate", (d) => d.isMixed || !["yes", "no"].includes(d.state)).on("click", invertMultikey);
+        }
         if (allowDragAndDrop) {
           registerDragAndDrop(chips);
         }
@@ -57931,17 +60313,13 @@ ${content}</tr>
           }
         });
         chips.select("a").attr("href", "#").on("click", removeMultikey).attr("class", "remove").text("\xD7");
+        updateIcon("");
       } else {
-        var isMixed = Array.isArray(tags[field.key]);
         var mixedValues = isMixed && tags[field.key].map(function(val) {
           return displayValue(val);
         }).filter(Boolean);
-        var showsValue = !isMixed && tags[field.key] && !(field.type === "typeCombo" && tags[field.key] === "yes");
-        var isRawValue = showsValue && !field.hasTextForStringId("options." + tags[field.key]);
-        var isKnownValue = showsValue && !isRawValue;
-        var isReadOnly = !_allowCustomValues || isKnownValue;
-        utilGetSetValue(_input, !isMixed ? displayValue(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 && (d3_event.keyCode === utilKeybinding.keyCodes["\u232B"] || d3_event.keyCode === utilKeybinding.keyCodes["\u2326"])) {
+        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 t = {};
@@ -57949,7 +60327,19 @@ ${content}</tr>
             dispatch10.call("change", this, t);
           }
         });
+        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;
@@ -57962,7 +60352,8 @@ ${content}</tr>
           targetIndex = null;
         }).on("drag", function(d3_event) {
           var x = d3_event.x - dragOrigin.x, y = d3_event.y - dragOrigin.y;
-          if (!select_default2(this).classed("dragging") && Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5)
+          if (!select_default2(this).classed("dragging") && // don't display drag until dragging beyond a distance threshold
+          Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5)
             return;
           var index = selection2.nodes().indexOf(this);
           select_default2(this).classed("dragging", true);
@@ -58051,14 +60442,20 @@ ${content}</tr>
   }
 
   // modules/ui/fields/input.js
+  var likelyRawNumberFormat = /^-?(0\.\d*|\d*\.\d{0,2}(\d{4,})?|\d{4,}\.\d{3})$/;
   function uiFieldText(field, context) {
     var dispatch10 = 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(d) {
         _phoneFormats = d;
@@ -58088,6 +60485,7 @@ ${content}</tr>
       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") {
@@ -58103,16 +60501,31 @@ ${content}</tr>
           return _t(`inspector.${which}`);
         }).merge(buttons).on("click", function(d3_event, d) {
           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(v) {
-            var num = parseFloat(v.trim(), 10);
-            if (isFinite(num))
-              return clamped(num + d);
-            const compassDir = cardinal[v.trim().toLowerCase()];
-            if (compassDir !== void 0)
-              return clamped(compassDir + d);
-            return v.trim();
+            v = v.trim();
+            const isRawNumber = likelyRawNumberFormat.test(v);
+            var num = isRawNumber ? parseFloat(v) : parseLocaleFloat(v);
+            if (isDirectionField) {
+              const compassDir = cardinal[v.toLowerCase()];
+              if (compassDir !== void 0) {
+                num = compassDir;
+              }
+            }
+            if (!isFinite(num))
+              return v;
+            num = parseFloat(num);
+            if (!isFinite(num))
+              return v;
+            num += d;
+            if (isDirectionField) {
+              num = (num % 360 + 360) % 360;
+            }
+            return formatFloat(clamped(num), isRawNumber ? v.includes(".") ? v.split(".")[1].length : 0 : countDecimalPlaces(v));
           });
           input.node().value = vals.join(";");
           change()();
@@ -58144,27 +60557,32 @@ ${content}</tr>
           if (value)
             window.open(value, "_blank");
         }).merge(outlinkButton);
-      } else if (field.key.split(":").includes("colour")) {
+      } else if (field.type === "colour") {
         input.attr("type", "text");
         updateColourPreview();
+      } else if (field.type === "date") {
+        input.attr("type", "text");
+        updateDateField();
       }
     }
-    function isColourValid(colour) {
-      if (!colour.match(/^(#([0-9a-fA-F]{3}){1,2}|\w+)$/)) {
-        return false;
-      } else if (!CSS.supports("color", colour) || ["unset", "inherit", "initial", "revert"].includes(colour)) {
-        return false;
-      }
-      return true;
-    }
     function updateColourPreview() {
+      function isColourValid(colour2) {
+        if (!colour2.match(/^(#([0-9a-fA-F]{3}){1,2}|\w+)$/)) {
+          return false;
+        } else if (!CSS.supports("color", colour2) || ["unset", "inherit", "initial", "revert"].includes(colour2)) {
+          return false;
+        }
+        return true;
+      }
       wrap2.selectAll(".colour-preview").remove();
       const colour = utilGetSetValue(input);
-      if (!isColourValid(colour) && colour !== "")
+      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]);
-      outlinkButton = wrap2.selectAll(".colour-preview").data([colour]);
-      colourSelector.enter().append("input").attr("type", "color").attr("class", "form-field-button colour-selector").attr("value", colour).on("input", debounce_default(function(d3_event) {
+      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))
@@ -58173,11 +60591,51 @@ ${content}</tr>
         change()();
         updateColourPreview();
       }, 100));
-      outlinkButton = outlinkButton.enter().append("div").attr("class", "form-field-button colour-preview").append("div").style("background-color", (d) => d).attr("class", "colour-box");
+      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", (d) => d).attr("class", "colour-box");
       if (colour === "") {
-        outlinkButton = outlinkButton.call(svgIcon("#iD-icon-edit"));
+        chooserButton = chooserButton.call(svgIcon("#iD-icon-edit"));
+      }
+      chooserButton.on("click", () => wrap2.select(".colour-selector").node().showPicker());
+    }
+    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());
       }
-      outlinkButton.on("click", () => wrap2.select(".colour-selector").node().click()).merge(outlinkButton);
     }
     function updatePhonePlaceholder() {
       if (input.empty() || !Object.keys(_phoneFormats).length)
@@ -58211,27 +60669,53 @@ ${content}</tr>
       }
       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((a, b) => /* @__PURE__ */ new Set([...a, ...b]));
+      } else {
+        return new Set([].concat(tags[field.key]));
+      }
+    }
     function change(onInput) {
       return function() {
         var t = {};
         var val = utilGetSetValue(input);
         if (!onInput)
           val = context.cleanTagValue(val);
-        if (!val && Array.isArray(_tags[field.key]))
+        if (!val && getVals(_tags).size > 1)
           return;
-        if (!onInput) {
-          if (field.type === "number" && val) {
-            var vals = val.split(";");
-            vals = vals.map(function(v) {
-              var num = parseFloat(v.trim(), 10);
-              return isFinite(num) ? clamped(num) : v.trim();
-            });
-            val = vals.join(";");
-          }
-          utilGetSetValue(input, val);
+        var displayVal = val;
+        if (field.type === "number" && val) {
+          var numbers2 = val.split(";");
+          numbers2 = numbers2.map(function(v) {
+            if (likelyRawNumberFormat.test(v)) {
+              return v;
+            }
+            var num = parseLocaleFloat(v);
+            const fractionDigits = countDecimalPlaces(v);
+            return isFinite(num) ? clamped(num).toFixed(fractionDigits) : v;
+          });
+          val = numbers2.join(";");
         }
+        if (!onInput)
+          utilGetSetValue(input, displayVal);
         t[field.key] = val || void 0;
-        dispatch10.call("change", this, t, onInput);
+        if (field.keys) {
+          dispatch10.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 {
+          dispatch10.call("change", this, t, onInput);
+        }
       };
     }
     i2.entityIDs = function(val) {
@@ -58242,14 +60726,56 @@ ${content}</tr>
     };
     i2.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 (field.key.split(":").includes("colour"))
+      const vals = getVals(tags);
+      const isMixed = vals.size > 1;
+      var val = vals.size === 1 ? [...vals][0] : "";
+      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(v) {
+          v = v.trim();
+          var num = Number(v);
+          if (!isFinite(num) || v === "")
+            return v;
+          const fractionDigits = v.includes(".") ? v.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);
+        }
+      }
+      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]);
+      }
     };
     i2.focus = function() {
       var node = input.node();
@@ -58299,7 +60825,7 @@ ${content}</tr>
       tag[d] = value || void 0;
       dispatch10.call("change", this, tag);
     }
-    access.options = function(type3) {
+    access.options = function(type2) {
       var options2 = [
         "yes",
         "no",
@@ -58311,15 +60837,16 @@ ${content}</tr>
         "permit",
         "unknown"
       ];
-      if (type3 === "access") {
+      if (type2 === "access") {
         options2 = options2.filter((v) => v !== "yes" && v !== "designated");
       }
-      if (type3 === "bicycle") {
+      if (type2 === "bicycle") {
         options2.splice(options2.length - 4, 0, "dismount");
       }
+      var stringsField = field.resolveReference("stringsCrossReference");
       return options2.map(function(option) {
         return {
-          title: field.t("options." + option + ".description"),
+          title: stringsField.t("options." + option + ".description"),
           value: option
         };
       });
@@ -58550,73 +61077,82 @@ ${content}</tr>
       }
     }).catch(function() {
     });
-    function getNearStreets() {
+    function getNear(isAddressable, type2, searchRadius, resultProp) {
       var extent = combinedEntityExtent();
       var l = extent.center();
-      var box = geoExtent(l).padByMeters(200);
-      var streets = context.history().intersects(box).filter(isAddressable).map(function(d) {
-        var loc = context.projection([
-          (extent[0][0] + extent[1][0]) / 2,
-          (extent[0][1] + extent[1][1]) / 2
-        ]);
-        var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
+      var box = geoExtent(l).padByMeters(searchRadius);
+      var features = context.history().intersects(box).filter(isAddressable).map((d) => {
+        let dist = geoSphericalDistance(d.extent(context.graph()).center(), l);
+        if (d.type === "way") {
+          var loc = context.projection([
+            (extent[0][0] + extent[1][0]) / 2,
+            (extent[0][1] + extent[1][1]) / 2
+          ]);
+          var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
+          dist = Math.min(dist, choice.distance);
+        }
+        const value = resultProp && d.tags[resultProp] ? d.tags[resultProp] : d.tags.name;
+        let title = value;
+        if (type2 === "street") {
+          title = `${addrField.t("placeholders.street")}: ${title}`;
+        } else if (type2 === "place") {
+          title = `${addrField.t("placeholders.place")}: ${title}`;
+        }
         return {
-          title: d.tags.name,
-          value: d.tags.name,
-          dist: choice.distance
+          title,
+          value,
+          dist,
+          type: type2,
+          klass: `address-${type2}`
         };
       }).sort(function(a, b) {
         return a.dist - b.dist;
       });
-      return utilArrayUniqBy(streets, "value");
+      return utilArrayUniqBy(features, "value");
+    }
+    function getNearStreets() {
       function isAddressable(d) {
         return d.tags.highway && d.tags.name && d.type === "way";
       }
+      return getNear(isAddressable, "street", 200);
+    }
+    function getNearPlaces() {
+      function isAddressable(d) {
+        if (d.tags.name) {
+          if (d.tags.place)
+            return true;
+          if (d.tags.boundary === "administrative" && d.tags.admin_level > 8)
+            return true;
+        }
+        return false;
+      }
+      return getNear(isAddressable, "place", 200);
     }
     function getNearCities() {
-      var extent = combinedEntityExtent();
-      var l = extent.center();
-      var box = geoExtent(l).padByMeters(200);
-      var cities = context.history().intersects(box).filter(isAddressable).map(function(d) {
-        return {
-          title: d.tags["addr:city"] || d.tags.name,
-          value: d.tags["addr:city"] || d.tags.name,
-          dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
-        };
-      }).sort(function(a, b) {
-        return a.dist - b.dist;
-      });
-      return utilArrayUniqBy(cities, "value");
       function isAddressable(d) {
         if (d.tags.name) {
-          if (d.tags.admin_level === "8" && d.tags.boundary === "administrative")
+          if (d.tags.boundary === "administrative" && d.tags.admin_level === "8")
             return true;
           if (d.tags.border_type === "city")
             return true;
           if (d.tags.place === "city" || d.tags.place === "town" || d.tags.place === "village")
             return true;
         }
-        if (d.tags["addr:city"])
+        if (d.tags[`${field.key}:city`])
           return true;
         return false;
       }
+      return getNear(isAddressable, "city", 200, `${field.key}:city`);
+    }
+    function getNearPostcodes() {
+      return [...new Set([].concat(getNearValues("postcode")).concat(getNear((d) => d.tags.postal_code, "postcode", 200, "postal_code")))];
     }
     function getNearValues(key) {
-      var extent = combinedEntityExtent();
-      var l = extent.center();
-      var box = geoExtent(l).padByMeters(200);
-      var results = context.history().intersects(box).filter(function hasTag(d) {
-        return _entityIDs.indexOf(d.id) === -1 && d.tags[key];
-      }).map(function(d) {
-        return {
-          title: d.tags[key],
-          value: d.tags[key],
-          dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
-        };
-      }).sort(function(a, b) {
-        return a.dist - b.dist;
-      });
-      return utilArrayUniqBy(results, "value");
+      const tagKey = `${field.key}:${key}`;
+      function hasTag(d) {
+        return _entityIDs.indexOf(d.id) === -1 && d.tags[tagKey];
+      }
+      return getNear(hasTag, key, 200, tagKey);
     }
     function updateForCountryCode() {
       if (!_countryCode)
@@ -58644,12 +61180,15 @@ ${content}</tr>
         "quarter",
         "state",
         "street",
+        "street+place",
         "subdistrict",
         "suburb"
       ];
       var widths = addressFormat.widths || {
-        housenumber: 1 / 3,
-        street: 2 / 3,
+        housenumber: 1 / 5,
+        unit: 1 / 5,
+        street: 1 / 2,
+        place: 1 / 2,
         city: 2 / 3,
         state: 1 / 4,
         postcode: 1 / 3
@@ -58677,10 +61216,36 @@ ${content}</tr>
       function addDropdown(d) {
         if (dropdowns.indexOf(d.id) === -1)
           return;
-        var nearValues = d.id === "street" ? getNearStreets : d.id === "city" ? getNearCities : getNearValues;
+        var nearValues;
+        switch (d.id) {
+          case "street":
+            nearValues = getNearStreets;
+            break;
+          case "place":
+            nearValues = getNearPlaces;
+            break;
+          case "street+place":
+            nearValues = () => [].concat(getNearStreets()).concat(getNearPlaces());
+            d.isAutoStreetPlace = true;
+            d.id = _tags[`${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-" + d.id).minItems(1).caseSensitive(true).fetcher(function(value, callback) {
-            callback(nearValues("addr:" + d.id));
+          uiCombobox(context, `address-${d.isAutoStreetPlace ? "street-place" : d.id}`).minItems(1).caseSensitive(true).fetcher(function(typedValue, callback) {
+            typedValue = typedValue.toLowerCase();
+            callback(nearValues(d.id).filter((v) => v.value.toLowerCase().indexOf(typedValue) !== -1));
+          }).on("accept", function(selected) {
+            if (d.isAutoStreetPlace) {
+              d.id = selected ? selected.type : "street";
+            }
           })
         );
       }
@@ -58710,17 +61275,26 @@ ${content}</tr>
     }
     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;
-          tags[key] = value || void 0;
-        });
-        dispatch10.call("change", this, tags, onInput);
+        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[`${field.key}:place`] = void 0;
+              } else if (subfield.id === "place") {
+                tags[`${field.key}:street`] = void 0;
+              }
+            }
+            tags[key] = value || void 0;
+          });
+          dispatch10.call("change", this, tags, onInput);
+        }, 0);
       };
     }
     function updatePlaceholder(inputSelection) {
@@ -58728,16 +61302,35 @@ ${content}</tr>
         if (_tags && Array.isArray(_tags[field.key + ":" + subfield.id])) {
           return _t("inspector.multiple_values");
         }
-        if (_countryCode) {
-          var localkey = subfield.id + "!" + _countryCode;
-          var tkey = addrField.hasTextForStringId("placeholders." + localkey) ? localkey : subfield.id;
-          return addrField.t("placeholders." + tkey);
+        if (subfield.isAutoStreetPlace) {
+          return `${getLocalPlaceholder("street")} / ${getLocalPlaceholder("place")}`;
         }
+        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"), function(subfield) {
-        var val = tags[field.key + ":" + subfield.id];
+      utilGetSetValue(_wrap.selectAll("input"), (subfield) => {
+        var val;
+        if (subfield.isAutoStreetPlace) {
+          const streetKey = `${field.key}:street`;
+          const placeKey = `${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[`${field.key}:${subfield.id}`];
+        }
         return typeof val === "string" ? val : "";
       }).attr("title", function(subfield) {
         var val = tags[field.key + ":" + subfield.id];
@@ -58767,13 +61360,21 @@ ${content}</tr>
     return utilRebind(address, dispatch10, "on");
   }
 
-  // modules/ui/fields/cycleway.js
-  function uiFieldCycleway(field, context) {
+  // modules/ui/fields/directional_combo.js
+  function uiFieldDirectionalCombo(field, context) {
     var dispatch10 = dispatch_default("change");
     var items = select_default2(null);
     var wrap2 = select_default2(null);
     var _tags;
-    function cycleway(selection2) {
+    var _combos = {};
+    if (field.type === "cycleway") {
+      field = {
+        ...field,
+        key: field.keys[0],
+        keys: field.keys.slice(1)
+      };
+    }
+    function directionalCombo(selection2) {
       function stripcolon(s) {
         return s.replace(":", "");
       }
@@ -58781,99 +61382,60 @@ ${content}</tr>
       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").merge(div);
-      var keys = ["cycleway:left", "cycleway:right"];
-      items = div.selectAll("li").data(keys);
+      items = div.selectAll("li").data(field.keys);
       var enter = items.enter().append("li").attr("class", function(d) {
-        return "labeled-input preset-cycleway-" + stripcolon(d);
+        return "labeled-input preset-directionalcombo-" + stripcolon(d);
       });
-      enter.append("span").attr("class", "label preset-label-cycleway").attr("for", function(d) {
-        return "preset-input-cycleway-" + stripcolon(d);
+      enter.append("span").attr("class", "label preset-label-directionalcombo").attr("for", function(d) {
+        return "preset-input-directionalcombo-" + stripcolon(d);
       }).html(function(d) {
         return field.t.html("types." + d);
       });
-      enter.append("div").attr("class", "preset-input-cycleway-wrap").append("input").attr("type", "text").attr("class", function(d) {
-        return "preset-input-cycleway preset-input-" + stripcolon(d);
-      }).call(utilNoAuto).each(function(d) {
-        select_default2(this).call(
-          uiCombobox(context, "cycleway-" + stripcolon(d)).data(cycleway.options(d))
-        );
-      });
-      items = items.merge(enter);
-      wrap2.selectAll(".preset-input-cycleway").on("change", change).on("blur", change);
-    }
-    function change(d3_event, key) {
-      var newValue = context.cleanTagValue(utilGetSetValue(select_default2(this)));
-      if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key])))
-        return;
-      if (newValue === "none" || newValue === "") {
-        newValue = void 0;
-      }
-      var otherKey = key === "cycleway:left" ? "cycleway:right" : "cycleway:left";
-      var otherValue = typeof _tags.cycleway === "string" ? _tags.cycleway : _tags[otherKey];
-      if (otherValue && Array.isArray(otherValue)) {
-        otherValue = otherValue[0];
-      }
-      if (otherValue === "none" || otherValue === "") {
-        otherValue = void 0;
-      }
-      var tag = {};
-      if (newValue === otherValue) {
-        tag = {
-          cycleway: newValue,
-          "cycleway:left": void 0,
-          "cycleway:right": void 0
-        };
-      } else {
-        tag = {
-          cycleway: void 0
-        };
-        tag[key] = newValue;
-        tag[otherKey] = otherValue;
-      }
-      dispatch10.call("change", this, tag);
-    }
-    cycleway.options = function() {
-      return field.options.map(function(option) {
-        return {
-          title: field.t("options." + option + ".description"),
-          value: option
+      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", (t) => change(key, t[key]));
+        _combos[key] = combo;
+        select_default2(this).call(combo);
       });
-    };
-    cycleway.tags = function(tags) {
-      _tags = tags;
-      var commonValue = typeof tags.cycleway === "string" && tags.cycleway;
-      utilGetSetValue(items.selectAll(".preset-input-cycleway"), function(d) {
-        if (commonValue)
-          return commonValue;
-        return !tags.cycleway && typeof tags[d] === "string" ? tags[d] : "";
-      }).attr("title", function(d) {
-        if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
-          var vals = [];
-          if (Array.isArray(tags.cycleway)) {
-            vals = vals.concat(tags.cycleway);
-          }
-          if (Array.isArray(tags[d])) {
-            vals = vals.concat(tags[d]);
-          }
-          return vals.filter(Boolean).join("\n");
-        }
-        return null;
-      }).attr("placeholder", function(d) {
-        if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
-          return _t("inspector.multiple_values");
+      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];
+      dispatch10.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 field.placeholder();
-      }).classed("mixed", function(d) {
-        return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
+        return tags;
       });
+    }
+    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] });
+      }
     };
-    cycleway.focus = function() {
+    directionalCombo.focus = function() {
       var node = wrap2.selectAll("input").node();
       if (node)
         node.focus();
     };
-    return utilRebind(cycleway, dispatch10, "on");
+    return utilRebind(directionalCombo, dispatch10, "on");
   }
 
   // modules/ui/fields/lanes.js
@@ -58940,6 +61502,7 @@ ${content}</tr>
     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() {
@@ -58960,7 +61523,9 @@ ${content}</tr>
         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)
@@ -58988,7 +61553,7 @@ ${content}</tr>
         var preset = _mainPresetIndex.match(entity, context.graph());
         if (preset) {
           var isSuggestion = preset.suggestion;
-          var fields = preset.fields();
+          var fields = preset.fields(entity.extent(context.graph()).center());
           var showsBrandField = fields.some(function(d) {
             return d.id === "brand";
           });
@@ -59036,6 +61601,7 @@ ${content}</tr>
       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);
@@ -59211,6 +61777,9 @@ ${content}</tr>
       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();
@@ -59244,6 +61813,8 @@ ${content}</tr>
     var _entityIDs = [];
     var _tags;
     var _isImperial;
+    var formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
+    var parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
     var primaryUnits = [
       {
         value: "m",
@@ -59294,16 +61865,24 @@ ${content}</tr>
         return;
       if (!primaryValue && !secondaryValue) {
         tag[field.key] = void 0;
-      } else if (isNaN(primaryValue) || isNaN(secondaryValue) || !_isImperial) {
-        tag[field.key] = context.cleanTagValue(primaryValue);
       } else {
-        if (primaryValue !== "") {
-          primaryValue = context.cleanTagValue(primaryValue + "'");
-        }
-        if (secondaryValue !== "") {
-          secondaryValue = context.cleanTagValue(secondaryValue + '"');
+        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) {
+          tag[field.key] = context.cleanTagValue(rawPrimaryValue);
+        } else {
+          if (rawPrimaryValue !== "") {
+            rawPrimaryValue = rawPrimaryValue + "'";
+          }
+          if (rawSecondaryValue !== "") {
+            rawSecondaryValue = rawSecondaryValue + '"';
+          }
+          tag[field.key] = context.cleanTagValue(rawPrimaryValue + rawSecondaryValue);
         }
-        tag[field.key] = primaryValue + secondaryValue;
       }
       dispatch10.call("change", this, tag);
     }
@@ -59316,20 +61895,28 @@ ${content}</tr>
         if (primaryValue && (primaryValue.indexOf("'") >= 0 || primaryValue.indexOf('"') >= 0)) {
           secondaryValue = primaryValue.match(/(-?[\d.]+)"/);
           if (secondaryValue !== null) {
-            secondaryValue = secondaryValue[1];
+            secondaryValue = formatFloat(parseFloat(secondaryValue[1]));
           }
           primaryValue = primaryValue.match(/(-?[\d.]+)'/);
           if (primaryValue !== null) {
-            primaryValue = primaryValue[1];
+            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;
         }
       }
       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 ? "0" : null).classed("mixed", isMixed).classed("disabled", !_isImperial).attr("readonly", _isImperial ? null : "readonly");
+      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() {
@@ -59352,6 +61939,8 @@ ${content}</tr>
     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];
@@ -59385,8 +61974,8 @@ ${content}</tr>
     }
     function comboValues(d) {
       return {
-        value: d.toString(),
-        title: d.toString()
+        value: formatFloat(d),
+        title: formatFloat(d)
       };
     }
     function change() {
@@ -59396,24 +61985,35 @@ ${content}</tr>
         return;
       if (!value) {
         tag[field.key] = void 0;
-      } else if (isNaN(value) || !_isImperial) {
-        tag[field.key] = context.cleanTagValue(value);
       } else {
-        tag[field.key] = context.cleanTagValue(value + " mph");
+        var rawValue = likelyRawNumberFormat.test(value) ? parseFloat(value) : parseLocaleFloat(value);
+        if (isNaN(rawValue))
+          rawValue = value;
+        if (isNaN(rawValue) || !_isImperial) {
+          tag[field.key] = context.cleanTagValue(rawValue);
+        } else {
+          tag[field.key] = context.cleanTagValue(rawValue + " mph");
+        }
       }
       dispatch10.call("change", this, tag);
     }
     roadspeed.tags = function(tags) {
       _tags = tags;
-      var value = tags[field.key];
+      var rawValue = tags[field.key];
+      var value = rawValue;
       var isMixed = Array.isArray(value);
       if (!isMixed) {
-        if (value && value.indexOf("mph") >= 0) {
-          value = parseInt(value, 10).toString();
+        if (rawValue && rawValue.indexOf("mph") >= 0) {
           _isImperial = true;
-        } else if (value) {
+        } 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);
@@ -59455,18 +62055,19 @@ ${content}</tr>
       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(d) {
-        return field.t("options." + d, { "default": d });
+        return stringsField.t("options." + d, { "default": d });
       }).attr("checked", false);
-      enter.append("span").html(function(d) {
-        return field.t.html("options." + d, { "default": d });
+      enter.append("span").each(function(d) {
+        stringsField.t.append("options." + d, { "default": d })(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 type3 = _mainPresetIndex.field(selected);
+      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] : []);
@@ -59474,9 +62075,9 @@ ${content}</tr>
       extrasWrap = extrasWrap.enter().append("div").attr("class", "structure-extras-wrap").merge(extrasWrap);
       var list = extrasWrap.selectAll("ul").data([0]);
       list = list.enter().append("ul").attr("class", "rows").merge(list);
-      if (type3) {
+      if (type2) {
         if (!typeField || typeField.id !== selected) {
-          typeField = uiField(context, type3, _entityIDs, { wrap: false }).on("change", changeType);
+          typeField = uiField(context, type2, _entityIDs, { wrap: false }).on("change", changeType);
         }
         typeField.tags(tags);
       } else {
@@ -59654,9 +62255,11 @@ ${content}</tr>
         _graph = context.graph();
         _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
       }
-      var isOK = _intersection && _intersection.vertices.length && _intersection.vertices.filter(function(vertex) {
+      var isOK = _intersection && _intersection.vertices.length && // has vertices
+      _intersection.vertices.filter(function(vertex) {
         return vertex.id === _vertexID;
-      }).length && _intersection.ways.length > 2 && _intersection.ways.filter(function(way) {
+      }).length && _intersection.ways.length > 2 && // has more than 2 ways
+      _intersection.ways.filter(function(way) {
         return way.__to;
       }).length > 1;
       select_default2(selection2.node().parentNode).classed("hide", !isOK);
@@ -59958,6 +62561,7 @@ ${content}</tr>
         var opts;
         if (isImperial) {
           var distToFeet = {
+            // imprecise conversion for prettier display
             20: 70,
             25: 85,
             30: 100,
@@ -59983,8 +62587,8 @@ ${content}</tr>
       var entity = graph.entity(entityID);
       var name = utilDisplayName(entity) || "";
       var matched = _mainPresetIndex.match(entity, graph);
-      var type3 = matched && matched.name() || utilDisplayType(entity.id);
-      return name || type3;
+      var type2 = matched && matched.name() || utilDisplayType(entity.id);
+      return name || type2;
     }
     restrictions.entityIDs = function(val) {
       _intersection = null;
@@ -60010,29 +62614,34 @@ ${content}</tr>
   function uiFieldTextarea(field, context) {
     var dispatch10 = 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).merge(wrap2);
+      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);
-    }
-    function change(onInput) {
-      return function() {
-        var val = utilGetSetValue(input);
-        if (!onInput)
-          val = context.cleanTagValue(val);
-        if (!val && Array.isArray(_tags[field.key]))
-          return;
-        var t = {};
-        t[field.key] = val || void 0;
-        dispatch10.call("change", this, t, onInput);
-      };
+      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 t = {};
+          t[field.key] = val || void 0;
+          dispatch10.call("change", this, t, 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();
@@ -60110,8 +62719,11 @@ ${content}</tr>
         }
       }
       wikidata.itemsForSearchQuery(q, function(err, data) {
-        if (err)
+        if (err) {
+          if (err !== "No query")
+            console.error(err);
           return;
+        }
         var result = data.map(function(item) {
           return {
             id: item.id,
@@ -60457,7 +63069,10 @@ ${content}</tr>
           const defaultLangInfo = defaultLanguageInfo();
           _wikiURL = `https://${defaultLangInfo[2]}.wikipedia.org/w/index.php?fulltext=1&search=${value}`;
         } else {
-          const shownOrDefaultLangInfo = language(true);
+          const shownOrDefaultLangInfo = language(
+            true
+            /* skipEnglishFallback */
+          );
           utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
           _wikiURL = "";
         }
@@ -60481,9 +63096,12 @@ ${content}</tr>
     access: uiFieldAccess,
     address: uiFieldAddress,
     check: uiFieldCheck,
+    colour: uiFieldText,
     combo: uiFieldCombo,
-    cycleway: uiFieldCycleway,
+    cycleway: uiFieldDirectionalCombo,
+    date: uiFieldText,
     defaultCheck: uiFieldCheck,
+    directionalCombo: uiFieldDirectionalCombo,
     email: uiFieldText,
     identifier: uiFieldText,
     lanes: uiFieldLanes,
@@ -60532,7 +63150,6 @@ ${content}</tr>
     }
     var _locked = false;
     var _lockedTip = uiTooltip().title(() => _t.append("inspector.lock.suggestion", { label: field.title })).placement("bottom");
-    field.keys = field.keys || [field.key];
     if (_show && !field.impl) {
       createField();
     }
@@ -60547,19 +63164,26 @@ ${content}</tr>
         }
       }
     }
+    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 field.keys.some(function(key) {
+        return allKeys().some(function(key) {
           return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
         });
       });
     }
     function tagsContainFieldKey() {
-      return field.keys.some(function(key) {
+      return allKeys().some(function(key) {
         if (field.type === "multiCombo") {
           for (var tagKey in _tags) {
             if (tagKey.indexOf(key) === 0) {
@@ -60576,7 +63200,7 @@ ${content}</tr>
       d3_event.preventDefault();
       if (!entityIDs || _locked)
         return;
-      dispatch10.call("revert", d, d.keys);
+      dispatch10.call("revert", d, allKeys());
     }
     function remove2(d3_event, d) {
       d3_event.stopPropagation();
@@ -60584,7 +63208,7 @@ ${content}</tr>
       if (_locked)
         return;
       var t = {};
-      d.keys.forEach(function(key) {
+      allKeys().forEach(function(key) {
         t[key] = void 0;
       });
       dispatch10.call("change", d, t);
@@ -60694,12 +63318,13 @@ ${content}</tr>
       }))
         return false;
       if (entityIDs && _entityExtent && field.locationSetID) {
-        var validLocations = _mainLocations.locationsAt(_entityExtent.center());
-        if (!validLocations[field.locationSetID])
+        var validHere = _sharedLocationManager.locationSetsAt(_entityExtent.center());
+        if (!validHere[field.locationSetID])
           return false;
       }
       var prerequisiteTag = field.prerequisiteTag;
-      if (entityIDs && !tagsContainFieldKey() && 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) {
@@ -60876,12 +63501,34 @@ ${content}</tr>
           });
         }
       }
-      var hasGoogle = _tags.comment.match(/google/i);
-      var commentWarning = selection2.select(".form-field-comment").selectAll(".comment-warning").data(hasGoogle ? [0] : []);
+      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, (d) => d.id);
       commentWarning.exit().transition().duration(200).style("opacity", 0).remove();
-      var commentEnter = commentWarning.enter().insert("div", ".tag-reference-body").attr("class", "field-warning comment-warning").style("opacity", 0);
-      commentEnter.append("a").attr("target", "_blank").call(svgIcon("#iD-icon-alert", "inline")).attr("href", _t("commit.google_warning_link")).append("span").call(_t.append("commit.google_warning"));
+      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(d) {
+        let selection3 = select_default2(this);
+        if (d.link) {
+          selection3 = selection3.append("a").attr("target", "_blank").attr("href", d.link);
+        }
+        selection3.call(d.msg);
+      });
     }
     changesetEditor.tags = function(_) {
       if (!arguments.length)
@@ -60935,7 +63582,10 @@ ${content}</tr>
     }
     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 ? {} : true;
+      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);
@@ -61030,7 +63680,10 @@ ${content}</tr>
       }
     }
     this.build = function(oXMLParent, nVerbosity, bFreeze, bNesteAttributes) {
-      var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : 1;
+      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);
     };
     this.unbuild = function(oObjTree) {
@@ -61624,7 +64277,7 @@ ${content}</tr>
         var sign2 = d === "previous" ? -1 : 1;
         container.selectAll(".conflict").remove();
         container.call(showConflict, index + sign2);
-      }).call(function(d) {
+      }).each(function(d) {
         _t.append("save.conflict." + d)(select_default2(this));
       });
     }
@@ -61813,9 +64466,9 @@ ${content}</tr>
       var buttons = fixesEnter.append("button").on("click", function(d3_event, d) {
         if (select_default2(this).attr("disabled") || !d.onClick)
           return;
-        if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1e3)
+        if (d.issue.dateLastRanFix && /* @__PURE__ */ new Date() - d.issue.dateLastRanFix < 1e3)
           return;
-        d.issue.dateLastRanFix = new Date();
+        d.issue.dateLastRanFix = /* @__PURE__ */ new Date();
         utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
         new Promise(function(resolve, reject) {
           d.onClick(context, resolve, reject);
@@ -61928,12 +64581,12 @@ ${content}</tr>
         fillEnter.append("path").attr("d", `M${c1} ${c1} L${c1} ${c2} L${c2} ${c2} L${c2} ${c1} Z`).attr("class", `area ${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);
+      [[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, w / 2], [c2, w / 2], [h / 2, c1], [h / 2, c2]].forEach((point) => {
-        fillEnter.append("circle").attr("class", "midpoint").attr("cx", point[0]).attr("cy", point[1]).attr("r", rMidpoint);
+      [[c1, w / 2], [c2, w / 2], [h / 2, c1], [h / 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 ${tagClasses}`);
@@ -61955,8 +64608,8 @@ ${content}</tr>
       ["casing", "stroke"].forEach((klass) => {
         lineEnter.append("path").attr("d", `M${x12} ${y} L${x2} ${y}`).attr("class", `line ${klass}`);
       });
-      [[x12 - 1, y], [x2 + 1, y]].forEach((point) => {
-        lineEnter.append("circle").attr("class", "vertex").attr("cx", point[0]).attr("cy", point[1]).attr("r", r);
+      [[x12 - 1, y], [x2 + 1, y]].forEach((point2) => {
+        lineEnter.append("circle").attr("class", "vertex").attr("cx", point2[0]).attr("cy", point2[1]).attr("r", r);
       });
       line = lineEnter.merge(line);
       line.selectAll("path.stroke").attr("class", `line stroke ${tagClasses}`);
@@ -61983,8 +64636,8 @@ ${content}</tr>
         routeEnter.append("path").attr("d", `M${x2} ${y2} L${x3} ${y12}`).attr("class", `segment1 line ${klass}`);
         routeEnter.append("path").attr("d", `M${x3} ${y12} L${x4} ${y2}`).attr("class", `segment2 line ${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", r);
+      [[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", r);
       });
       route = routeEnter.merge(route);
       if (drawRoute) {
@@ -62002,7 +64655,8 @@ ${content}</tr>
       const isMaki = picon && /^maki-/.test(picon);
       const isTemaki = picon && /^temaki-/.test(picon);
       const isFa = picon && /^fa[srb]-/.test(picon);
-      const isiDIcon = picon && !(isMaki || isTemaki || isFa);
+      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);
@@ -62182,13 +64836,17 @@ ${content}</tr>
           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();
-          var moreFields = preset.moreFields();
+          var fields = preset.fields(loc);
+          var moreFields = preset.moreFields(loc);
           allFields = utilArrayUnion(allFields, fields);
           allMoreFields = utilArrayUnion(allMoreFields, moreFields);
           if (!sharedTotalFields) {
@@ -62233,8 +64891,8 @@ ${content}</tr>
         _fieldsArr.forEach(function(field) {
           field.on("change", function(t, onInput) {
             dispatch10.call("change", field, _entityIDs, t, onInput);
-          }).on("revert", function(keys) {
-            dispatch10.call("revert", field, keys);
+          }).on("revert", function(keys2) {
+            dispatch10.call("revert", field, keys2);
           });
         });
       }
@@ -62244,11 +64902,6 @@ ${content}</tr>
       selection2.call(
         formFields.fieldsArr(_fieldsArr).state(_state).klass("grouped-items-area")
       );
-      selection2.selectAll(".wrap-form-field input").on("keydown", function(d3_event) {
-        if (d3_event.keyCode === 13 && context.container().select(".combobox").empty()) {
-          context.enter(modeBrowse(context));
-        }
-      });
     }
     section.presets = function(val) {
       if (!arguments.length)
@@ -62424,7 +65077,8 @@ ${content}</tr>
           targetIndex = null;
         }).on("drag", function(d3_event) {
           var x = d3_event.x - dragOrigin.x, y = d3_event.y - dragOrigin.y;
-          if (!select_default2(this).classed("dragging") && Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5)
+          if (!select_default2(this).classed("dragging") && // don't display drag until dragging beyond a distance threshold
+          Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5)
             return;
           var index = items.nodes().indexOf(this);
           select_default2(this).classed("dragging", true);
@@ -62958,7 +65612,7 @@ ${content}</tr>
       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(`icons.${direction}`)).call(svgIcon(`#iD-icon-${direction}`));
+      headerEnter.append("button").attr("class", "preset-reset preset-choose").attr("title", _t("inspector.back_tooltip")).call(svgIcon(`#iD-icon-${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"));
@@ -63027,14 +65681,18 @@ ${content}</tr>
         var entityID = entityIDs[i2];
         var entity = context.entity(entityID);
         var tags = Object.assign({}, entity.tags);
-        for (var k in changed) {
-          if (!k)
-            continue;
-          var v = changed[k];
-          if (typeof v === "object") {
-            tags[k] = tags[v.oldKey];
-          } else if (v !== void 0 || tags.hasOwnProperty(k)) {
-            tags[k] = v;
+        if (typeof changed === "function") {
+          tags = changed(tags);
+        } else {
+          for (var k in changed) {
+            if (!k)
+              continue;
+            var v = changed[k];
+            if (typeof v === "object") {
+              tags[k] = tags[v.oldKey];
+            } else if (v !== void 0 || tags.hasOwnProperty(k)) {
+              tags[k] = v;
+            }
           }
         }
         if (!onInput) {
@@ -63063,14 +65721,14 @@ ${content}</tr>
         context.validator().validate();
       }
     }
-    function revertTags(keys) {
+    function revertTags(keys2) {
       var actions = [];
       for (var i2 in _entityIDs) {
         var entityID = _entityIDs[i2];
         var original = context.graph().base().entities[entityID];
         var changed = {};
-        for (var j2 in keys) {
-          var key = keys[j2];
+        for (var j2 in keys2) {
+          var key = keys2[j2];
           changed[key] = original ? original.tags[key] : void 0;
         }
         var entity = context.entity(entityID);
@@ -63198,7 +65856,8 @@ ${content}</tr>
       }
       function keypress(d3_event) {
         var q = search.property("value"), items = list.selectAll(".feature-list-item");
-        if (d3_event.keyCode === 13 && q.length && items.size()) {
+        if (d3_event.keyCode === 13 && // ↩ Return
+        q.length && items.size()) {
           click(d3_event, items.datum());
         }
       }
@@ -63215,7 +65874,7 @@ ${content}</tr>
           drawList();
         }
       }
-      function features2() {
+      function features() {
         var result = [];
         var graph = context.graph();
         var visibleCenter = context.map().extent().center();
@@ -63224,7 +65883,7 @@ ${content}</tr>
           return result;
         var locationMatch = sexagesimal.pair(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
         if (locationMatch) {
-          var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
+          var loc = [Number(locationMatch[0]), Number(locationMatch[1])];
           result.push({
             id: -1,
             geometry: "point",
@@ -63233,7 +65892,7 @@ ${content}</tr>
             location: loc
           });
         }
-        var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
+        var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W{0,2}0*([1-9]\d*)(?:\W|$)/i);
         if (idMatch) {
           var elemType = idMatch[1].charAt(0);
           var elemId = idMatch[2];
@@ -63254,14 +65913,14 @@ ${content}</tr>
           if (name.toLowerCase().indexOf(q) < 0)
             continue;
           var matched = _mainPresetIndex.match(entity, graph);
-          var type3 = matched && matched.name() || utilDisplayType(entity.id);
+          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: type3,
+            type: type2,
             name,
             distance
           });
@@ -63284,15 +65943,15 @@ ${content}</tr>
             var tempEntity = osmEntity(attrs);
             var tempGraph = coreGraph([tempEntity]);
             var matched2 = _mainPresetIndex.match(tempEntity, tempGraph);
-            var type4 = matched2 && matched2.name() || utilDisplayType(id3);
+            var type3 = matched2 && matched2.name() || utilDisplayType(id3);
             result.push({
               id: tempEntity.id,
               geometry: tempEntity.geometry(tempGraph),
-              type: type4,
+              type: type3,
               name: d.display_name,
               extent: new geoExtent(
-                [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
-                [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])]
+                [Number(d.boundingbox[3]), Number(d.boundingbox[0])],
+                [Number(d.boundingbox[2]), Number(d.boundingbox[1])]
               )
             });
           }
@@ -63321,7 +65980,7 @@ ${content}</tr>
       }
       function drawList() {
         var value = search.property("value");
-        var results = features2();
+        var results = features();
         list.classed("filtered", value.length);
         var resultsIndicator = list.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");
@@ -63637,7 +66296,7 @@ ${content}</tr>
       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", direction).on("click", function() {
+      messagewrap.append("button").attr("class", "preset-choose").attr("title", _entityIDs.length === 1 ? _t("inspector.edit") : _t("inspector.edit_features")).on("click", function() {
         dispatch10.call("cancel", this);
       }).call(svgIcon(`#iD-icon-${direction}`));
       function initialKeydown(d3_event) {
@@ -63655,7 +66314,8 @@ ${content}</tr>
         }
       }
       function keydown(d3_event) {
-        if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"] && search.node().selectionStart === search.property("value").length) {
+        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 = list.selectAll(".preset-list-button");
@@ -63665,7 +66325,8 @@ ${content}</tr>
       }
       function keypress(d3_event) {
         var value = search.property("value");
-        if (d3_event.keyCode === 13 && value.length) {
+        if (d3_event.keyCode === 13 && // ↩ Return
+        value.length) {
           list.selectAll(".preset-list-item:first-child").each(function(d) {
             d.choose.call(this);
           });
@@ -64328,8 +66989,8 @@ ${content}</tr>
       }
     }
     lasso.extent = function() {
-      return lasso.coordinates.reduce(function(extent, point) {
-        return extent.extend(geoExtent(point));
+      return lasso.coordinates.reduce(function(extent, point2) {
+        return extent.extend(geoExtent(point2));
       }, geoExtent());
     };
     lasso.p = function(_) {
@@ -64535,7 +67196,8 @@ ${content}</tr>
       }
       noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons);
       function keydown(d3_event) {
-        if (!(d3_event.keyCode === 13 && d3_event.metaKey))
+        if (!(d3_event.keyCode === 13 && // ↩ Return
+        d3_event.metaKey))
           return;
         var osm = services.osm;
         if (!osm)
@@ -64682,7 +67344,7 @@ ${content}</tr>
 
   // modules/ui/source_switch.js
   function uiSourceSwitch(context) {
-    var keys;
+    var keys2;
     function click(d3_event) {
       d3_event.preventDefault();
       var osm = context.connection();
@@ -64698,15 +67360,15 @@ ${content}</tr>
       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 ? keys[0] : keys[1]);
+      osm.switch(isLive ? keys2[0] : keys2[1]);
     }
     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(_) {
       if (!arguments.length)
-        return keys;
-      keys = _;
+        return keys2;
+      keys2 = _;
       return sourceSwitch;
     };
     return sourceSwitch;
@@ -64840,12 +67502,12 @@ ${content}</tr>
   }
 
   // node_modules/osm-community-index/lib/simplify.js
-  var import_diacritics3 = __toESM(require_diacritics(), 1);
-  function simplify2(str2) {
+  var import_diacritics2 = __toESM(require_diacritics(), 1);
+  function simplify(str2) {
     if (typeof str2 !== "string")
       return "";
-    return import_diacritics3.default.remove(
-      str2.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\u200b-\u200f\u2016\u2017\u2020-\u2027\u2030-\u2038\u203b-\u203e\u2041-\u2043\u2047-\u2051\u2053\u2055-\u205e\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00\u2e01\u2e06-\u2e08\u2e0b\u2e0e-\u2e16\u2e18\u2e19\u2e1b\u2e1e\u2e1f\u2e2a-\u2e2e\u2e30-\u2e39\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()
+    return import_diacritics2.default.remove(
+      str2.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()
     );
   }
 
@@ -64856,7 +67518,7 @@ ${content}</tr>
     const anyToken = new RegExp(/(\{\w+\})/, "gi");
     if (localizerFn) {
       if (itemStrings.community) {
-        const communityID = simplify2(itemStrings.community);
+        const communityID = simplify(itemStrings.community);
         itemStrings.community = localizerFn(`_communities.${communityID}`);
       }
       ["name", "description", "extendedDescription"].forEach((prop) => {
@@ -64945,11 +67607,11 @@ ${content}</tr>
         if (_oci)
           return _oci;
         if (vals[0] && Array.isArray(vals[0].features)) {
-          _mainLocations.mergeCustomGeoJSON(vals[0]);
+          _sharedLocationManager.mergeCustomGeoJSON(vals[0]);
         }
         let ociResources = Object.values(vals[1].resources);
         if (ociResources.length) {
-          return _mainLocations.mergeLocationSets(ociResources).then(() => {
+          return _sharedLocationManager.mergeLocationSets(ociResources).then(() => {
             _oci = {
               resources: ociResources,
               defaults: vals[2].defaults
@@ -64959,6 +67621,7 @@ ${content}</tr>
         } else {
           _oci = {
             resources: [],
+            // no resources?
             defaults: vals[2].defaults
           };
           return _oci;
@@ -64999,10 +67662,10 @@ ${content}</tr>
       }));
       ensureOSMCommunityIndex().then((oci) => {
         const loc = context.map().center();
-        const validLocations = _mainLocations.locationsAt(loc);
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
         let communities = [];
         oci.resources.forEach((resource) => {
-          let area = validLocations[resource.locationSetID];
+          let area = validHere[resource.locationSetID];
           if (!area)
             return;
           const localizer = (stringID) => _t.html(`community.${stringID}`);
@@ -65043,7 +67706,7 @@ ${content}</tr>
         return event;
       }).filter((event) => {
         const t = event.date.getTime();
-        const now3 = new Date().setHours(0, 0, 0, 0);
+        const now3 = (/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0);
         return !isNaN(t) && t >= now3;
       }).sort((a, b) => {
         return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
@@ -65475,9 +68138,7 @@ ${content}</tr>
           query: value2
         }, function(err, data) {
           if (!err) {
-            var filtered = data.filter(function(d) {
-              return _tags[d.value] === void 0;
-            });
+            const filtered = data.filter((d) => _tags[d.value] === void 0).filter((d) => d.value.toLowerCase().includes(value2.toLowerCase()));
             callback(sort(value2, filtered));
           }
         });
@@ -65489,10 +68150,12 @@ ${content}</tr>
           geometry,
           query: value2
         }, function(err, data) {
-          if (!err)
-            callback(sort(value2, data));
+          if (!err) {
+            const filtered = data.filter((d) => d.value.toLowerCase().includes(value2.toLowerCase()));
+            callback(sort(value2, filtered));
+          }
         });
-      }));
+      }).caseSensitive(allowUpperCaseTagValues.test(utilGetSetValue(key))));
       function sort(value2, data) {
         var sameletter = [];
         var other = [];
@@ -65672,11 +68335,11 @@ ${content}</tr>
   // modules/ui/osmose_details.js
   function uiOsmoseDetails(context) {
     let _qaItem;
-    function issueString(d, type3) {
+    function issueString(d, type2) {
       if (!d)
         return "";
       const s = services.osmose.getStrings(d.itemType);
-      return type3 in s ? s[type3] : "";
+      return type2 in s ? s[type2] : "";
     }
     function osmoseDetails(selection2) {
       const details = selection2.selectAll(".error-details").data(
@@ -66183,9 +68846,12 @@ ${content}</tr>
   function modeAddArea(context, mode) {
     mode.id = "add-area";
     var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
-    var defaultTags = { area: "yes" };
-    if (mode.preset)
-      defaultTags = mode.preset.setTags(defaultTags, "area");
+    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());
@@ -66194,7 +68860,7 @@ ${content}</tr>
     function start2(loc) {
       var startGraph = context.graph();
       var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags });
+      var way = osmWay({ tags: defaultTags(loc) });
       context.perform(
         actionAddEntity(node),
         actionAddEntity(way),
@@ -66206,7 +68872,7 @@ ${content}</tr>
     function startFromWay(loc, edge) {
       var startGraph = context.graph();
       var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags });
+      var way = osmWay({ tags: defaultTags(loc) });
       context.perform(
         actionAddEntity(node),
         actionAddEntity(way),
@@ -66218,7 +68884,7 @@ ${content}</tr>
     }
     function startFromNode(node) {
       var startGraph = context.graph();
-      var way = osmWay({ tags: defaultTags });
+      var way = osmWay({ tags: defaultTags(node.loc) });
       context.perform(
         actionAddEntity(way),
         actionAddVertex(way.id, node.id),
@@ -66239,13 +68905,16 @@ ${content}</tr>
   function modeAddLine(context, mode) {
     mode.id = "add-line";
     var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
-    var defaultTags = {};
-    if (mode.preset)
-      defaultTags = mode.preset.setTags(defaultTags, "line");
+    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 });
+      var way = osmWay({ tags: defaultTags(loc) });
       context.perform(
         actionAddEntity(node),
         actionAddEntity(way),
@@ -66256,7 +68925,7 @@ ${content}</tr>
     function startFromWay(loc, edge) {
       var startGraph = context.graph();
       var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags });
+      var way = osmWay({ tags: defaultTags(loc) });
       context.perform(
         actionAddEntity(node),
         actionAddEntity(way),
@@ -66267,7 +68936,7 @@ ${content}</tr>
     }
     function startFromNode(node) {
       var startGraph = context.graph();
-      var way = osmWay({ tags: defaultTags });
+      var way = osmWay({ tags: defaultTags(node.loc) });
       context.perform(
         actionAddEntity(way),
         actionAddVertex(way.id, node.id)
@@ -66287,11 +68956,14 @@ ${content}</tr>
   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);
-    var defaultTags = {};
-    if (mode.preset)
-      defaultTags = mode.preset.setTags(defaultTags, "point");
+    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 });
+      var node = osmNode({ loc, tags: defaultTags(loc) });
       context.perform(
         actionAddEntity(node),
         _t("operations.add.annotation.point")
@@ -66299,7 +68971,7 @@ ${content}</tr>
       enterSelectMode(node);
     }
     function addWay(loc, edge) {
-      var node = osmNode({ tags: defaultTags });
+      var node = osmNode({ tags: defaultTags(loc) });
       context.perform(
         actionAddMidpoint({ loc, edge }, node),
         _t("operations.add.annotation.vertex")
@@ -66312,13 +68984,14 @@ ${content}</tr>
       );
     }
     function addNode(node) {
-      if (Object.keys(defaultTags).length === 0) {
+      const _defaultTags = defaultTags(node.loc);
+      if (Object.keys(_defaultTags).length === 0) {
         enterSelectMode(node);
         return;
       }
       var tags = Object.assign({}, node.tags);
-      for (var key in defaultTags) {
-        tags[key] = defaultTags[key];
+      for (var key in _defaultTags) {
+        tags[key] = _defaultTags[key];
       }
       context.perform(
         actionChangeTags(node.id, tags),
@@ -67006,7 +69679,10 @@ ${content}</tr>
       icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "undo" : "redo")
     }];
     function editable() {
-      return context.mode() && context.mode().id !== "save" && context.map().editableDataEnabled(true);
+      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(d) {
@@ -67433,21 +70109,21 @@ ${content}</tr>
         var item = select_default2(this).select("label");
         var span = item.select("span");
         var placement = i2 < nodes.length / 2 ? "bottom" : "top";
-        var description = d.description();
+        var hasDescription = d.hasDescription();
         var isOverflowing = span.property("clientWidth") !== span.property("scrollWidth");
         item.call(uiTooltip().destroyAny);
         if (d.id === previousBackgroundID()) {
           item.call(
             uiTooltip().placement(placement).title(() => _t.append("background.switch")).keys([uiCmd("\u2318" + _t("background.key"))])
           );
-        } else if (description || isOverflowing) {
+        } else if (hasDescription || isOverflowing) {
           item.call(
-            uiTooltip().placement(placement).title(() => description || d.label())
+            uiTooltip().placement(placement).title(() => hasDescription ? d.description() : d.label())
           );
         }
       });
     }
-    function drawListItems(layerList, type3, change, filter2) {
+    function drawListItems(layerList, type2, change, filter2) {
       var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter2).sort(function(a, b) {
         return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : descending(a.area(), b.area()) || ascending(a.name(), b.name()) || 0;
       });
@@ -67461,7 +70137,7 @@ ${content}</tr>
         return d.best();
       });
       var label = enter.append("label");
-      label.append("input").attr("type", type3).attr("name", "background-layer").attr("value", function(d) {
+      label.append("input").attr("type", type2).attr("name", "background-layer").attr("value", function(d) {
         return d.id;
       }).on("change", change);
       label.append("span").each(function(d) {
@@ -67650,7 +70326,7 @@ ${content}</tr>
       _overlayList.call(updateLayerSelections);
       document.activeElement.blur();
     }
-    function drawListItems(layerList, type3, change, filter2) {
+    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(d) {
         return d.name();
@@ -67658,7 +70334,7 @@ ${content}</tr>
       layerLinks.exit().remove();
       var enter = layerLinks.enter().append("li");
       var label = enter.append("label");
-      label.append("input").attr("type", type3).attr("name", "layers").on("change", change);
+      label.append("input").attr("type", type2).attr("name", "layers").on("change", change);
       label.append("span").each(function(d) {
         d.label()(select_default2(this));
       });
@@ -67706,6 +70382,7 @@ ${content}</tr>
         "before_start",
         "open_source_h",
         "open_source",
+        "open_source_attribution",
         "open_source_help"
       ]],
       ["overview", [
@@ -68141,7 +70818,9 @@ ${content}</tr>
     function getOptions() {
       return {
         what: corePreferences("validate-what") || "edited",
+        // 'all', 'edited'
         where: corePreferences("validate-where") || "all"
+        // 'all', 'visible'
       };
     }
     function updateOptionValue(d3_event, d, val) {
@@ -68181,7 +70860,7 @@ ${content}</tr>
       container = container.merge(containerEnter);
       container.selectAll(".issue-rules-list").call(drawListItems, _ruleKeys, "checkbox", "rule", toggleRule, isRuleEnabled);
     }
-    function drawListItems(selection2, data, type3, name, change, active) {
+    function drawListItems(selection2, data, type2, name, change, active) {
       var items = selection2.selectAll("li").data(data);
       items.exit().remove();
       var enter = items.enter().append("li");
@@ -68193,7 +70872,7 @@ ${content}</tr>
         );
       }
       var label = enter.append("label");
-      label.append("input").attr("type", type3).attr("name", name).on("change", change);
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
       label.append("span").html(function(d) {
         var params = {};
         if (d === "unsquare_way") {
@@ -68223,7 +70902,7 @@ ${content}</tr>
     function changeSquare() {
       var input = select_default2(this);
       var degStr = utilGetSetValue(input).trim();
-      var degNum = parseFloat(degStr, 10);
+      var degNum = Number(degStr);
       if (!isFinite(degNum)) {
         degNum = DEFAULTSQUARE;
       } else if (degNum > MAXSQUARE) {
@@ -68288,12 +70967,12 @@ ${content}</tr>
     function setNoIssuesText(selection2) {
       var opts = getOptions();
       function checkForHiddenIssues(cases) {
-        for (var type3 in cases) {
-          var hiddenOpts = cases[type3];
+        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." + type3,
+              "issues.no_issues.hidden_issues." + type2,
               { count: hiddenIssues.length.toString() }
             ));
             return;
@@ -68673,7 +71352,7 @@ ${content}</tr>
       container = container.merge(containerEnter);
       container.selectAll(".layer-feature-list").call(drawListItems, _features, "checkbox", "feature", clickFeature, showsFeature);
     }
-    function drawListItems(selection2, data, type3, name, change, active) {
+    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(
@@ -68690,7 +71369,7 @@ ${content}</tr>
         }).placement("top")
       );
       var label = enter.append("label");
-      label.append("input").attr("type", type3).attr("name", name).on("change", change);
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
       label.append("span").html(function(d) {
         return _t.html(name + "." + d + ".description");
       });
@@ -68725,7 +71404,7 @@ ${content}</tr>
         return context.surface().classed("highlight-edited");
       });
     }
-    function drawListItems(selection2, data, type3, name, change, active) {
+    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(
@@ -68739,952 +71418,1765 @@ ${content}</tr>
         }).placement("top")
       );
       var label = enter.append("label");
-      label.append("input").attr("type", type3).attr("name", name).on("change", change);
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
       label.append("span").html(function(d) {
         return _t.html(name + "." + d + ".description");
       });
-      items = items.merge(enter);
-      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
-    }
-    function isActiveFill(d) {
-      return context.map().activeAreaFill() === d;
-    }
-    function toggleHighlightEdited(d3_event) {
-      d3_event.preventDefault();
-      context.map().toggleHighlightEdited();
-    }
-    function setFill(d3_event, d) {
-      context.map().activeAreaFill(d);
-    }
-    context.map().on("changeHighlighting.ui_style, changeAreaFill.ui_style", section.reRender);
-    return section;
+      items = items.merge(enter);
+      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
+    }
+    function isActiveFill(d) {
+      return context.map().activeAreaFill() === d;
+    }
+    function toggleHighlightEdited(d3_event) {
+      d3_event.preventDefault();
+      context.map().toggleHighlightEdited();
+    }
+    function setFill(d3_event, d) {
+      context.map().activeAreaFill(d);
+    }
+    context.map().on("changeHighlighting.ui_style, changeAreaFill.ui_style", section.reRender);
+    return section;
+  }
+
+  // modules/ui/sections/photo_overlays.js
+  function uiSectionPhotoOverlays(context) {
+    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);
+    }
+    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) {
+        return obj.layer.supported();
+      });
+      function layerSupported(d) {
+        return d.layer && d.layer.supported();
+      }
+      function layerEnabled(d) {
+        return layerSupported(d) && d.layer.enabled();
+      }
+      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(d) {
+        var classes = "list-item-photos list-item-" + d.id;
+        if (d.id === "mapillary-signs" || d.id === "mapillary-map-features") {
+          classes += " indented";
+        }
+        return classes;
+      });
+      var labelEnter = liEnter.append("label").each(function(d) {
+        var titleID;
+        if (d.id === "mapillary-signs")
+          titleID = "mapillary.signs.tooltip";
+        else if (d.id === "mapillary")
+          titleID = "mapillary_images.tooltip";
+        else if (d.id === "kartaview")
+          titleID = "kartaview_images.tooltip";
+        else
+          titleID = d.id.replace(/-/g, "_") + ".tooltip";
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append(titleID)).placement("top")
+        );
+      });
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d) {
+        toggleLayer(d.id);
+      });
+      labelEnter.append("span").html(function(d) {
+        var id2 = d.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("checked", layerEnabled);
+    }
+    function drawPhotoTypeItems(selection2) {
+      var data = context.photos().allPhotoTypes();
+      function typeEnabled(d) {
+        return context.photos().showsPhotoType(d);
+      }
+      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(d) {
+        return "list-item-photo-types list-item-" + d;
+      });
+      var labelEnter = liEnter.append("label").each(function(d) {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("photo_overlays.photo_type." + d + ".tooltip")).placement("top")
+        );
+      });
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d) {
+        context.photos().togglePhotoType(d);
+      });
+      labelEnter.append("span").html(function(d) {
+        return _t.html("photo_overlays.photo_type." + d + ".title");
+      });
+      li.merge(liEnter).classed("active", typeEnabled).selectAll("input").property("checked", typeEnabled);
+    }
+    function drawDateFilter(selection2) {
+      var data = context.photos().dateFilters();
+      function filterEnabled(d) {
+        return context.photos().dateFilterValue(d);
+      }
+      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(d) {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("photo_overlays.date_filter." + d + ".tooltip")).placement("top")
+        );
+      });
+      labelEnter.append("span").each(function(d) {
+        _t.append("photo_overlays.date_filter." + d + ".title")(select_default2(this));
+      });
+      labelEnter.append("input").attr("type", "date").attr("class", "list-item-input").attr("placeholder", _t("units.year_month_day")).call(utilNoAuto).each(function(d) {
+        utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d) || "");
+      }).on("change", function(d3_event, d) {
+        var value = utilGetSetValue(select_default2(this)).trim();
+        context.photos().setDateFilter(d, value, true);
+        li.selectAll("input").each(function(d2) {
+          utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d2) || "");
+        });
+      });
+      li = li.merge(liEnter).classed("active", filterEnabled);
+    }
+    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;
+      }
+    }
+    function toggleLayer(which) {
+      setLayer(which, !showsLayer(which));
+    }
+    function showsLayer(which) {
+      var layer = layers.layer(which);
+      if (layer) {
+        return layer.enabled();
+      }
+      return false;
+    }
+    function setLayer(which, enabled) {
+      var layer = layers.layer(which);
+      if (layer) {
+        layer.enabled(enabled);
+      }
+    }
+    context.layers().on("change.uiSectionPhotoOverlays", section.reRender);
+    context.photos().on("change.uiSectionPhotoOverlays", section.reRender);
+    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();
+        });
+      }
+      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;
+        }
+      });
+      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));
+      }
+      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();
+        });
+      }
+      _initCounter++;
+      if (ui.hash.startWalkthrough) {
+        ui.hash.startWalkthrough = false;
+        context.container().call(uiIntro(context));
+      }
+      function pan(d) {
+        return function(d3_event) {
+          if (d3_event.shiftKey)
+            return;
+          if (context.container().select(".combobox").size())
+            return;
+          d3_event.preventDefault();
+          context.map().pan(d, 100);
+        };
+      }
+    }
+    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;
+    };
+    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);
+    };
+    ui.checkOverflow = function(selector, reset) {
+      if (reset) {
+        delete _needWidth[selector];
+      }
+      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);
+      }
+    };
+    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 {
+          showPane.style(side, "0px");
+        }
+      } 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();
+      }
+      operations.forEach(function(operation) {
+        if (operation.point)
+          operation.point(anchorPoint);
+      });
+      _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations);
+      context.map().supersurface.call(_editMenu);
+    };
+    ui.closeEditMenu = function() {
+      context.map().supersurface.select(".edit-menu").remove();
+    };
+    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);
+    });
+    return ui;
   }
 
-  // modules/ui/sections/photo_overlays.js
-  function uiSectionPhotoOverlays(context) {
-    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);
+  // modules/core/context.js
+  function coreContext() {
+    const dispatch10 = dispatch_default("enter", "exit", "change");
+    let context = utilRebind({}, dispatch10, "on");
+    let _deferred2 = /* @__PURE__ */ new Set();
+    context.version = package_default.version;
+    context.privacyVersion = "20201202";
+    context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
+    context.changeset = null;
+    let _defaultChangesetComment = context.initialHashParams.comment;
+    let _defaultChangesetSource = context.initialHashParams.source;
+    let _defaultChangesetHashtags = context.initialHashParams.hashtags;
+    context.defaultChangesetComment = function(val) {
+      if (!arguments.length)
+        return _defaultChangesetComment;
+      _defaultChangesetComment = val;
+      return context;
+    };
+    context.defaultChangesetSource = function(val) {
+      if (!arguments.length)
+        return _defaultChangesetSource;
+      _defaultChangesetSource = val;
+      return context;
+    };
+    context.defaultChangesetHashtags = function(val) {
+      if (!arguments.length)
+        return _defaultChangesetHashtags;
+      _defaultChangesetHashtags = val;
+      return context;
+    };
+    let _setsDocumentTitle = true;
+    context.setsDocumentTitle = function(val) {
+      if (!arguments.length)
+        return _setsDocumentTitle;
+      _setsDocumentTitle = val;
+      return context;
+    };
+    let _documentTitleBase = document.title;
+    context.documentTitleBase = function(val) {
+      if (!arguments.length)
+        return _documentTitleBase;
+      _documentTitleBase = val;
+      return context;
+    };
+    let _ui;
+    context.ui = () => _ui;
+    context.lastPointerType = () => _ui.lastPointerType();
+    let _keybinding = utilKeybinding("context");
+    context.keybinding = () => _keybinding;
+    select_default2(document).call(_keybinding);
+    let _connection = services.osm;
+    let _history;
+    let _validator;
+    let _uploader;
+    context.connection = () => _connection;
+    context.history = () => _history;
+    context.validator = () => _validator;
+    context.uploader = () => _uploader;
+    context.preauth = (options2) => {
+      if (_connection) {
+        _connection.switch(options2);
+      }
+      return context;
+    };
+    context.locale = function(locale2) {
+      if (!arguments.length)
+        return _mainLocalizer.localeCode();
+      _mainLocalizer.preferredLocaleCodes(locale2);
+      return context;
+    };
+    function afterLoad(cid, callback) {
+      return (err, result) => {
+        if (err) {
+          if (err.status === 400 || err.status === 401 || err.status === 403) {
+            if (_connection) {
+              _connection.logout();
+            }
+          }
+          if (typeof callback === "function") {
+            callback(err);
+          }
+          return;
+        } else if (_connection && _connection.getConnectionId() !== cid) {
+          if (typeof callback === "function") {
+            callback({ message: "Connection Switched", status: -1 });
+          }
+          return;
+        } else {
+          _history.merge(result.data, result.extent);
+          if (typeof callback === "function") {
+            callback(err, result);
+          }
+          return;
+        }
+      };
     }
-    function drawPhotoItems(selection2) {
-      var photoKeys = context.photos().overlayLayerIDs();
-      var photoLayers = layers.all().filter(function(obj) {
-        return photoKeys.indexOf(obj.id) !== -1;
+    context.loadTiles = (projection2, callback) => {
+      const handle = window.requestIdleCallback(() => {
+        _deferred2.delete(handle);
+        if (_connection && context.editableDataEnabled()) {
+          const cid = _connection.getConnectionId();
+          _connection.loadTiles(projection2, afterLoad(cid, callback));
+        }
       });
-      var data = photoLayers.filter(function(obj) {
-        return obj.layer.supported();
+      _deferred2.add(handle);
+    };
+    context.loadTileAtLoc = (loc, callback) => {
+      const handle = window.requestIdleCallback(() => {
+        _deferred2.delete(handle);
+        if (_connection && context.editableDataEnabled()) {
+          const cid = _connection.getConnectionId();
+          _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
+        }
       });
-      function layerSupported(d) {
-        return d.layer && d.layer.supported();
-      }
-      function layerEnabled(d) {
-        return layerSupported(d) && d.layer.enabled();
+      _deferred2.add(handle);
+    };
+    context.loadEntity = (entityID, callback) => {
+      if (_connection) {
+        const cid = _connection.getConnectionId();
+        _connection.loadEntity(entityID, afterLoad(cid, callback));
+        _connection.loadEntityRelations(entityID, afterLoad(cid, callback));
       }
-      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(d) {
-        var classes = "list-item-photos list-item-" + d.id;
-        if (d.id === "mapillary-signs" || d.id === "mapillary-map-features") {
-          classes += " indented";
+    };
+    context.zoomToEntity = (entityID, zoomTo) => {
+      context.loadEntity(entityID, (err, result) => {
+        if (err)
+          return;
+        if (zoomTo !== false) {
+          const entity = result.data.find((e) => e.id === entityID);
+          if (entity) {
+            _map.zoomTo(entity);
+          }
         }
-        return classes;
-      });
-      var labelEnter = liEnter.append("label").each(function(d) {
-        var titleID;
-        if (d.id === "mapillary-signs")
-          titleID = "mapillary.signs.tooltip";
-        else if (d.id === "mapillary")
-          titleID = "mapillary_images.tooltip";
-        else if (d.id === "kartaview")
-          titleID = "kartaview_images.tooltip";
-        else
-          titleID = d.id.replace(/-/g, "_") + ".tooltip";
-        select_default2(this).call(
-          uiTooltip().title(() => _t.append(titleID)).placement("top")
-        );
       });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d) {
-        toggleLayer(d.id);
+      _map.on("drawn.zoomToEntity", () => {
+        if (!context.hasEntity(entityID))
+          return;
+        _map.on("drawn.zoomToEntity", null);
+        context.on("enter.zoomToEntity", null);
+        context.enter(modeSelect(context, [entityID]));
       });
-      labelEnter.append("span").html(function(d) {
-        var id2 = d.id;
-        if (id2 === "mapillary-signs")
-          id2 = "photo_overlays.traffic_signs";
-        return _t.html(id2.replace(/-/g, "_") + ".title");
+      context.on("enter.zoomToEntity", () => {
+        if (_mode.id !== "browse") {
+          _map.on("drawn.zoomToEntity", null);
+          context.on("enter.zoomToEntity", null);
+        }
       });
-      li.merge(liEnter).classed("active", layerEnabled).selectAll("input").property("checked", layerEnabled);
-    }
-    function drawPhotoTypeItems(selection2) {
-      var data = context.photos().allPhotoTypes();
-      function typeEnabled(d) {
-        return context.photos().showsPhotoType(d);
+    };
+    let _minEditableZoom = 16;
+    context.minEditableZoom = function(val) {
+      if (!arguments.length)
+        return _minEditableZoom;
+      _minEditableZoom = val;
+      if (_connection) {
+        _connection.tileZoom(val);
       }
-      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(d) {
-        return "list-item-photo-types list-item-" + d;
-      });
-      var labelEnter = liEnter.append("label").each(function(d) {
-        select_default2(this).call(
-          uiTooltip().title(() => _t.append("photo_overlays.photo_type." + d + ".tooltip")).placement("top")
-        );
-      });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d) {
-        context.photos().togglePhotoType(d);
-      });
-      labelEnter.append("span").html(function(d) {
-        return _t.html("photo_overlays.photo_type." + d + ".title");
-      });
-      li.merge(liEnter).classed("active", typeEnabled).selectAll("input").property("checked", typeEnabled);
+      return context;
+    };
+    context.maxCharsForTagKey = () => 255;
+    context.maxCharsForTagValue = () => 255;
+    context.maxCharsForRelationRole = () => 255;
+    context.cleanTagKey = (val) => utilCleanOsmString(val, context.maxCharsForTagKey());
+    context.cleanTagValue = (val) => utilCleanOsmString(val, context.maxCharsForTagValue());
+    context.cleanRelationRole = (val) => utilCleanOsmString(val, context.maxCharsForRelationRole());
+    let _inIntro = false;
+    context.inIntro = function(val) {
+      if (!arguments.length)
+        return _inIntro;
+      _inIntro = val;
+      return context;
+    };
+    context.save = () => {
+      if (_inIntro || context.container().select(".modal").size())
+        return;
+      let canSave;
+      if (_mode && _mode.id === "save") {
+        canSave = false;
+        if (services.osm && services.osm.isChangesetInflight()) {
+          _history.clearSaved();
+          return;
+        }
+      } else {
+        canSave = context.selectedIDs().every((id2) => {
+          const entity = context.hasEntity(id2);
+          return entity && !entity.isDegenerate();
+        });
+      }
+      if (canSave) {
+        _history.save();
+      }
+      if (_history.hasChanges()) {
+        return _t("save.unsaved_changes");
+      }
+    };
+    context.debouncedSave = debounce_default(context.save, 350);
+    function withDebouncedSave(fn) {
+      return function() {
+        const result = fn.apply(_history, arguments);
+        context.debouncedSave();
+        return result;
+      };
     }
-    function drawDateFilter(selection2) {
-      var data = context.photos().dateFilters();
-      function filterEnabled(d) {
-        return context.photos().dateFilterValue(d);
+    context.hasEntity = (id2) => _history.graph().hasEntity(id2);
+    context.entity = (id2) => _history.graph().entity(id2);
+    let _mode;
+    context.mode = () => _mode;
+    context.enter = (newMode) => {
+      if (_mode) {
+        _mode.exit();
+        dispatch10.call("exit", this, _mode);
       }
-      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(d) {
-        select_default2(this).call(
-          uiTooltip().title(() => _t.append("photo_overlays.date_filter." + d + ".tooltip")).placement("top")
-        );
+      _mode = newMode;
+      _mode.enter();
+      dispatch10.call("enter", this, _mode);
+    };
+    context.selectedIDs = () => _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
+    context.activeID = () => _mode && _mode.activeID && _mode.activeID();
+    let _selectedNoteID;
+    context.selectedNoteID = function(noteID) {
+      if (!arguments.length)
+        return _selectedNoteID;
+      _selectedNoteID = noteID;
+      return context;
+    };
+    let _selectedErrorID;
+    context.selectedErrorID = function(errorID) {
+      if (!arguments.length)
+        return _selectedErrorID;
+      _selectedErrorID = errorID;
+      return context;
+    };
+    context.install = (behavior) => context.surface().call(behavior);
+    context.uninstall = (behavior) => context.surface().call(behavior.off);
+    let _copyGraph;
+    context.copyGraph = () => _copyGraph;
+    let _copyIDs = [];
+    context.copyIDs = function(val) {
+      if (!arguments.length)
+        return _copyIDs;
+      _copyIDs = val;
+      _copyGraph = _history.graph();
+      return context;
+    };
+    let _copyLonLat;
+    context.copyLonLat = function(val) {
+      if (!arguments.length)
+        return _copyLonLat;
+      _copyLonLat = val;
+      return context;
+    };
+    let _background;
+    context.background = () => _background;
+    let _features;
+    context.features = () => _features;
+    context.hasHiddenConnections = (id2) => {
+      const graph = _history.graph();
+      const entity = graph.entity(id2);
+      return _features.hasHiddenConnections(entity, graph);
+    };
+    let _photos;
+    context.photos = () => _photos;
+    let _map;
+    context.map = () => _map;
+    context.layers = () => _map.layers();
+    context.surface = () => _map.surface;
+    context.editableDataEnabled = () => _map.editableDataEnabled();
+    context.surfaceRect = () => _map.surface.node().getBoundingClientRect();
+    context.editable = () => {
+      const mode = context.mode();
+      if (!mode || mode.id === "save")
+        return false;
+      return _map.editableDataEnabled();
+    };
+    let _debugFlags = {
+      tile: false,
+      // tile boundaries
+      collision: false,
+      // label collision bounding boxes
+      imagery: false,
+      // imagery bounding polygons
+      target: false,
+      // touch targets
+      downloaded: false
+      // downloaded data from osm
+    };
+    context.debugFlags = () => _debugFlags;
+    context.getDebug = (flag) => flag && _debugFlags[flag];
+    context.setDebug = function(flag, val) {
+      if (arguments.length === 1)
+        val = true;
+      _debugFlags[flag] = val;
+      dispatch10.call("change");
+      return context;
+    };
+    let _container = select_default2(null);
+    context.container = function(val) {
+      if (!arguments.length)
+        return _container;
+      _container = val;
+      _container.classed("ideditor", true);
+      return context;
+    };
+    context.containerNode = function(val) {
+      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;
+      _embed = val;
+      return context;
+    };
+    let _assetPath = "";
+    context.assetPath = function(val) {
+      if (!arguments.length)
+        return _assetPath;
+      _assetPath = val;
+      _mainFileFetcher.assetPath(val);
+      return context;
+    };
+    let _assetMap = {};
+    context.assetMap = function(val) {
+      if (!arguments.length)
+        return _assetMap;
+      _assetMap = val;
+      _mainFileFetcher.assetMap(val);
+      return context;
+    };
+    context.asset = (val) => {
+      if (/^http(s)?:\/\//i.test(val))
+        return val;
+      const filename = _assetPath + val;
+      return _assetMap[filename] || filename;
+    };
+    context.imagePath = (val) => context.asset(`img/${val}`);
+    context.reset = context.flush = () => {
+      context.debouncedSave.cancel();
+      Array.from(_deferred2).forEach((handle) => {
+        window.cancelIdleCallback(handle);
+        _deferred2.delete(handle);
       });
-      labelEnter.append("span").each(function(d) {
-        _t.append("photo_overlays.date_filter." + d + ".title")(select_default2(this));
+      Object.values(services).forEach((service) => {
+        if (service && typeof service.reset === "function") {
+          service.reset(context);
+        }
       });
-      labelEnter.append("input").attr("type", "date").attr("class", "list-item-input").attr("placeholder", _t("units.year_month_day")).call(utilNoAuto).each(function(d) {
-        utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d) || "");
-      }).on("change", function(d3_event, d) {
-        var value = utilGetSetValue(select_default2(this)).trim();
-        context.photos().setDateFilter(d, value, true);
-        li.selectAll("input").each(function(d2) {
-          utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d2) || "");
+      context.changeset = null;
+      _validator.reset();
+      _features.reset();
+      _history.reset();
+      _uploader.reset();
+      context.container().select(".inspector-wrap *").remove();
+      return context;
+    };
+    context.projection = geoRawMercator();
+    context.curtainProjection = geoRawMercator();
+    context.init = () => {
+      instantiateInternal();
+      initializeDependents();
+      return context;
+      function instantiateInternal() {
+        _history = coreHistory(context);
+        context.graph = _history.graph;
+        context.pauseChangeDispatch = _history.pauseChangeDispatch;
+        context.resumeChangeDispatch = _history.resumeChangeDispatch;
+        context.perform = withDebouncedSave(_history.perform);
+        context.replace = withDebouncedSave(_history.replace);
+        context.pop = withDebouncedSave(_history.pop);
+        context.overwrite = withDebouncedSave(_history.overwrite);
+        context.undo = withDebouncedSave(_history.undo);
+        context.redo = withDebouncedSave(_history.redo);
+        _validator = coreValidator(context);
+        _uploader = coreUploader(context);
+        _background = rendererBackground(context);
+        _features = rendererFeatures(context);
+        _map = rendererMap(context);
+        _photos = rendererPhotos(context);
+        _ui = uiInit(context);
+      }
+      function initializeDependents() {
+        if (context.initialHashParams.presets) {
+          _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(",")));
+        }
+        if (context.initialHashParams.locale) {
+          _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
+        }
+        _mainLocalizer.ensureLoaded();
+        _mainPresetIndex.ensureLoaded();
+        _background.ensureLoaded();
+        Object.values(services).forEach((service) => {
+          if (service && typeof service.init === "function") {
+            service.init();
+          }
         });
-      });
-      li = li.merge(liEnter).classed("active", filterEnabled);
-    }
-    function drawUsernameFilter(selection2) {
-      function filterEnabled() {
-        return context.photos().usernames();
+        _map.init();
+        _validator.init();
+        _features.init();
+        if (services.maprules && context.initialHashParams.maprules) {
+          json_default(context.initialHashParams.maprules).then((mapcss) => {
+            services.maprules.init();
+            mapcss.forEach((mapcssSelector) => services.maprules.addRule(mapcssSelector));
+          }).catch(() => {
+          });
+        }
+        if (!context.container().empty()) {
+          _ui.ensureLoaded().then(() => {
+            _background.init();
+            _photos.init();
+          });
+        }
       }
-      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")
-        );
+    };
+    return context;
+  }
+
+  // modules/services/nominatim.js
+  var apibase = nominatimApiUrl;
+  var _inflight = {};
+  var _nominatimCache;
+  var nominatim_default = {
+    init: function() {
+      _inflight = {};
+      _nominatimCache = new import_rbush7.default();
+    },
+    reset: function() {
+      Object.values(_inflight).forEach(function(controller) {
+        controller.abort();
       });
-      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);
+      _inflight = {};
+      _nominatimCache = new import_rbush7.default();
+    },
+    countryCode: function(location, callback) {
+      this.reverse(location, function(err, result) {
+        if (err) {
+          return callback(err);
+        } else if (result.address) {
+          return callback(null, result.address.country_code);
+        } else {
+          return callback("Unable to geocode", null);
+        }
       });
-      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();
-      }
-      return false;
-    }
-    function setLayer(which, enabled) {
-      var layer = layers.layer(which);
-      if (layer) {
-        layer.enabled(enabled);
+    },
+    reverse: function(loc, callback) {
+      var cached = _nominatimCache.search(
+        { minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1] }
+      );
+      if (cached.length > 0) {
+        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;
+      var controller = new AbortController();
+      _inflight[url] = controller;
+      json_default(url, {
+        signal: controller.signal,
+        headers: {
+          "Accept-Language": _mainLocalizer.localeCodes().join(",")
+        }
+      }).then(function(result) {
+        delete _inflight[url];
+        if (result && result.error) {
+          throw new Error(result.error);
+        }
+        var extent = geoExtent(loc).padByMeters(200);
+        _nominatimCache.insert(Object.assign(extent.bbox(), { data: result }));
+        if (callback)
+          callback(null, result);
+      }).catch(function(err) {
+        delete _inflight[url];
+        if (err.name === "AbortError")
+          return;
+        if (callback)
+          callback(err.message);
+      });
+    },
+    search: function(val, callback) {
+      var searchVal = encodeURIComponent(val);
+      var url = apibase + "search/" + searchVal + "?limit=10&format=json";
+      if (_inflight[url])
+        return;
+      var controller = new AbortController();
+      _inflight[url] = controller;
+      json_default(url, {
+        signal: controller.signal,
+        headers: {
+          "Accept-Language": _mainLocalizer.localeCodes().join(",")
+        }
+      }).then(function(result) {
+        delete _inflight[url];
+        if (result && result.error) {
+          throw new Error(result.error);
+        }
+        if (callback)
+          callback(null, result);
+      }).catch(function(err) {
+        delete _inflight[url];
+        if (err.name === "AbortError")
+          return;
+        if (callback)
+          callback(err.message);
+      });
     }
-    context.layers().on("change.uiSectionPhotoOverlays", section.reRender);
-    context.photos().on("change.uiSectionPhotoOverlays", section.reRender);
-    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;
+  // node_modules/name-suggestion-index/lib/matcher.js
+  var import_which_polygon4 = __toESM(require_which_polygon(), 1);
+
+  // node_modules/name-suggestion-index/lib/simplify.js
+  var import_diacritics3 = __toESM(require_diacritics(), 1);
+  function simplify2(str2) {
+    if (typeof str2 !== "string")
+      return "";
+    return import_diacritics3.default.remove(
+      str2.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()
+    );
   }
 
-  // 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;
-  }
+  // node_modules/name-suggestion-index/config/matchGroups.json
+  var matchGroups_default = {
+    matchGroups: {
+      adult_gaming_centre: [
+        "amenity/casino",
+        "amenity/gambling",
+        "leisure/adult_gaming_centre"
+      ],
+      beauty: [
+        "shop/beauty",
+        "shop/hairdresser_supply"
+      ],
+      bed: [
+        "shop/bed",
+        "shop/furniture"
+      ],
+      beverages: [
+        "shop/alcohol",
+        "shop/beer",
+        "shop/beverages",
+        "shop/kiosk",
+        "shop/wine"
+      ],
+      camping: [
+        "tourism/camp_site",
+        "tourism/caravan_site"
+      ],
+      car_parts: [
+        "shop/car_parts",
+        "shop/car_repair",
+        "shop/tires",
+        "shop/tyres"
+      ],
+      clinic: [
+        "amenity/clinic",
+        "amenity/doctors",
+        "healthcare/clinic",
+        "healthcare/laboratory",
+        "healthcare/physiotherapist",
+        "healthcare/sample_collection",
+        "healthcare/dialysis"
+      ],
+      convenience: [
+        "shop/beauty",
+        "shop/chemist",
+        "shop/convenience",
+        "shop/cosmetics",
+        "shop/grocery",
+        "shop/kiosk",
+        "shop/newsagent",
+        "shop/perfumery"
+      ],
+      coworking: [
+        "amenity/coworking_space",
+        "office/coworking",
+        "office/coworking_space"
+      ],
+      dentist: [
+        "amenity/dentist",
+        "amenity/doctors",
+        "healthcare/dentist"
+      ],
+      electronics: [
+        "office/telecommunication",
+        "shop/computer",
+        "shop/electronics",
+        "shop/hifi",
+        "shop/kiosk",
+        "shop/mobile",
+        "shop/mobile_phone",
+        "shop/telecommunication"
+      ],
+      fabric: [
+        "shop/fabric",
+        "shop/haberdashery",
+        "shop/sewing"
+      ],
+      fashion: [
+        "shop/accessories",
+        "shop/bag",
+        "shop/boutique",
+        "shop/clothes",
+        "shop/department_store",
+        "shop/fashion",
+        "shop/fashion_accessories",
+        "shop/sports",
+        "shop/shoes"
+      ],
+      financial: [
+        "amenity/bank",
+        "office/accountant",
+        "office/financial",
+        "office/financial_advisor",
+        "office/tax_advisor",
+        "shop/tax"
+      ],
+      fitness: [
+        "leisure/fitness_centre",
+        "leisure/fitness_center",
+        "leisure/sports_centre",
+        "leisure/sports_center"
+      ],
+      food: [
+        "amenity/bar",
+        "amenity/cafe",
+        "amenity/fast_food",
+        "amenity/ice_cream",
+        "amenity/pub",
+        "amenity/restaurant",
+        "shop/bakery",
+        "shop/candy",
+        "shop/chocolate",
+        "shop/coffee",
+        "shop/confectionary",
+        "shop/confectionery",
+        "shop/food",
+        "shop/kiosk",
+        "shop/ice_cream",
+        "shop/pastry",
+        "shop/tea"
+      ],
+      fuel: [
+        "amenity/fuel",
+        "shop/gas",
+        "shop/convenience;gas",
+        "shop/gas;convenience"
+      ],
+      gift: [
+        "shop/gift",
+        "shop/card",
+        "shop/cards",
+        "shop/kiosk",
+        "shop/stationery"
+      ],
+      hardware: [
+        "shop/bathroom_furnishing",
+        "shop/carpet",
+        "shop/diy",
+        "shop/doityourself",
+        "shop/doors",
+        "shop/electrical",
+        "shop/flooring",
+        "shop/hardware",
+        "shop/hardware_store",
+        "shop/power_tools",
+        "shop/tool_hire",
+        "shop/tools",
+        "shop/trade"
+      ],
+      health_food: [
+        "shop/health",
+        "shop/health_food",
+        "shop/herbalist",
+        "shop/nutrition_supplements"
+      ],
+      hobby: [
+        "shop/electronics",
+        "shop/hobby",
+        "shop/books",
+        "shop/games",
+        "shop/collector",
+        "shop/toys",
+        "shop/model",
+        "shop/video_games",
+        "shop/anime"
+      ],
+      hospital: [
+        "amenity/doctors",
+        "amenity/hospital",
+        "healthcare/hospital"
+      ],
+      houseware: [
+        "shop/houseware",
+        "shop/interior_decoration"
+      ],
+      lifeboat_station: [
+        "amenity/lifeboat_station",
+        "emergency/lifeboat_station",
+        "emergency/marine_rescue"
+      ],
+      lodging: [
+        "tourism/hotel",
+        "tourism/motel"
+      ],
+      money_transfer: [
+        "amenity/money_transfer",
+        "shop/money_transfer"
+      ],
+      office_supplies: [
+        "shop/office_supplies",
+        "shop/stationary",
+        "shop/stationery"
+      ],
+      outdoor: [
+        "shop/clothes",
+        "shop/outdoor",
+        "shop/sports"
+      ],
+      parcel_locker: [
+        "amenity/parcel_locker",
+        "amenity/vending_machine"
+      ],
+      pharmacy: [
+        "amenity/doctors",
+        "amenity/pharmacy",
+        "healthcare/pharmacy"
+      ],
+      playground: [
+        "amenity/theme_park",
+        "leisure/amusement_arcade",
+        "leisure/playground"
+      ],
+      rental: [
+        "amenity/bicycle_rental",
+        "amenity/boat_rental",
+        "amenity/car_rental",
+        "amenity/truck_rental",
+        "amenity/vehicle_rental",
+        "shop/kiosk",
+        "shop/rental"
+      ],
+      school: [
+        "amenity/childcare",
+        "amenity/college",
+        "amenity/kindergarten",
+        "amenity/language_school",
+        "amenity/prep_school",
+        "amenity/school",
+        "amenity/university"
+      ],
+      storage: [
+        "shop/storage_units",
+        "shop/storage_rental"
+      ],
+      substation: [
+        "power/station",
+        "power/substation",
+        "power/sub_station"
+      ],
+      supermarket: [
+        "shop/food",
+        "shop/frozen_food",
+        "shop/greengrocer",
+        "shop/grocery",
+        "shop/supermarket",
+        "shop/wholesale"
+      ],
+      variety_store: [
+        "shop/variety_store",
+        "shop/discount",
+        "shop/convenience"
+      ],
+      vending: [
+        "amenity/vending_machine",
+        "shop/kiosk",
+        "shop/vending_machine"
+      ],
+      weight_loss: [
+        "amenity/clinic",
+        "amenity/doctors",
+        "amenity/weight_clinic",
+        "healthcare/counselling",
+        "leisure/fitness_centre",
+        "office/therapist",
+        "shop/beauty",
+        "shop/diet",
+        "shop/food",
+        "shop/health_food",
+        "shop/herbalist",
+        "shop/nutrition",
+        "shop/nutrition_supplements",
+        "shop/weight_loss"
+      ],
+      wholesale: [
+        "shop/wholesale",
+        "shop/supermarket",
+        "shop/department_store"
+      ]
+    }
+  };
+
+  // node_modules/name-suggestion-index/config/genericWords.json
+  var genericWords_default = {
+    genericWords: [
+      "^(barn|bazaa?r|bench|bou?tique|building|casa|church)$",
+      "^(baseball|basketball|football|soccer|softball|tennis(halle)?)\\s?(field|court)?$",
+      "^(club|green|out|ware)\\s?house$",
+      "^(driveway|el \xE1rbol|fountain|generic|golf|government|graveyard)$",
+      "^(fixme|n\\s?\\/?\\s?a|name|no\\s?name|none|null|temporary|test|unknown)$",
+      "^(hofladen|librairie|magazine?|maison)$",
+      "^(mobile home|skate)?\\s?park$",
+      "^(obuwie|pond|pool|sale|shops?|sklep|stores?)$",
+      "^\\?+$",
+      "^private$",
+      "^tattoo( studio)?$",
+      "^windmill$",
+      "^\u0446\u0435\u0440\u043A\u043E\u0432\u043D\u0430\u044F( \u043B\u0430\u0432\u043A\u0430)?$"
+    ]
+  };
 
-  // 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 && (node.nodeName === "INPUT" || node.nodeName === "LABEL" || node.nodeName === "A");
-        });
-        if (isOkayTarget)
-          return;
-        d3_event.preventDefault();
-      });
-      var detected = utilDetect();
-      if ("GestureEvent" in window && !detected.isMobileWebKit) {
-        container.on("gesturestart.ui gesturechange.ui gestureend.ui", function(d3_event) {
-          d3_event.preventDefault();
-        });
-      }
-      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;
-        }
-      });
-      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.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));
-      }
-      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();
+  // node_modules/name-suggestion-index/config/trees.json
+  var trees_default = {
+    trees: {
+      brands: {
+        emoji: "\u{1F354}",
+        mainTag: "brand:wikidata",
+        sourceTags: ["brand", "name"],
+        nameTags: {
+          primary: "^(name|name:\\w+)$",
+          alternate: "^(brand|brand:\\w+|operator|operator:\\w+|\\w+_name|\\w+_name:\\w+)$"
         }
-        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);
+      },
+      flags: {
+        emoji: "\u{1F6A9}",
+        mainTag: "flag:wikidata",
+        nameTags: {
+          primary: "^(flag:name|flag:name:\\w+)$",
+          alternate: "^(country|country:\\w+|flag|flag:\\w+|subject|subject:\\w+)$"
         }
-      }).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));
-          }
+      },
+      operators: {
+        emoji: "\u{1F4BC}",
+        mainTag: "operator:wikidata",
+        sourceTags: ["operator"],
+        nameTags: {
+          primary: "^(name|name:\\w+|operator|operator:\\w+)$",
+          alternate: "^(brand|brand:\\w+|\\w+_name|\\w+_name:\\w+)$"
         }
-      }).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));
+      },
+      transit: {
+        emoji: "\u{1F687}",
+        mainTag: "network:wikidata",
+        sourceTags: ["network"],
+        nameTags: {
+          primary: "^network$",
+          alternate: "^(operator|operator:\\w+|network:\\w+|\\w+_name|\\w+_name:\\w+)$"
         }
-        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();
-        });
-      }
-      _initCounter++;
-      if (ui.hash.startWalkthrough) {
-        ui.hash.startWalkthrough = false;
-        context.container().call(uiIntro(context));
-      }
-      function pan(d) {
-        return function(d3_event) {
-          if (d3_event.shiftKey)
-            return;
-          if (context.container().select(".combobox").size())
-            return;
-          d3_event.preventDefault();
-          context.map().pan(d, 100);
-        };
       }
     }
-    let ui = {};
-    let _loadPromise;
-    ui.ensureLoaded = () => {
-      if (_loadPromise)
-        return _loadPromise;
-      return _loadPromise = Promise.all([
-        _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;
-    };
-    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);
-    };
-    ui.checkOverflow = function(selector, reset) {
-      if (reset) {
-        delete _needWidth[selector];
-      }
-      var selection2 = context.container().select(selector);
-      if (selection2.empty())
+  };
+
+  // node_modules/name-suggestion-index/lib/matcher.js
+  var matchGroups = matchGroups_default.matchGroups;
+  var trees = trees_default.trees;
+  var Matcher = class {
+    //
+    // `constructor`
+    // initialize the genericWords regexes
+    constructor() {
+      this.matchIndex = void 0;
+      this.genericWords = /* @__PURE__ */ new Map();
+      (genericWords_default.genericWords || []).forEach((s) => this.genericWords.set(s, new RegExp(s, "i")));
+      this.itemLocation = void 0;
+      this.locationSets = void 0;
+      this.locationIndex = void 0;
+      this.warnings = [];
+    }
+    //
+    // `buildMatchIndex()`
+    // Call this to prepare the matcher for use
+    //
+    // `data` needs to be an Object indexed on a 'tree/key/value' path.
+    // (e.g. cache filled by `fileTree.read` or data found in `dist/nsi.json`)
+    // {
+    //    'brands/amenity/bank': { properties: {}, items: [ {}, {}, … ] },
+    //    'brands/amenity/bar':  { properties: {}, items: [ {}, {}, … ] },
+    //    …
+    // }
+    //
+    buildMatchIndex(data) {
+      const that = this;
+      if (that.matchIndex)
         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);
-      }
-    };
-    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 {
-          showPane.style(side, "0px");
+      that.matchIndex = /* @__PURE__ */ new Map();
+      const seenTree = /* @__PURE__ */ new Map();
+      Object.keys(data).forEach((tkv) => {
+        const category = data[tkv];
+        const parts = tkv.split("/", 3);
+        const t = parts[0];
+        const k = parts[1];
+        const v = parts[2];
+        const thiskv = `${k}/${v}`;
+        const tree = trees[t];
+        let branch = that.matchIndex.get(thiskv);
+        if (!branch) {
+          branch = {
+            primary: /* @__PURE__ */ new Map(),
+            alternate: /* @__PURE__ */ new Map(),
+            excludeGeneric: /* @__PURE__ */ new Map(),
+            excludeNamed: /* @__PURE__ */ new Map()
+          };
+          that.matchIndex.set(thiskv, branch);
         }
-      } 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);
+        const properties = category.properties || {};
+        const exclude = properties.exclude || {};
+        (exclude.generic || []).forEach((s) => branch.excludeGeneric.set(s, new RegExp(s, "i")));
+        (exclude.named || []).forEach((s) => branch.excludeNamed.set(s, new RegExp(s, "i")));
+        const excludeRegexes = [...branch.excludeGeneric.values(), ...branch.excludeNamed.values()];
+        let items = category.items;
+        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 skipGenericKV = skipGenericKVMatches(t, k, v);
+        const genericKV = /* @__PURE__ */ new Set([`${k}/yes`, `building/yes`]);
+        const matchGroupKV = /* @__PURE__ */ new Set();
+        Object.values(matchGroups).forEach((matchGroup) => {
+          const inGroup = matchGroup.some((otherkv) => otherkv === thiskv);
+          if (!inGroup)
+            return;
+          matchGroup.forEach((otherkv) => {
+            if (otherkv === thiskv)
+              return;
+            matchGroupKV.add(otherkv);
+            const otherk = otherkv.split("/", 2)[0];
+            genericKV.add(`${otherk}/yes`);
+          });
         });
-      }
-    };
-    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();
-      }
-      operations.forEach(function(operation) {
-        if (operation.point)
-          operation.point(anchorPoint);
-      });
-      _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations);
-      context.map().supersurface.call(_editMenu);
-    };
-    ui.closeEditMenu = function() {
-      context.map().supersurface.select(".edit-menu").remove();
-    };
-    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);
-    });
-    return ui;
-  }
-
-  // modules/core/context.js
-  function coreContext() {
-    const dispatch10 = dispatch_default("enter", "exit", "change");
-    let context = utilRebind({}, dispatch10, "on");
-    let _deferred2 = /* @__PURE__ */ new Set();
-    context.version = "2.22.0";
-    context.privacyVersion = "20201202";
-    context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
-    context.changeset = null;
-    let _defaultChangesetComment = context.initialHashParams.comment;
-    let _defaultChangesetSource = context.initialHashParams.source;
-    let _defaultChangesetHashtags = context.initialHashParams.hashtags;
-    context.defaultChangesetComment = function(val) {
-      if (!arguments.length)
-        return _defaultChangesetComment;
-      _defaultChangesetComment = val;
-      return context;
-    };
-    context.defaultChangesetSource = function(val) {
-      if (!arguments.length)
-        return _defaultChangesetSource;
-      _defaultChangesetSource = val;
-      return context;
-    };
-    context.defaultChangesetHashtags = function(val) {
-      if (!arguments.length)
-        return _defaultChangesetHashtags;
-      _defaultChangesetHashtags = val;
-      return context;
-    };
-    let _setsDocumentTitle = true;
-    context.setsDocumentTitle = function(val) {
-      if (!arguments.length)
-        return _setsDocumentTitle;
-      _setsDocumentTitle = val;
-      return context;
-    };
-    let _documentTitleBase = document.title;
-    context.documentTitleBase = function(val) {
-      if (!arguments.length)
-        return _documentTitleBase;
-      _documentTitleBase = val;
-      return context;
-    };
-    let _ui;
-    context.ui = () => _ui;
-    context.lastPointerType = () => _ui.lastPointerType();
-    let _keybinding = utilKeybinding("context");
-    context.keybinding = () => _keybinding;
-    select_default2(document).call(_keybinding);
-    let _connection = services.osm;
-    let _history;
-    let _validator;
-    let _uploader;
-    context.connection = () => _connection;
-    context.history = () => _history;
-    context.validator = () => _validator;
-    context.uploader = () => _uploader;
-    context.preauth = (options2) => {
-      if (_connection) {
-        _connection.switch(options2);
-      }
-      return context;
-    };
-    let _apiConnections;
-    context.apiConnections = function(val) {
-      if (!arguments.length)
-        return _apiConnections;
-      _apiConnections = val;
-      return context;
-    };
-    context.locale = function(locale2) {
-      if (!arguments.length)
-        return _mainLocalizer.localeCode();
-      _mainLocalizer.preferredLocaleCodes(locale2);
-      return context;
-    };
-    function afterLoad(cid, callback) {
-      return (err, result) => {
-        if (err) {
-          if (err.status === 400 || err.status === 401 || err.status === 403) {
-            if (_connection) {
-              _connection.logout();
-            }
-          }
-          if (typeof callback === "function") {
-            callback(err);
+        items.forEach((item) => {
+          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;
           }
-          return;
-        } else if (_connection && _connection.getConnectionId() !== cid) {
-          if (typeof callback === "function") {
-            callback({ message: "Connection Switched", status: -1 });
+          let kvTags = [`${thiskv}`].concat(item.matchTags || []);
+          if (!skipGenericKV) {
+            kvTags = kvTags.concat(Array.from(genericKV));
           }
-          return;
-        } else {
-          _history.merge(result.data, result.extent);
-          if (typeof callback === "function") {
-            callback(err, result);
+          Object.keys(item.tags).forEach((osmkey) => {
+            if (notName.test(osmkey))
+              return;
+            const osmvalue = item.tags[osmkey];
+            if (!osmvalue || excludeRegexes.some((regex) => regex.test(osmvalue)))
+              return;
+            if (primaryName.test(osmkey)) {
+              kvTags.forEach((kv) => insertName("primary", t, kv, simplify2(osmvalue), item.id));
+            } else if (alternateName.test(osmkey)) {
+              kvTags.forEach((kv) => insertName("alternate", t, kv, simplify2(osmvalue), item.id));
+            }
+          });
+          let keepMatchNames = /* @__PURE__ */ new Set();
+          (item.matchNames || []).forEach((matchName) => {
+            const nsimple = simplify2(matchName);
+            kvTags.forEach((kv) => {
+              const branch2 = that.matchIndex.get(kv);
+              const primaryLeaf = branch2 && branch2.primary.get(nsimple);
+              const alternateLeaf = branch2 && branch2.alternate.get(nsimple);
+              const inPrimary = primaryLeaf && primaryLeaf.has(item.id);
+              const inAlternate = alternateLeaf && alternateLeaf.has(item.id);
+              if (!inPrimary && !inAlternate) {
+                insertName("alternate", t, kv, nsimple, item.id);
+                keepMatchNames.add(matchName);
+              }
+            });
+          });
+          if (keepMatchNames.size) {
+            item.matchNames = Array.from(keepMatchNames);
+          } else {
+            delete item.matchNames;
           }
+        });
+      });
+      function insertName(which, t, kv, nsimple, itemID) {
+        if (!nsimple) {
+          that.warnings.push(`Warning: skipping empty ${which} name for item ${t}/${kv}: ${itemID}`);
           return;
         }
-      };
-    }
-    context.loadTiles = (projection2, callback) => {
-      const handle = window.requestIdleCallback(() => {
-        _deferred2.delete(handle);
-        if (_connection && context.editableDataEnabled()) {
-          const cid = _connection.getConnectionId();
-          _connection.loadTiles(projection2, afterLoad(cid, callback));
+        let branch = that.matchIndex.get(kv);
+        if (!branch) {
+          branch = {
+            primary: /* @__PURE__ */ new Map(),
+            alternate: /* @__PURE__ */ new Map(),
+            excludeGeneric: /* @__PURE__ */ new Map(),
+            excludeNamed: /* @__PURE__ */ new Map()
+          };
+          that.matchIndex.set(kv, branch);
         }
-      });
-      _deferred2.add(handle);
-    };
-    context.loadTileAtLoc = (loc, callback) => {
-      const handle = window.requestIdleCallback(() => {
-        _deferred2.delete(handle);
-        if (_connection && context.editableDataEnabled()) {
-          const cid = _connection.getConnectionId();
-          _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
+        let leaf = branch[which].get(nsimple);
+        if (!leaf) {
+          leaf = /* @__PURE__ */ new Set();
+          branch[which].set(nsimple, leaf);
         }
-      });
-      _deferred2.add(handle);
-    };
-    context.loadEntity = (entityID, callback) => {
-      if (_connection) {
-        const cid = _connection.getConnectionId();
-        _connection.loadEntity(entityID, afterLoad(cid, callback));
-        _connection.loadEntityRelations(entityID, afterLoad(cid, callback));
-      }
-    };
-    context.zoomToEntity = (entityID, zoomTo) => {
-      context.loadEntity(entityID, (err, result) => {
-        if (err)
-          return;
-        if (zoomTo !== false) {
-          const entity = result.data.find((e) => e.id === entityID);
-          if (entity) {
-            _map.zoomTo(entity);
+        leaf.add(itemID);
+        if (!/yes$/.test(kv)) {
+          const kvnsimple = `${kv}/${nsimple}`;
+          const existing = seenTree.get(kvnsimple);
+          if (existing && existing !== t) {
+            const items = Array.from(leaf);
+            that.warnings.push(`Duplicate cache key "${kvnsimple}" in trees "${t}" and "${existing}", check items: ${items}`);
+            return;
           }
+          seenTree.set(kvnsimple, t);
         }
-      });
-      _map.on("drawn.zoomToEntity", () => {
-        if (!context.hasEntity(entityID))
-          return;
-        _map.on("drawn.zoomToEntity", null);
-        context.on("enter.zoomToEntity", null);
-        context.enter(modeSelect(context, [entityID]));
-      });
-      context.on("enter.zoomToEntity", () => {
-        if (_mode.id !== "browse") {
-          _map.on("drawn.zoomToEntity", null);
-          context.on("enter.zoomToEntity", null);
-        }
-      });
-    };
-    let _minEditableZoom = 16;
-    context.minEditableZoom = function(val) {
-      if (!arguments.length)
-        return _minEditableZoom;
-      _minEditableZoom = val;
-      if (_connection) {
-        _connection.tileZoom(val);
       }
-      return context;
-    };
-    context.maxCharsForTagKey = () => 255;
-    context.maxCharsForTagValue = () => 255;
-    context.maxCharsForRelationRole = () => 255;
-    function cleanOsmString(val, maxChars) {
-      if (val === void 0 || val === null) {
-        val = "";
-      } else {
-        val = val.toString();
+      function skipGenericKVMatches(t, k, v) {
+        return t === "flags" || t === "transit" || k === "landuse" || v === "atm" || v === "bicycle_parking" || v === "car_sharing" || v === "caravan_site" || v === "charging_station" || v === "dog_park" || v === "parking" || v === "phone" || v === "playground" || v === "post_box" || v === "public_bookcase" || v === "recycling" || v === "vending_machine";
       }
-      val = val.trim();
-      if (val.normalize)
-        val = val.normalize("NFC");
-      return utilUnicodeCharsTruncated(val, maxChars);
     }
-    context.cleanTagKey = (val) => cleanOsmString(val, context.maxCharsForTagKey());
-    context.cleanTagValue = (val) => cleanOsmString(val, context.maxCharsForTagValue());
-    context.cleanRelationRole = (val) => cleanOsmString(val, context.maxCharsForRelationRole());
-    let _inIntro = false;
-    context.inIntro = function(val) {
-      if (!arguments.length)
-        return _inIntro;
-      _inIntro = val;
-      return context;
-    };
-    context.save = () => {
-      if (_inIntro || context.container().select(".modal").size())
+    //
+    // `buildLocationIndex()`
+    // Call this to prepare a which-polygon location index.
+    // This *resolves* all the locationSets into GeoJSON, which takes some time.
+    // You can skip this step if you don't care about matching within a location.
+    //
+    // `data` needs to be an Object indexed on a 'tree/key/value' path.
+    // (e.g. cache filled by `fileTree.read` or data found in `dist/nsi.json`)
+    // {
+    //    'brands/amenity/bank': { properties: {}, items: [ {}, {}, … ] },
+    //    'brands/amenity/bar':  { properties: {}, items: [ {}, {}, … ] },
+    //    …
+    // }
+    //
+    buildLocationIndex(data, loco) {
+      const that = this;
+      if (that.locationIndex)
         return;
-      let canSave;
-      if (_mode && _mode.id === "save") {
-        canSave = false;
-        if (services.osm && services.osm.isChangesetInflight()) {
-          _history.clearSaved();
+      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;
-        }
-      } else {
-        canSave = context.selectedIDs().every((id2) => {
-          const entity = context.hasEntity(id2);
-          return entity && !entity.isDegenerate();
+        items.forEach((item) => {
+          if (that.itemLocation.has(item.id))
+            return;
+          let resolved;
+          try {
+            resolved = loco.resolveLocationSet(item.locationSet);
+          } catch (err) {
+            console.warn(`buildLocationIndex: ${err.message}`);
+          }
+          if (!resolved || !resolved.id)
+            return;
+          that.itemLocation.set(item.id, resolved.id);
+          if (that.locationSets.has(resolved.id))
+            return;
+          let feature3 = _cloneDeep2(resolved.feature);
+          feature3.id = resolved.id;
+          feature3.properties.id = resolved.id;
+          if (!feature3.geometry.coordinates.length || !feature3.properties.area) {
+            console.warn(`buildLocationIndex: locationSet ${resolved.id} for ${item.id} resolves to an empty feature:`);
+            console.warn(JSON.stringify(feature3));
+            return;
+          }
+          that.locationSets.set(resolved.id, feature3);
         });
+      });
+      that.locationIndex = (0, import_which_polygon4.default)({ type: "FeatureCollection", features: [...that.locationSets.values()] });
+      function _cloneDeep2(obj) {
+        return JSON.parse(JSON.stringify(obj));
       }
-      if (canSave) {
-        _history.save();
-      }
-      if (_history.hasChanges()) {
-        return _t("save.unsaved_changes");
-      }
-    };
-    context.debouncedSave = debounce_default(context.save, 350);
-    function withDebouncedSave(fn) {
-      return function() {
-        const result = fn.apply(_history, arguments);
-        context.debouncedSave();
-        return result;
-      };
     }
-    context.hasEntity = (id2) => _history.graph().hasEntity(id2);
-    context.entity = (id2) => _history.graph().entity(id2);
-    let _mode;
-    context.mode = () => _mode;
-    context.enter = (newMode) => {
-      if (_mode) {
-        _mode.exit();
-        dispatch10.call("exit", this, _mode);
+    //
+    // `match()`
+    // Pass parts and return an Array of matches.
+    // `k` - key
+    // `v` - value
+    // `n` - namelike
+    // `loc` - optional - [lon,lat] location to search
+    //
+    // 1. If the [k,v,n] tuple matches a canonical item…
+    // Return an Array of match results.
+    // Each result will include the area in km² that the item is valid.
+    //
+    // Order of results:
+    // Primary ordering will be on the "match" column:
+    //   "primary" - where the query matches the `name` tag, followed by
+    //   "alternate" - where the query matches an alternate name tag (e.g. short_name, brand, operator, etc)
+    // Secondary ordering will be on the "area" column:
+    //   "area descending" if no location was provided, (worldwide before local)
+    //   "area ascending" if location was provided (local before worldwide)
+    //
+    // [
+    //   { match: 'primary',   itemID: String,  area: Number,  kv: String,  nsimple: String },
+    //   { match: 'primary',   itemID: String,  area: Number,  kv: String,  nsimple: String },
+    //   { match: 'alternate', itemID: String,  area: Number,  kv: String,  nsimple: String },
+    //   { match: 'alternate', itemID: String,  area: Number,  kv: String,  nsimple: String },
+    //   …
+    // ]
+    //
+    // -or-
+    //
+    // 2. If the [k,v,n] tuple matches an exclude pattern…
+    // Return an Array with a single exclude result, either
+    //
+    // [ { match: 'excludeGeneric', pattern: String,  kv: String } ]  // "generic" e.g. "Food Court"
+    //   or
+    // [ { match: 'excludeNamed', pattern: String,  kv: String } ]    // "named", e.g. "Kebabai"
+    //
+    // About results
+    //   "generic" - a generic word that is probably not really a name.
+    //     For these, iD should warn the user "Hey don't put 'food court' in the name tag".
+    //   "named" - a real name like "Kebabai" that is just common, but not a brand.
+    //     For these, iD should just let it be. We don't include these in NSI, but we don't want to nag users about it either.
+    //
+    // -or-
+    //
+    // 3. If the [k,v,n] tuple matches nothing of any kind, return `null`
+    //
+    //
+    match(k, v, n2, loc) {
+      const that = this;
+      if (!that.matchIndex) {
+        throw new Error("match:  matchIndex not built.");
       }
-      _mode = newMode;
-      _mode.enter();
-      dispatch10.call("enter", this, _mode);
-    };
-    context.selectedIDs = () => _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
-    context.activeID = () => _mode && _mode.activeID && _mode.activeID();
-    let _selectedNoteID;
-    context.selectedNoteID = function(noteID) {
-      if (!arguments.length)
-        return _selectedNoteID;
-      _selectedNoteID = noteID;
-      return context;
-    };
-    let _selectedErrorID;
-    context.selectedErrorID = function(errorID) {
-      if (!arguments.length)
-        return _selectedErrorID;
-      _selectedErrorID = errorID;
-      return context;
-    };
-    context.install = (behavior) => context.surface().call(behavior);
-    context.uninstall = (behavior) => context.surface().call(behavior.off);
-    let _copyGraph;
-    context.copyGraph = () => _copyGraph;
-    let _copyIDs = [];
-    context.copyIDs = function(val) {
-      if (!arguments.length)
-        return _copyIDs;
-      _copyIDs = val;
-      _copyGraph = _history.graph();
-      return context;
-    };
-    let _copyLonLat;
-    context.copyLonLat = function(val) {
-      if (!arguments.length)
-        return _copyLonLat;
-      _copyLonLat = val;
-      return context;
-    };
-    let _background;
-    context.background = () => _background;
-    let _features;
-    context.features = () => _features;
-    context.hasHiddenConnections = (id2) => {
-      const graph = _history.graph();
-      const entity = graph.entity(id2);
-      return _features.hasHiddenConnections(entity, graph);
-    };
-    let _photos;
-    context.photos = () => _photos;
-    let _map;
-    context.map = () => _map;
-    context.layers = () => _map.layers();
-    context.surface = () => _map.surface;
-    context.editableDataEnabled = () => _map.editableDataEnabled();
-    context.surfaceRect = () => _map.surface.node().getBoundingClientRect();
-    context.editable = () => {
-      const mode = context.mode();
-      if (!mode || mode.id === "save")
-        return false;
-      return _map.editableDataEnabled();
-    };
-    let _debugFlags = {
-      tile: false,
-      collision: false,
-      imagery: false,
-      target: false,
-      downloaded: false
-    };
-    context.debugFlags = () => _debugFlags;
-    context.getDebug = (flag) => flag && _debugFlags[flag];
-    context.setDebug = function(flag, val) {
-      if (arguments.length === 1)
-        val = true;
-      _debugFlags[flag] = val;
-      dispatch10.call("change");
-      return context;
-    };
-    let _container = select_default2(null);
-    context.container = function(val) {
-      if (!arguments.length)
-        return _container;
-      _container = val;
-      _container.classed("ideditor", true);
-      return context;
-    };
-    context.containerNode = function(val) {
-      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;
-      _embed = val;
-      return context;
-    };
-    let _assetPath = "";
-    context.assetPath = function(val) {
-      if (!arguments.length)
-        return _assetPath;
-      _assetPath = val;
-      _mainFileFetcher.assetPath(val);
-      return context;
-    };
-    let _assetMap = {};
-    context.assetMap = function(val) {
-      if (!arguments.length)
-        return _assetMap;
-      _assetMap = val;
-      _mainFileFetcher.assetMap(val);
-      return context;
-    };
-    context.asset = (val) => {
-      if (/^http(s)?:\/\//i.test(val))
-        return val;
-      const filename = _assetPath + val;
-      return _assetMap[filename] || filename;
-    };
-    context.imagePath = (val) => context.asset(`img/${val}`);
-    context.reset = context.flush = () => {
-      context.debouncedSave.cancel();
-      Array.from(_deferred2).forEach((handle) => {
-        window.cancelIdleCallback(handle);
-        _deferred2.delete(handle);
-      });
-      Object.values(services).forEach((service) => {
-        if (service && typeof service.reset === "function") {
-          service.reset(context);
-        }
-      });
-      context.changeset = null;
-      _validator.reset();
-      _features.reset();
-      _history.reset();
-      _uploader.reset();
-      context.container().select(".inspector-wrap *").remove();
-      return context;
-    };
-    context.projection = geoRawMercator();
-    context.curtainProjection = geoRawMercator();
-    context.init = () => {
-      instantiateInternal();
-      initializeDependents();
-      return context;
-      function instantiateInternal() {
-        _history = coreHistory(context);
-        context.graph = _history.graph;
-        context.pauseChangeDispatch = _history.pauseChangeDispatch;
-        context.resumeChangeDispatch = _history.resumeChangeDispatch;
-        context.perform = withDebouncedSave(_history.perform);
-        context.replace = withDebouncedSave(_history.replace);
-        context.pop = withDebouncedSave(_history.pop);
-        context.overwrite = withDebouncedSave(_history.overwrite);
-        context.undo = withDebouncedSave(_history.undo);
-        context.redo = withDebouncedSave(_history.redo);
-        _validator = coreValidator(context);
-        _uploader = coreUploader(context);
-        _background = rendererBackground(context);
-        _features = rendererFeatures(context);
-        _map = rendererMap(context);
-        _photos = rendererPhotos(context);
-        _ui = uiInit(context);
+      let matchLocations;
+      if (Array.isArray(loc) && that.locationIndex) {
+        matchLocations = that.locationIndex([loc[0], loc[1], loc[0], loc[1]], true);
       }
-      function initializeDependents() {
-        if (context.initialHashParams.presets) {
-          _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(",")));
+      const nsimple = simplify2(n2);
+      let seen = /* @__PURE__ */ new Set();
+      let results = [];
+      gatherResults("primary");
+      gatherResults("alternate");
+      if (results.length)
+        return results;
+      gatherResults("exclude");
+      return results.length ? results : null;
+      function gatherResults(which) {
+        const kv = `${k}/${v}`;
+        let didMatch = tryMatch(which, kv);
+        if (didMatch)
+          return;
+        for (let mg in matchGroups) {
+          const matchGroup = matchGroups[mg];
+          const inGroup = matchGroup.some((otherkv) => otherkv === kv);
+          if (!inGroup)
+            continue;
+          for (let i2 = 0; i2 < matchGroup.length; i2++) {
+            const otherkv = matchGroup[i2];
+            if (otherkv === kv)
+              continue;
+            didMatch = tryMatch(which, otherkv);
+            if (didMatch)
+              return;
+          }
         }
-        if (context.initialHashParams.locale) {
-          _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
+        if (which === "exclude") {
+          const regex = [...that.genericWords.values()].find((regex2) => regex2.test(n2));
+          if (regex) {
+            results.push({ match: "excludeGeneric", pattern: String(regex) });
+            return;
+          }
         }
-        _mainLocalizer.ensureLoaded();
-        _mainPresetIndex.ensureLoaded();
-        _background.ensureLoaded();
-        Object.values(services).forEach((service) => {
-          if (service && typeof service.init === "function") {
-            service.init();
+      }
+      function tryMatch(which, kv) {
+        const branch = that.matchIndex.get(kv);
+        if (!branch)
+          return;
+        if (which === "exclude") {
+          let regex = [...branch.excludeNamed.values()].find((regex2) => regex2.test(n2));
+          if (regex) {
+            results.push({ match: "excludeNamed", pattern: String(regex), kv });
+            return;
+          }
+          regex = [...branch.excludeGeneric.values()].find((regex2) => regex2.test(n2));
+          if (regex) {
+            results.push({ match: "excludeGeneric", pattern: String(regex), kv });
+            return;
+          }
+          return;
+        }
+        const leaf = branch[which].get(nsimple);
+        if (!leaf || !leaf.size)
+          return;
+        let hits = Array.from(leaf).map((itemID) => {
+          let area = Infinity;
+          if (that.itemLocation && that.locationSets) {
+            const location = that.locationSets.get(that.itemLocation.get(itemID));
+            area = location && location.properties.area || Infinity;
           }
+          return { match: which, itemID, area, kv, nsimple };
         });
-        _map.init();
-        _validator.init();
-        _features.init();
-        if (services.maprules && context.initialHashParams.maprules) {
-          json_default(context.initialHashParams.maprules).then((mapcss) => {
-            services.maprules.init();
-            mapcss.forEach((mapcssSelector) => services.maprules.addRule(mapcssSelector));
-          }).catch(() => {
-          });
+        let sortFn = byAreaDescending;
+        if (matchLocations) {
+          hits = hits.filter(isValidLocation);
+          sortFn = byAreaAscending;
         }
-        if (!context.container().empty()) {
-          _ui.ensureLoaded().then(() => {
-            _background.init();
-            _photos.init();
-          });
+        if (!hits.length)
+          return;
+        hits.sort(sortFn).forEach((hit) => {
+          if (seen.has(hit.itemID))
+            return;
+          seen.add(hit.itemID);
+          results.push(hit);
+        });
+        return true;
+        function isValidLocation(hit) {
+          if (!that.itemLocation)
+            return true;
+          return matchLocations.find((props) => props.id === that.itemLocation.get(hit.itemID));
+        }
+        function byAreaAscending(hitA, hitB) {
+          return hitA.area - hitB.area;
+        }
+        function byAreaDescending(hitA, hitB) {
+          return hitB.area - hitA.area;
         }
       }
-    };
-    return context;
-  }
+    }
+    //
+    // `getWarnings()`
+    // Return any warnings discovered when buiding the index.
+    // (currently this does nothing)
+    //
+    getWarnings() {
+      return this.warnings;
+    }
+  };
 
   // modules/services/nsi.js
+  var import_vparse2 = __toESM(require_vparse());
   var _nsiStatus = "loading";
   var _nsi = {};
   var buildingPreset = {
@@ -69702,14 +73194,15 @@ ${content}</tr>
     const nsiVersion = package_default.dependencies["name-suggestion-index"] || package_default.devDependencies["name-suggestion-index"];
     const v = (0, import_vparse2.default)(nsiVersion);
     const vMinor = `${v.major}.${v.minor}`;
+    const cdn = nsiCdnUrl.replace("{version}", vMinor);
     const sources = {
-      "nsi_data": `https://cdn.jsdelivr.net/npm/name-suggestion-index@${vMinor}/dist/nsi.min.json`,
-      "nsi_dissolved": `https://cdn.jsdelivr.net/npm/name-suggestion-index@${vMinor}/dist/dissolved.min.json`,
-      "nsi_features": `https://cdn.jsdelivr.net/npm/name-suggestion-index@${vMinor}/dist/featureCollection.min.json`,
-      "nsi_generics": `https://cdn.jsdelivr.net/npm/name-suggestion-index@${vMinor}/dist/genericWords.min.json`,
-      "nsi_presets": `https://cdn.jsdelivr.net/npm/name-suggestion-index@${vMinor}/dist/presets/nsi-id-presets.min.json`,
-      "nsi_replacements": `https://cdn.jsdelivr.net/npm/name-suggestion-index@${vMinor}/dist/replacements.min.json`,
-      "nsi_trees": `https://cdn.jsdelivr.net/npm/name-suggestion-index@${vMinor}/dist/trees.min.json`
+      "nsi_data": cdn + "dist/nsi.min.json",
+      "nsi_dissolved": cdn + "dist/dissolved.min.json",
+      "nsi_features": cdn + "dist/featureCollection.min.json",
+      "nsi_generics": cdn + "dist/genericWords.min.json",
+      "nsi_presets": cdn + "dist/presets/nsi-id-presets.min.json",
+      "nsi_replacements": cdn + "dist/replacements.min.json",
+      "nsi_trees": cdn + "dist/trees.min.json"
     };
     let fileMap = _mainFileFetcher.fileMap();
     for (const k in sources) {
@@ -69738,16 +73231,51 @@ ${content}</tr>
     ]).then((vals) => {
       _nsi = {
         data: vals[0].nsi,
+        // the raw name-suggestion-index data
         dissolved: vals[1].dissolved,
+        // list of dissolved items
         replacements: vals[2].replacements,
+        // trivial old->new qid replacements
         trees: vals[3].trees,
+        // metadata about trees, main tags
         kvt: /* @__PURE__ */ new Map(),
+        // Map (k -> Map (v -> t) )
         qids: /* @__PURE__ */ new Map(),
+        // Map (wd/wp tag values -> qids)
         ids: /* @__PURE__ */ new Map()
+        // Map (id -> NSI item)
+      };
+      const matcher = _nsi.matcher = new Matcher();
+      matcher.buildMatchIndex(_nsi.data);
+      matcher.itemLocation = /* @__PURE__ */ new Map();
+      matcher.locationSets = /* @__PURE__ */ new Map();
+      Object.keys(_nsi.data).forEach((tkv) => {
+        const items = _nsi.data[tkv].items;
+        if (!Array.isArray(items) || !items.length)
+          return;
+        items.forEach((item) => {
+          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;
+          const fakeFeature = { id: locationSetID, properties: { id: locationSetID, area: 1 } };
+          matcher.locationSets.set(locationSetID, fakeFeature);
+        });
+      });
+      matcher.locationIndex = (bbox2) => {
+        const validHere = _sharedLocationManager.locationSetsAt([bbox2[0], bbox2[1]]);
+        const results = [];
+        for (const [locationSetID, area] of Object.entries(validHere)) {
+          const fakeFeature = matcher.locationSets.get(locationSetID);
+          if (fakeFeature) {
+            fakeFeature.properties.area = area;
+            results.push(fakeFeature);
+          }
+        }
+        return results;
       };
-      _nsi.matcher = new Matcher();
-      _nsi.matcher.buildMatchIndex(_nsi.data);
-      _nsi.matcher.buildLocationIndex(_nsi.data, _mainLocations.loco());
       Object.keys(_nsi.data).forEach((tkv) => {
         const category = _nsi.data[tkv];
         const parts = tkv.split("/", 3);
@@ -69842,6 +73370,7 @@ ${content}</tr>
       patterns2 = {
         primary: /^(flag:name|flag:name:\w+)$/i,
         alternate: /^(flag|flag:\w+|subject|subject:\w+)$/i
+        // note: no `country`, we special-case it below
       };
     } else if (t === "brands") {
       testNameFragments = true;
@@ -69965,42 +73494,39 @@ ${content}</tr>
       return changed ? { newTags, matched: null } : null;
     }
     const tuples = gatherTuples(tryKVs, tryNames);
-    let foundPrimary = false;
-    let bestItem;
-    for (let i2 = 0; i2 < tuples.length && !foundPrimary; i2++) {
+    for (let i2 = 0; i2 < tuples.length; i2++) {
       const tuple = tuples[i2];
       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;
+      let itemID, item;
       for (let j2 = 0; j2 < hits.length; j2++) {
         const hit = hits[j2];
-        const isPrimary = hits[j2].match === "primary";
-        const itemID = hit.itemID;
+        itemID = hit.itemID;
         if (_nsi.dissolved[itemID])
           continue;
-        const item = _nsi.ids.get(itemID);
+        item = _nsi.ids.get(itemID);
         if (!item)
           continue;
         const mainTag = item.mainTag;
         const itemQID = item.tags[mainTag];
         const notQID = newTags[`not:${mainTag}`];
-        if (!itemQID || itemQID === notQID || newTags.office && !item.tags.office) {
+        if (
+          // Exceptions, skip this hit
+          !itemQID || itemQID === notQID || // No `*:wikidata` or matched a `not:*:wikidata`
+          newTags.office && !item.tags.office
+        ) {
+          item = null;
           continue;
-        }
-        if (!bestItem || isPrimary) {
-          bestItem = item;
-          if (isPrimary) {
-            foundPrimary = true;
-          }
+        } else {
           break;
         }
       }
-    }
-    if (bestItem) {
-      const itemID = bestItem.id;
-      const item = JSON.parse(JSON.stringify(bestItem));
+      if (!item)
+        continue;
+      item = JSON.parse(JSON.stringify(item));
       const tkv = item.tkv;
       const parts = tkv.split("/", 3);
       const k = parts[1];
@@ -70088,20 +73614,55 @@ ${content}</tr>
     return false;
   }
   var nsi_default = {
+    // `init()`
+    // On init, start preparing the name-suggestion-index
+    //
     init: () => {
       setNsiSources();
-      _mainPresetIndex.ensureLoaded().then(() => loadNsiPresets()).then(() => delay(100)).then(() => _mainLocations.mergeLocationSets([])).then(() => loadNsiData()).then(() => _nsiStatus = "ok").catch(() => _nsiStatus = "failed");
-      function delay(msec) {
-        return new Promise((resolve) => {
-          window.setTimeout(resolve, msec);
-        });
-      }
+      _mainPresetIndex.ensureLoaded().then(() => loadNsiPresets()).then(() => loadNsiData()).then(() => _nsiStatus = "ok").catch(() => _nsiStatus = "failed");
     },
+    // `reset()`
+    // Reset is called when user saves data to OSM (does nothing here)
+    //
     reset: () => {
     },
+    // `status()`
+    // To let other code know how it's going...
+    //
+    // Returns
+    //   `String`: 'loading', 'ok', 'failed'
+    //
     status: () => _nsiStatus,
+    // `isGenericName()`
+    // Is the `name` tag generic?
+    //
+    // Arguments
+    //   `tags`: `Object` containing the feature's OSM tags
+    // Returns
+    //   `true` if it is generic, `false` if not
+    //
     isGenericName: (tags) => _isGenericName(tags),
+    // `upgradeTags()`
+    // Suggest tag upgrades.
+    // This function will not modify the input tags, it makes a copy.
+    //
+    // Arguments
+    //   `tags`: `Object` containing the feature's OSM tags
+    //   `loc`: Location where this feature exists, as a [lon, lat]
+    // Returns
+    //   `Object` containing the result, or `null` if no changes needed:
+    //   {
+    //     'newTags': `Object` - The tags the the feature should have
+    //     'matched': `Object` - The matched item
+    //   }
+    //
     upgradeTags: (tags, loc) => _upgradeTags(tags, loc),
+    // `cache()`
+    // Direct access to the NSI cache, useful for testing or breaking things
+    //
+    // Returns
+    //   `Object`: the internal NSI cache
+    //
     cache: () => _nsi
   };
 
@@ -70152,14 +73713,15 @@ ${content}</tr>
   }
   function loadNextTilePage(which, currZoom, url, tile) {
     var cache = _oscCache[which];
-    var bbox = tile.extent.bbox();
+    var bbox2 = tile.extent.bbox();
     var maxPages = maxPageAtZoom(currZoom);
     var nextPage = cache.nextPage[tile.id] || 1;
     var params = utilQsString({
       ipp: maxResults,
       page: nextPage,
-      bbTopLeft: [bbox.maxY, bbox.minX].join(","),
-      bbBottomRight: [bbox.minY, bbox.maxX].join(",")
+      // client_id: clientId,
+      bbTopLeft: [bbox2.maxY, bbox2.minX].join(","),
+      bbBottomRight: [bbox2.minY, bbox2.maxX].join(",")
     }, true);
     if (nextPage > maxPages)
       return;
@@ -70180,7 +73742,7 @@ ${content}</tr>
       if (!data || !data.currentPageItems || !data.currentPageItems.length) {
         throw new Error("No Data");
       }
-      var features2 = data.currentPageItems.map(function(item) {
+      var features = data.currentPageItems.map(function(item) {
         var loc = [+item.lng, +item.lat];
         var d;
         if (which === "images") {
@@ -70210,7 +73772,7 @@ ${content}</tr>
           data: d
         };
       });
-      cache.rtree.load(features2);
+      cache.rtree.load(features);
       if (data.currentPageItems.length === maxResults) {
         cache.nextPage[tile.id] = nextPage + 1;
         loadNextTilePage(which, currZoom, url, tile);
@@ -70267,9 +73829,9 @@ ${content}</tr>
       var viewport = projection2.clipExtent();
       var min3 = [viewport[0][0], viewport[1][1]];
       var max3 = [viewport[1][0], viewport[0][1]];
-      var bbox = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
+      var bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
       var sequenceKeys = {};
-      _oscCache.images.rtree.search(bbox).forEach(function(d) {
+      _oscCache.images.rtree.search(bbox2).forEach(function(d) {
         sequenceKeys[d.data.sequence_id] = true;
       });
       var lineStrings = [];
@@ -70424,6 +73986,9 @@ ${content}</tr>
     getSequenceKeyForImage: function(d) {
       return d && d.sequence_id;
     },
+    // Updates the currently highlighted sequence and selected bubble.
+    // Reset is only necessary when interacting with the viewport because
+    // this implicitly changes the currently selected bubble/sequence
     setStyles: function(context, hovered, reset) {
       if (reset) {
         context.container().selectAll(".viewfield-group").classed("highlighted", false).classed("hovered", false).classed("currentView", false);
@@ -70509,14 +74074,21 @@ ${content}</tr>
         response_type: "code",
         scope: o.scope
       });
-      if (!o.singlepage) {
+      if (o.singlepage) {
+        var params = utilStringQs2(window.location.search.slice(1));
+        if (params.code) {
+          getAccessToken(params.code);
+        } else {
+          window.location = url;
+        }
+      } else {
         var w = 600;
         var h = 550;
         var settings = [
           ["width", w],
           ["height", h],
-          ["left", screen.width / 2 - w / 2],
-          ["top", screen.height / 2 - h / 2]
+          ["left", window.screen.width / 2 - w / 2],
+          ["top", window.screen.height / 2 - h / 2]
         ].map(function(x) {
           return x.join("=");
         }).join(",");
@@ -70530,8 +74102,8 @@ ${content}</tr>
         }
       }
       window.authComplete = function(url2) {
-        var params = utilStringQs2(url2.split("?")[1]);
-        getAccessToken(params.code);
+        var params2 = utilStringQs2(url2.split("?")[1]);
+        getAccessToken(params2.code);
         delete window.authComplete;
       };
       function getAccessToken(auth_code) {
@@ -70591,6 +74163,42 @@ ${content}</tr>
       }
       getAccessToken(auth_code);
     };
+    oauth2.fetch = function(path, options2, callback) {
+      if (oauth2.authenticated()) {
+        return run();
+      } else {
+        if (o.auto) {
+          oauth2.authenticate(run);
+          return;
+        } else {
+          callback("not authenticated", null);
+          return;
+        }
+      }
+      function run() {
+        var url = options2.prefix !== false ? o.url + path : path;
+        var headers = options2.headers || { "Content-Type": "application/x-www-form-urlencoded" };
+        headers.Authorization = "Bearer " + token("oauth2_access_token");
+        return fetch(url, {
+          method: options2.method,
+          body: options2.body,
+          headers
+        }).then((resp) => {
+          var contentType = resp.headers.get("content-type").split(";")[0];
+          switch (contentType) {
+            case "text/html":
+            case "text/xml":
+              return resp.text().then(
+                (txt) => new window.DOMParser().parseFromString(txt, contentType)
+              );
+            case "application/html":
+              return resp.json();
+            default:
+              return resp.text();
+          }
+        });
+      }
+    };
     oauth2.xhr = function(options2, callback) {
       if (oauth2.authenticated()) {
         return run();
@@ -70710,17 +74318,18 @@ ${content}</tr>
   var import_rbush9 = __toESM(require_rbush_min());
   var tiler5 = utilTiler();
   var dispatch7 = dispatch_default("apiStatusChange", "authLoading", "authDone", "change", "loading", "loaded", "loadedNotes");
-  var urlroot = "https://www.openstreetmap.org";
+  var urlroot = osmApiConnections[0].url;
   var redirectPath = window.location.origin + window.location.pathname;
   var oauth = osmAuth({
     url: urlroot,
-    client_id: "0tmNTmd0Jo1dQp4AUmMBLtGiD9YpMuXzHefitcuVStc",
-    client_secret: "BTlNrNxIPitHdL4sP2clHw5KLoee9aKkA7dQbc0Bj7Q",
+    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,
     done: authDone
   });
+  var _apiConnections = osmApiConnections;
   var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
   var _tileCache = { toLoad: {}, loaded: {}, inflight: {}, seen: {}, rtree: new import_rbush9.default() };
   var _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: new import_rbush9.default() };
@@ -70765,7 +74374,7 @@ ${content}</tr>
   function getLoc(attrs) {
     var lon = attrs.lon && attrs.lon.value;
     var lat = attrs.lat && attrs.lat.value;
-    return [parseFloat(lon), parseFloat(lat)];
+    return [Number(lon), Number(lat)];
   }
   function getNodes(obj) {
     var elems = obj.getElementsByTagName("nd");
@@ -70867,7 +74476,7 @@ ${content}</tr>
         timestamp: obj.timestamp,
         user: obj.user,
         uid: obj.uid && obj.uid.toString(),
-        loc: [parseFloat(obj.lon), parseFloat(obj.lat)],
+        loc: [Number(obj.lon), Number(obj.lat)],
         tags: obj.tags
       });
     },
@@ -71035,8 +74644,8 @@ ${content}</tr>
         if (coincident) {
           props.loc = geoVecAdd(props.loc, [epsilon3, epsilon3]);
         }
-        var bbox = geoExtent(props.loc).bbox();
-        coincident = _noteCache.rtree.search(bbox).length;
+        var bbox2 = geoExtent(props.loc).bbox();
+        coincident = _noteCache.rtree.search(bbox2).length;
       } while (coincident);
       for (var i2 = 0; i2 < childNodes.length; i2++) {
         var node = childNodes[i2];
@@ -71202,6 +74811,8 @@ ${content}</tr>
     noteReportURL: function(note) {
       return urlroot + "/reports/new?reportable_type=Note&reportable_id=" + note.id;
     },
+    // Generic method to load data from the OSM API
+    // Can handle either auth or unauth calls.
     loadFromAPI: function(path, callback, options2) {
       options2 = Object.assign({ skipSeen: true }, options2);
       var that = this;
@@ -71263,12 +74874,16 @@ ${content}</tr>
         return controller;
       }
     },
+    // Load a single entity by id (ways and relations use the `/full` call to include
+    // nodes and members). Parent relations are not included, see `loadEntityRelations`.
+    // GET /api/0.6/node/#id
+    // GET /api/0.6/[way|relation]/#id/full
     loadEntity: function(id2, callback) {
-      var type3 = osmEntity.id.type(id2);
+      var type2 = osmEntity.id.type(id2);
       var osmID = osmEntity.id.toOSM(id2);
       var options2 = { skipSeen: false };
       this.loadFromAPI(
-        "/api/0.6/" + type3 + "/" + osmID + (type3 !== "node" ? "/full" : "") + ".json",
+        "/api/0.6/" + type2 + "/" + osmID + (type2 !== "node" ? "/full" : "") + ".json",
         function(err, entities) {
           if (callback)
             callback(err, { data: entities });
@@ -71276,12 +74891,14 @@ ${content}</tr>
         options2
       );
     },
+    // Load a single entity with a specific version
+    // GET /api/0.6/[node|way|relation]/#id/#version
     loadEntityVersion: function(id2, version, callback) {
-      var type3 = osmEntity.id.type(id2);
+      var type2 = osmEntity.id.type(id2);
       var osmID = osmEntity.id.toOSM(id2);
       var options2 = { skipSeen: false };
       this.loadFromAPI(
-        "/api/0.6/" + type3 + "/" + osmID + "/" + version + ".json",
+        "/api/0.6/" + type2 + "/" + osmID + "/" + version + ".json",
         function(err, entities) {
           if (callback)
             callback(err, { data: entities });
@@ -71289,12 +74906,14 @@ ${content}</tr>
         options2
       );
     },
+    // Load the relations of a single entity with the given.
+    // GET /api/0.6/[node|way|relation]/#id/relations
     loadEntityRelations: function(id2, callback) {
-      var type3 = osmEntity.id.type(id2);
+      var type2 = osmEntity.id.type(id2);
       var osmID = osmEntity.id.toOSM(id2);
       var options2 = { skipSeen: false };
       this.loadFromAPI(
-        "/api/0.6/" + type3 + "/" + osmID + "/relations.json",
+        "/api/0.6/" + type2 + "/" + osmID + "/relations.json",
         function(err, entities) {
           if (callback)
             callback(err, { data: entities });
@@ -71302,18 +74921,22 @@ ${content}</tr>
         options2
       );
     },
+    // Load multiple entities in chunks
+    // (note: callback may be called multiple times)
+    // Unlike `loadEntity`, child nodes and members are not fetched
+    // GET /api/0.6/[nodes|ways|relations]?#parameters
     loadMultiple: function(ids, callback) {
       var that = this;
       var groups = utilArrayGroupBy(utilArrayUniq(ids), osmEntity.id.type);
       Object.keys(groups).forEach(function(k) {
-        var type3 = k + "s";
+        var type2 = k + "s";
         var osmIDs = groups[k].map(function(id2) {
           return osmEntity.id.toOSM(id2);
         });
         var options2 = { skipSeen: false };
         utilArrayChunk(osmIDs, 150).forEach(function(arr) {
           that.loadFromAPI(
-            "/api/0.6/" + type3 + ".json?" + type3 + "=" + arr.join(),
+            "/api/0.6/" + type2 + ".json?" + type2 + "=" + arr.join(),
             function(err, entities) {
               if (callback)
                 callback(err, { data: entities });
@@ -71323,6 +74946,10 @@ ${content}</tr>
         });
       });
     },
+    // Create, upload, and close a changeset
+    // PUT /api/0.6/changeset/create
+    // POST /api/0.6/changeset/#id/upload
+    // PUT /api/0.6/changeset/#id/close
     putChangeset: function(changeset, changes, callback) {
       var cid = _connectionID;
       if (_changeset.inflight) {
@@ -71378,6 +75005,9 @@ ${content}</tr>
         }
       }
     },
+    // Load multiple users in chunks
+    // (note: callback may be called multiple times)
+    // GET /api/0.6/users?users=#id1,#id2,...,#idn
     loadUsers: function(uids, callback) {
       var toLoad = [];
       var cached = [];
@@ -71411,6 +75041,8 @@ ${content}</tr>
         }, options2);
       }
     },
+    // Load a given user by id
+    // GET /api/0.6/user/#id
     loadUser: function(uid, callback) {
       if (_userCache.user[uid] || !this.authenticated()) {
         delete _userCache.toLoad[uid];
@@ -71431,6 +75063,8 @@ ${content}</tr>
         }, options2);
       }
     },
+    // Load the details of the logged-in user
+    // GET /api/0.6/user/details
     userDetails: function(callback) {
       if (_userDetails) {
         return callback(void 0, _userDetails);
@@ -71451,6 +75085,8 @@ ${content}</tr>
         }, options2);
       }
     },
+    // Load previous changesets for the logged in user
+    // GET /api/0.6/changesets?user=#id
     userChangesets: function(callback) {
       if (_userChangesets) {
         return callback(void 0, _userChangesets);
@@ -71483,6 +75119,8 @@ ${content}</tr>
         return callback(void 0, _userChangesets);
       }
     },
+    // Fetch the status of the OSM API
+    // GET /api/capabilities
     status: function(callback) {
       var url = urlroot + "/api/capabilities";
       var errback = wrapcb(this, done, _connectionID);
@@ -71523,6 +75161,8 @@ ${content}</tr>
         }
       }
     },
+    // Calls `status` and dispatches an `apiStatusChange` event if the returned
+    // status differs from the cached status.
     reloadApiStatus: function() {
       if (!this.throttledReloadApiStatus) {
         var that = this;
@@ -71537,9 +75177,12 @@ ${content}</tr>
       }
       this.throttledReloadApiStatus();
     },
+    // Returns the maximum number of nodes a single way can have
     maxWayNodes: function() {
       return _maxWayNodes;
     },
+    // Load data (entities) from the API in tiles
+    // GET /api/0.6/map?bbox=
     loadTiles: function(projection2, callback) {
       if (_off)
         return;
@@ -71553,6 +75196,8 @@ ${content}</tr>
         this.loadTile(tile, callback);
       }, this);
     },
+    // Load a single data tile
+    // GET /api/0.6/map?bbox=
     loadTile: function(tile, callback) {
       if (_off)
         return;
@@ -71573,9 +75218,9 @@ ${content}</tr>
         if (!err) {
           delete _tileCache.toLoad[tile.id];
           _tileCache.loaded[tile.id] = true;
-          var bbox = tile.extent.bbox();
-          bbox.id = tile.id;
-          _tileCache.rtree.insert(bbox);
+          var bbox2 = tile.extent.bbox();
+          bbox2.id = tile.id;
+          _tileCache.rtree.insert(bbox2);
         }
         if (callback) {
           callback(err, Object.assign({ data: parsed }, tile));
@@ -71586,9 +75231,10 @@ ${content}</tr>
       }
     },
     isDataLoaded: function(loc) {
-      var bbox = { minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1] };
-      return _tileCache.rtree.collides(bbox);
+      var bbox2 = { minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1] };
+      return _tileCache.rtree.collides(bbox2);
     },
+    // load the tile that covers the given `loc`
     loadTileAtLoc: function(loc, callback) {
       if (Object.keys(_tileCache.toLoad).length > 50)
         return;
@@ -71603,6 +75249,8 @@ ${content}</tr>
         this.loadTile(tile, callback);
       }, this);
     },
+    // Load notes from the API in tiles
+    // GET /api/0.6/notes?bbox=
     loadNotes: function(projection2, noteOptions) {
       noteOptions = Object.assign({ limit: 1e4, closed: 7 }, noteOptions);
       if (_off)
@@ -71636,6 +75284,8 @@ ${content}</tr>
         );
       });
     },
+    // Create a note
+    // POST /api/0.6/notes?params
     postNoteCreate: function(note, callback) {
       if (!this.authenticated()) {
         return callback({ message: "Not Authenticated", status: -3 }, note);
@@ -71670,6 +75320,10 @@ ${content}</tr>
         }, options2);
       }
     },
+    // Update a note
+    // POST /api/0.6/notes/#id/comment?text=comment
+    // POST /api/0.6/notes/#id/close?text=comment
+    // POST /api/0.6/notes/#id/reopen?text=comment
     postNoteUpdate: function(note, newStatus, callback) {
       if (!this.authenticated()) {
         return callback({ message: "Not Authenticated", status: -3 }, note);
@@ -71716,6 +75370,13 @@ ${content}</tr>
         }, options2);
       }
     },
+    /* connection options for source switcher (optional) */
+    apiConnections: function(val) {
+      if (!arguments.length)
+        return _apiConnections;
+      _apiConnections = val;
+      return this;
+    },
     switch: function(newOptions) {
       urlroot = newOptions.url;
       var oldOptions = utilObjectOmit(oauth.options(), "access_token");
@@ -71733,6 +75394,9 @@ ${content}</tr>
     isChangesetInflight: function() {
       return !!_changeset.inflight;
     },
+    // get/set cached data
+    // This is used to save/restore the state when entering/exiting the walkthrough
+    // Also used for testing purposes.
     caches: function(obj) {
       function cloneCache(source) {
         var target = {};
@@ -71822,24 +75486,28 @@ ${content}</tr>
       _tileZoom4 = val;
       return this;
     },
+    // get all cached notes covering the viewport
     notes: function(projection2) {
       var viewport = projection2.clipExtent();
       var min3 = [viewport[0][0], viewport[1][1]];
       var max3 = [viewport[1][0], viewport[0][1]];
-      var bbox = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
-      return _noteCache.rtree.search(bbox).map(function(d) {
+      var bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
+      return _noteCache.rtree.search(bbox2).map(function(d) {
         return d.data;
       });
     },
+    // get a single note from the cache
     getNote: function(id2) {
       return _noteCache.note[id2];
     },
+    // remove a single note from the cache
     removeNote: function(note) {
       if (!(note instanceof osmNote) || !note.id)
         return;
       delete _noteCache.note[note.id];
       updateRtree4(encodeNoteRtree(note), false);
     },
+    // replace a single note in the cache
     replaceNote: function(note) {
       if (!(note instanceof osmNote) || !note.id)
         return;
@@ -71847,6 +75515,8 @@ ${content}</tr>
       updateRtree4(encodeNoteRtree(note), true);
       return note;
     },
+    // Get an array of note IDs closed during this session.
+    // Used to populate `closed:note` changeset tag
     getClosedIDs: function() {
       return Object.keys(_noteCache.closed).sort();
     }
@@ -71887,6 +75557,12 @@ ${content}</tr>
       });
       _inflight2 = {};
     },
+    /**
+     * Get the best value for the property, or undefined if not found
+     * @param entity object from wikibase
+     * @param property string e.g. 'P4' for image
+     * @param langCode string e.g. 'fr' for French
+     */
     claimToValue: function(entity, property, langCode) {
       if (!entity.claims[property])
         return void 0;
@@ -71908,6 +75584,11 @@ ${content}</tr>
         return void 0;
       }
     },
+    /**
+     * Convert monolingual property into a key-value object (language -> value)
+     * @param entity object from wikibase
+     * @param property string e.g. 'P31' for monolingual wiki page title
+     */
     monolingualClaimToValueObj: function(entity, property) {
       if (!entity || !entity.claims[property])
         return void 0;
@@ -71921,6 +75602,14 @@ ${content}</tr>
       var result = value ? "Tag:" + key + "=" + value : "Key:" + key;
       return result.replace(/_/g, " ").trim();
     },
+    //
+    // Pass params object of the form:
+    // {
+    //   key: 'string',
+    //   value: 'string',
+    //   langCode: 'string'
+    // }
+    //
     getEntity: function(params, callback) {
       var doRequest = params.debounce ? debouncedRequest : request;
       var that = this;
@@ -71970,6 +75659,9 @@ ${content}</tr>
         languagefallback: 1,
         origin: "*",
         format: "json"
+        // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
+        // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
+        // formatversion: 2,
       };
       var url = apibase3 + "?" + utilQsString(obj);
       doRequest(url, function(err, d) {
@@ -72007,6 +75699,22 @@ ${content}</tr>
         }
       });
     },
+    //
+    // Pass params object of the form:
+    // {
+    //   key: 'string',     // required
+    //   value: 'string'    // optional
+    // }
+    //
+    // Get an result object used to display tag documentation
+    // {
+    //   title:        'string',
+    //   description:  'string',
+    //   editURL:      'string',
+    //   imageURL:     'string',
+    //   wiki:         { title: 'string', text: 'string', url: 'string' }
+    // }
+    //
     getDocs: function(params, callback) {
       var that = this;
       var langCodes = _mainLocalizer.localeCodes().map(function(code) {
@@ -72218,7 +75926,7 @@ ${content}</tr>
       if (!bubbles)
         return;
       bubbles.shift();
-      const features2 = bubbles.map((bubble) => {
+      const features = bubbles.map((bubble) => {
         if (cache.points[bubble.id])
           return null;
         const loc = [bubble.lo, bubble.la];
@@ -72228,8 +75936,14 @@ ${content}</tr>
           ca: bubble.he,
           captured_at: bubble.cd,
           captured_by: "microsoft",
+          // nbn: bubble.nbn,
+          // pbn: bubble.pbn,
+          // ad: bubble.ad,
+          // rn: bubble.rn,
           pr: bubble.pr,
+          // previous
           ne: bubble.ne,
+          // next
           pano: true,
           sequenceKey: null
         };
@@ -72245,7 +75959,7 @@ ${content}</tr>
           data: d
         };
       }).filter(Boolean);
-      cache.rtree.load(features2);
+      cache.rtree.load(features);
       connectSequences();
       if (which === "bubbles") {
         dispatch8.call("loadedImages");
@@ -72728,12 +76442,18 @@ ${content}</tr>
     return quadKeys;
   }
   var streetside_default = {
+    /**
+     * init() initialize streetside.
+     */
     init: function() {
       if (!_ssCache) {
         this.reset();
       }
       this.event = utilRebind(this, dispatch8, "on");
     },
+    /**
+     * reset() reset the cache.
+     */
     reset: function() {
       if (_ssCache) {
         Object.values(_ssCache.bubbles.inflight).forEach(abortRequest6);
@@ -72743,6 +76463,9 @@ ${content}</tr>
         sequences: {}
       };
     },
+    /**
+     * bubbles()
+     */
     bubbles: function(projection2) {
       const limit = 5;
       return searchLimited3(limit, projection2, _ssCache.bubbles.rtree);
@@ -72754,10 +76477,10 @@ ${content}</tr>
       const viewport = projection2.clipExtent();
       const min3 = [viewport[0][0], viewport[1][1]];
       const max3 = [viewport[1][0], viewport[0][1]];
-      const bbox = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
+      const bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
       let seen = {};
       let results = [];
-      _ssCache.bubbles.rtree.search(bbox).forEach((d) => {
+      _ssCache.bubbles.rtree.search(bbox2).forEach((d) => {
         const key = d.data.sequenceKey;
         if (key && !seen[key]) {
           seen[key] = true;
@@ -72766,6 +76489,9 @@ ${content}</tr>
       });
       return results;
     },
+    /**
+     * loadBubbles()
+     */
     loadBubbles: function(projection2, margin) {
       if (margin === void 0)
         margin = 2;
@@ -72865,8 +76591,8 @@ ${content}</tr>
           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, point) => {
-            return extent2.extend(geoExtent(point));
+          let extent = poly.reduce((extent2, point2) => {
+            return extent2.extend(geoExtent(point2));
           }, geoExtent());
           let minDist = Infinity;
           _ssCache.bubbles.rtree.search(extent.bbox()).forEach((d) => {
@@ -72899,6 +76625,9 @@ ${content}</tr>
       _sceneOptions.yaw = yaw;
       return this;
     },
+    /**
+     * showViewer()
+     */
     showViewer: function(context) {
       let wrap2 = context.container().select(".photoviewer").classed("hide", false);
       let isHidden = wrap2.selectAll(".photo-wrapper.ms-wrapper.hide").size();
@@ -72908,6 +76637,9 @@ ${content}</tr>
       }
       return this;
     },
+    /**
+     * hideViewer()
+     */
     hideViewer: function(context) {
       let viewer = context.container().select(".photoviewer");
       if (!viewer.empty())
@@ -72917,6 +76649,9 @@ ${content}</tr>
       this.updateUrlImage(null);
       return this.setStyles(context, null, true);
     },
+    /**
+     * selectImage().
+     */
     selectImage: function(context, key) {
       let that = this;
       let d = this.cachedImage(key);
@@ -72950,7 +76685,7 @@ ${content}</tr>
       label.append("span").call(_t.append("streetside.hires"));
       let captureInfo = line1.append("div").attr("class", "attribution-capture-info");
       if (d.captured_by) {
-        const yyyy = new Date().getFullYear();
+        const yyyy = (/* @__PURE__ */ new Date()).getFullYear();
         captureInfo.append("a").attr("class", "captured_by").attr("target", "_blank").attr("href", "https://www.microsoft.com/en-us/maps/streetside").text("\xA9" + yyyy + " Microsoft");
         captureInfo.append("span").text("|");
       }
@@ -72966,7 +76701,7 @@ ${content}</tr>
         bubbleIdQuadKey = "0" + bubbleIdQuadKey;
       }
       const imgUrlPrefix = streetsideImagesApi + "hs" + bubbleIdQuadKey;
-      const imgUrlSuffix = ".jpg?g=6338&n=z";
+      const imgUrlSuffix = ".jpg?g=13515&n=z";
       const faceKeys = ["01", "02", "03", "10", "11", "12"];
       let quadKeys = getQuadKeys();
       let faces = faceKeys.map((faceKey) => {
@@ -72998,6 +76733,9 @@ ${content}</tr>
     getSequenceKeyForBubble: function(d) {
       return d && d.sequenceKey;
     },
+    // Updates the currently highlighted sequence and selected bubble.
+    // Reset is only necessary when interacting with the viewport because
+    // this implicitly changes the currently selected bubble/sequence
     setStyles: function(context, hovered, reset) {
       if (reset) {
         context.container().selectAll(".viewfield-group").classed("highlighted", false).classed("hovered", false).classed("currentView", false);
@@ -73038,13 +76776,16 @@ ${content}</tr>
         window.location.replace("#" + utilQsString(hash, true));
       }
     },
+    /**
+     * cache().
+     */
     cache: function() {
       return _ssCache;
     }
   };
 
   // modules/services/taginfo.js
-  var apibase4 = "https://taginfo.openstreetmap.org/api/4/";
+  var apibase4 = taginfoApiUrl;
   var _inflight3 = {};
   var _popularKeys = {};
   var _taginfoCache = {};
@@ -73092,15 +76833,15 @@ ${content}</tr>
   function clean(params) {
     return utilObjectOmit(params, ["geometry", "debounce"]);
   }
-  function filterKeys(type3) {
-    var count_type = type3 ? "count_" + type3 : "count_all";
+  function filterKeys(type2) {
+    var count_type = type2 ? "count_" + type2 : "count_all";
     return function(d) {
-      return parseFloat(d[count_type]) > 2500 || d.in_wiki;
+      return Number(d[count_type]) > 2500 || d.in_wiki;
     };
   }
   function filterMultikeys(prefix) {
     return function(d) {
-      var re2 = new RegExp("^" + prefix + "(.*)$");
+      var re2 = new RegExp("^" + prefix + "(.*)$", "i");
       var matches = d.key.match(re2) || [];
       return matches.length === 2 && matches[1].indexOf(":") === -1;
     };
@@ -73120,7 +76861,7 @@ ${content}</tr>
         return false;
       if (d.role.match(/[A-Z*;,]/) !== null)
         return false;
-      return parseFloat(d[tag_members_fractions[geometry]]) > 0;
+      return Number(d[tag_members_fractions[geometry]]) > 0;
     };
   }
   function valKey(d) {
@@ -73187,6 +76928,7 @@ ${content}</tr>
       _inflight3 = {};
       _taginfoCache = {};
       _popularKeys = {
+        // manually exclude some keys – #5377, #7485
         postal_code: true,
         full_name: true,
         loc_name: true,
@@ -73288,8 +77030,7 @@ ${content}</tr>
         if (err) {
           callback(err);
         } else {
-          var re2 = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery|cai_scale/;
-          var allowUpperCase = re2.test(params.key);
+          var allowUpperCase = allowUpperCaseTagValues.test(params.key);
           var f2 = filterValues(allowUpperCase);
           var result = d.data.filter(f2).map(valKeyDescription);
           _taginfoCache[url] = result;
@@ -73349,248 +77090,6 @@ ${content}</tr>
 
   // modules/services/vector_tile.js
   var import_fast_deep_equal11 = __toESM(require_fast_deep_equal());
-
-  // 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.");
-        }
-      }
-    }
-    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");
-    }
-    var geom = {
-      type: "LineString",
-      coordinates
-    };
-    return feature2(geom, properties, options2);
-  }
-  function multiLineString(coordinates, properties, options2) {
-    if (options2 === void 0) {
-      options2 = {};
-    }
-    var geom = {
-      type: "MultiLineString",
-      coordinates
-    };
-    return feature2(geom, properties, options2);
-  }
-  function multiPolygon(coordinates, properties, options2) {
-    if (options2 === void 0) {
-      options2 = {};
-    }
-    var geom = {
-      type: "MultiPolygon",
-      coordinates
-    };
-    return feature2(geom, properties, options2);
-  }
-
-  // node_modules/@turf/invariant/dist/es/index.js
-  function getGeom(geojson) {
-    if (geojson.type === "Feature") {
-      return geojson.geometry;
-    }
-    return geojson;
-  }
-
-  // node_modules/@turf/bbox-clip/dist/es/lib/lineclip.js
-  function lineclip(points, bbox, result) {
-    var len = points.length, codeA = bitCode(points[0], bbox), part = [], i2, codeB, lastCode;
-    var a;
-    var b;
-    if (!result)
-      result = [];
-    for (i2 = 1; i2 < len; i2++) {
-      a = points[i2 - 1];
-      b = points[i2];
-      codeB = lastCode = bitCode(b, bbox);
-      while (true) {
-        if (!(codeA | codeB)) {
-          part.push(a);
-          if (codeB !== lastCode) {
-            part.push(b);
-            if (i2 < len - 1) {
-              result.push(part);
-              part = [];
-            }
-          } else if (i2 === len - 1) {
-            part.push(b);
-          }
-          break;
-        } else if (codeA & codeB) {
-          break;
-        } else if (codeA) {
-          a = intersect(a, b, codeA, bbox);
-          codeA = bitCode(a, bbox);
-        } else {
-          b = intersect(a, b, codeB, bbox);
-          codeB = bitCode(b, bbox);
-        }
-      }
-      codeA = lastCode;
-    }
-    if (part.length)
-      result.push(part);
-    return result;
-  }
-  function polygonclip(points, bbox) {
-    var result, edge, prev, prevInside, i2, p, inside;
-    for (edge = 1; edge <= 8; edge *= 2) {
-      result = [];
-      prev = points[points.length - 1];
-      prevInside = !(bitCode(prev, bbox) & edge);
-      for (i2 = 0; i2 < points.length; i2++) {
-        p = points[i2];
-        inside = !(bitCode(p, bbox) & edge);
-        if (inside !== prevInside)
-          result.push(intersect(prev, p, edge, bbox));
-        if (inside)
-          result.push(p);
-        prev = p;
-        prevInside = inside;
-      }
-      points = result;
-      if (!points.length)
-        break;
-    }
-    return result;
-  }
-  function intersect(a, b, edge, bbox) {
-    return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : null;
-  }
-  function bitCode(p, bbox) {
-    var code = 0;
-    if (p[0] < bbox[0])
-      code |= 1;
-    else if (p[0] > bbox[2])
-      code |= 2;
-    if (p[1] < bbox[1])
-      code |= 4;
-    else if (p[1] > bbox[3])
-      code |= 8;
-    return code;
-  }
-
-  // node_modules/@turf/bbox-clip/dist/es/index.js
-  function bboxClip(feature3, bbox) {
-    var geom = getGeom(feature3);
-    var type3 = geom.type;
-    var properties = feature3.type === "Feature" ? feature3.properties : {};
-    var coords = geom.coordinates;
-    switch (type3) {
-      case "LineString":
-      case "MultiLineString": {
-        var lines_1 = [];
-        if (type3 === "LineString") {
-          coords = [coords];
-        }
-        coords.forEach(function(line) {
-          lineclip(line, bbox, lines_1);
-        });
-        if (lines_1.length === 1) {
-          return lineString(lines_1[0], properties);
-        }
-        return multiLineString(lines_1, properties);
-      }
-      case "Polygon":
-        return polygon(clipPolygon(coords, bbox), properties);
-      case "MultiPolygon":
-        return multiPolygon(coords.map(function(poly) {
-          return clipPolygon(poly, bbox);
-        }), properties);
-      default:
-        throw new Error("geometry " + type3 + " not supported");
-    }
-  }
-  function clipPolygon(rings, bbox) {
-    var outRings = [];
-    for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
-      var ring = rings_1[_i];
-      var clipped = polygonclip(ring, bbox);
-      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);
-        }
-      }
-    }
-    return outRings;
-  }
-
-  // modules/services/vector_tile.js
   var import_fast_json_stable_stringify2 = __toESM(require_fast_json_stable_stringify());
   var import_polygon_clipping2 = __toESM(require_polygon_clipping_umd());
   var import_pbf2 = __toESM(require_pbf());
@@ -73607,7 +77106,7 @@ ${content}</tr>
     if (!Array.isArray(layers)) {
       layers = [layers];
     }
-    var features2 = [];
+    var features = [];
     layers.forEach(function(layerID) {
       var layer = vectorTile.layers[layerID];
       if (layer) {
@@ -73634,7 +77133,7 @@ ${content}</tr>
           feature3.__layerID__ = layerID.replace(/[^_a-zA-Z0-9\-]/g, "_");
           feature3.__featurehash__ = featurehash;
           feature3.__propertyhash__ = propertyhash;
-          features2.push(feature3);
+          features.push(feature3);
           if (isClipped && geometry.type === "MultiPolygon") {
             var merged = mergeCache[propertyhash];
             if (merged && merged.length) {
@@ -73658,7 +77157,7 @@ ${content}</tr>
         }
       }
     });
-    return features2;
+    return features;
   }
   function loadTile2(source, tile) {
     if (source.loaded[tile.id] || source.inflight[tile.id])
@@ -73719,11 +77218,11 @@ ${content}</tr>
       var seen = {};
       var results = [];
       for (var i2 = 0; i2 < tiles.length; i2++) {
-        var features2 = source.loaded[tiles[i2].id];
-        if (!features2 || !features2.length)
+        var features = source.loaded[tiles[i2].id];
+        if (!features || !features.length)
           continue;
-        for (var j2 = 0; j2 < features2.length; j2++) {
-          var feature3 = features2[j2];
+        for (var j2 = 0; j2 < features.length; j2++) {
+          var feature3 = features[j2];
           var hash = feature3.__featurehash__;
           if (seen[hash])
             continue;
@@ -73766,7 +77265,8 @@ ${content}</tr>
     reset: function() {
       _wikidataCache = {};
     },
-    itemsForSearchQuery: function(query, callback) {
+    // Search for Wikidata items matching the query
+    itemsForSearchQuery: function(query, callback, language) {
       if (!query) {
         if (callback)
           callback("No query", {});
@@ -73779,14 +77279,21 @@ ${content}</tr>
         formatversion: 2,
         search: query,
         type: "item",
-        language: lang,
+        // the language to search
+        language: language || lang,
+        // the language for the label and description in the result
         uselang: lang,
         limit: 10,
         origin: "*"
       });
-      json_default(url).then(function(result) {
+      json_default(url).then((result) => {
         if (result && result.error) {
-          throw new Error(result.error);
+          if (result.error.code === "badvalue" && result.error.info.includes(lang) && !language && lang.includes("-")) {
+            this.itemsForSearchQuery(query, callback, lang.split("-")[0]);
+            return;
+          } else {
+            throw new Error(result.error);
+          }
         }
         if (callback)
           callback(null, result.search || {});
@@ -73795,6 +77302,8 @@ ${content}</tr>
           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)
@@ -73809,6 +77318,7 @@ ${content}</tr>
         sites: lang.replace(/-/g, "_") + "wiki",
         titles: title,
         languages: "en",
+        // shrink response by filtering to one language
         origin: "*"
       });
       json_default(url).then(function(result) {
@@ -73864,6 +77374,20 @@ ${content}</tr>
           callback(err.message, {});
       });
     },
+    // Pass `params` object of the form:
+    // {
+    //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
+    // }
+    //
+    // Get an result object used to display tag documentation
+    // {
+    //   title:        'string',
+    //   description:  'string',
+    //   editURL:      'string',
+    //   imageURL:     'string',
+    //   wiki:         { title: 'string', text: 'string', url: 'string' }
+    // }
+    //
     getDocs: function(params, callback) {
       var langs = this.languagesToQuery();
       this.entityByQID(params.qid, function(err, entity) {
@@ -74092,11 +77616,11 @@ ${content}</tr>
       context.enter(mode);
       context.selectedNoteID(_note.id);
     }
-    function move(d3_event, entity, point) {
+    function move(d3_event, entity, point2) {
       d3_event.stopPropagation();
-      _lastLoc = context.projection.invert(point);
+      _lastLoc = context.projection.invert(point2);
       doMove(d3_event);
-      var nudge = geoViewportEdge(point, context.map().dimensions());
+      var nudge = geoViewportEdge(point2, context.map().dimensions());
       if (nudge) {
         startNudge(d3_event, nudge);
       } else {
@@ -74206,7 +77730,8 @@ ${content}</tr>
         if (activeNode && (/* @__PURE__ */ new Set(["INPUT", "TEXTAREA"])).has(activeNode.nodeName))
           return;
       }
-      if (d3_event.keyCode === 93 || d3_event.keyCode === 32) {
+      if (d3_event.keyCode === 93 || // context menu key
+      d3_event.keyCode === 32) {
         d3_event.preventDefault();
       }
       if (d3_event.repeat)
@@ -74253,7 +77778,9 @@ ${content}</tr>
       if (d3_event.buttons && d3_event.buttons !== 1)
         return;
       context.ui().closeEditMenu();
-      _longPressTimeout = window.setTimeout(didLongPress, 500, id2, "longdown-" + (d3_event.pointerType || "mouse"));
+      if (d3_event.pointerType !== "mouse") {
+        _longPressTimeout = window.setTimeout(didLongPress, 500, id2, "longdown-" + (d3_event.pointerType || "mouse"));
+      }
       _downPointers[id2] = {
         firstEvent: d3_event,
         lastEvent: d3_event
@@ -74309,13 +77836,18 @@ ${content}</tr>
       d3_event.preventDefault();
       if (!+d3_event.clientX && !+d3_event.clientY) {
         if (_lastMouseEvent) {
-          d3_event.sourceEvent = _lastMouseEvent;
+          d3_event = _lastMouseEvent;
         } else {
           return;
         }
       } else {
         _lastMouseEvent = d3_event;
-        _lastInteractionType = "rightclick";
+        if (d3_event.pointerType === "touch" || d3_event.pointerType === "pen" || d3_event.mozInputSource && // firefox doesn't give a pointerType on contextmenu events
+        (d3_event.mozInputSource === MouseEvent.MOZ_SOURCE_TOUCH || d3_event.mozInputSource === MouseEvent.MOZ_SOURCE_PEN)) {
+          _lastInteractionType = "touch";
+        } else {
+          _lastInteractionType = "rightclick";
+        }
       }
       _showMenu = true;
       click(d3_event, d3_event);
@@ -74341,7 +77873,10 @@ ${content}</tr>
           _downPointers[selectPointerInfo.pointerId].done = true;
         }
       }
-      var isMultiselect = context.mode().id === "select" && (lastEvent && lastEvent.shiftKey || context.surface().select(".lasso").node() || _multiselectionPointerId && !multiselectEntityId);
+      var isMultiselect = context.mode().id === "select" && // and shift key is down
+      (lastEvent && lastEvent.shiftKey || // or we're lasso-selecting
+      context.surface().select(".lasso").node() || // or a pointer is down over a selected feature
+      _multiselectionPointerId && !multiselectEntityId);
       processClick(targetDatum, isMultiselect, p2, multiselectEntityId);
       function mapContains(event) {
         var rect = mapNode.getBoundingClientRect();
@@ -74371,7 +77906,7 @@ ${content}</tr>
         return null;
       }
     }
-    function processClick(datum2, isMultiselect, point, alsoSelectId) {
+    function processClick(datum2, isMultiselect, point2, alsoSelectId) {
       var mode = context.mode();
       var showMenu = _showMenu;
       var interactionType = _lastInteractionType;
@@ -74424,7 +77959,7 @@ ${content}</tr>
       }
       context.ui().closeEditMenu();
       if (showMenu)
-        context.ui().showEditMenu(point, interactionType);
+        context.ui().showEditMenu(point2, interactionType);
       resetProperties();
     }
     function cancelLongPress() {
@@ -74814,17 +78349,17 @@ ${content}</tr>
       _affectedFeatureCount = 0;
       for (var i2 in entityIds) {
         var entityID = entityIds[i2];
-        var type3 = downgradeTypeForEntityID(entityID);
-        if (type3) {
+        var type2 = downgradeTypeForEntityID(entityID);
+        if (type2) {
           _affectedFeatureCount += 1;
-          if (downgradeType && type3 !== downgradeType) {
-            if (downgradeType !== "generic" && type3 !== "generic") {
+          if (downgradeType && type2 !== downgradeType) {
+            if (downgradeType !== "generic" && type2 !== "generic") {
               downgradeType = "building_address";
             } else {
               downgradeType = "generic";
             }
           } else {
-            downgradeType = type3;
+            downgradeType = type2;
           }
         }
       }
@@ -74856,18 +78391,18 @@ ${content}</tr>
       context.perform(function(graph) {
         for (var i2 in selectedIDs) {
           var entityID = selectedIDs[i2];
-          var type3 = downgradeTypeForEntityID(entityID);
-          if (!type3)
+          var type2 = downgradeTypeForEntityID(entityID);
+          if (!type2)
             continue;
           var tags = Object.assign({}, graph.entity(entityID).tags);
           for (var key in tags) {
-            if (type3 === "address" && addressKeysToKeep.indexOf(key) !== -1)
+            if (type2 === "address" && addressKeysToKeep.indexOf(key) !== -1)
               continue;
-            if (type3 === "building") {
+            if (type2 === "building") {
               if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/))
                 continue;
             }
-            if (type3 !== "generic") {
+            if (type2 !== "generic") {
               if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/))
                 continue;
             }
@@ -74987,9 +78522,9 @@ ${content}</tr>
       var join = actionJoin(selectedIDs);
       if (!join.disabled(context.graph()))
         return join;
-      var merge3 = actionMerge(selectedIDs);
-      if (!merge3.disabled(context.graph()))
-        return merge3;
+      var merge2 = actionMerge(selectedIDs);
+      if (!merge2.disabled(context.graph()))
+        return merge2;
       var mergePolygon = actionMergePolygon(selectedIDs);
       if (!mergePolygon.disabled(context.graph()))
         return mergePolygon;
@@ -74998,8 +78533,8 @@ ${content}</tr>
         return mergeNodes;
       if (join.disabled(context.graph()) !== "not_eligible")
         return join;
-      if (merge3.disabled(context.graph()) !== "not_eligible")
-        return merge3;
+      if (merge2.disabled(context.graph()) !== "not_eligible")
+        return merge2;
       if (mergePolygon.disabled(context.graph()) !== "not_eligible")
         return mergePolygon;
       return mergeNodes;
@@ -75505,6 +79040,7 @@ ${content}</tr>
       }).filter(function(o) {
         return o.id !== "delete" && o.id !== "downgrade" && o.id !== "copy";
       }).concat([
+        // group copy/downgrade/delete operation together at the end of the list
         operationCopy(context, selectedIDs),
         operationDowngrade(context, selectedIDs),
         operationDelete(context, selectedIDs)
@@ -75676,7 +79212,12 @@ ${content}</tr>
           surface.selectAll(utilEntitySelector([_focusedParentWayId])).classed("related", true);
         }
         if (context.map().withinEditableZoom()) {
-          surface.selectAll(utilDeepMemberSelector(selectedIDs, context.graph(), true)).classed("selected-member", true);
+          surface.selectAll(utilDeepMemberSelector(
+            selectedIDs,
+            context.graph(),
+            true
+            /* skipMultipolgonMembers */
+          )).classed("selected-member", true);
           surface.selectAll(utilEntityOrDeepMemberSelector(selectedIDs, context.graph())).classed("selected", true);
         }
       }
@@ -75824,8 +79365,15 @@ ${content}</tr>
       context.ui().sidebar.hide();
       context.features().forceVisible([]);
       var entity = singular();
-      if (_newFeature && entity && entity.type === "relation" && Object.keys(entity.tags).length === 0 && context.graph().parentRelations(entity).length === 0 && (entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
-        var deleteAction = actionDeleteRelation(entity.id, true);
+      if (_newFeature && entity && entity.type === "relation" && // no tags
+      Object.keys(entity.tags).length === 0 && // no parent relations
+      context.graph().parentRelations(entity).length === 0 && // no members or one member with no role
+      (entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
+        var deleteAction = actionDeleteRelation(
+          entity.id,
+          true
+          /* don't delete untagged members */
+        );
         context.perform(deleteAction, _t("operations.delete.annotation.relation"));
         context.validator().validate();
       }
@@ -75864,7 +79412,10 @@ ${content}</tr>
           return [];
         var graph = context.graph();
         var limitToNodes;
-        if (context.map().editableDataEnabled(true) && context.map().isInWideSelection()) {
+        if (context.map().editableDataEnabled(
+          true
+          /* skipZoomCheck */
+        ) && context.map().isInWideSelection()) {
           limitToNodes = new Set(utilGetAllNodes(context.selectedIDs(), graph));
         } else if (!context.map().editableDataEnabled()) {
           return [];
@@ -75883,7 +79434,7 @@ ${content}</tr>
               var sharedParentNodes = sharedParents[0].nodes;
               return sharedParentNodes.indexOf(node1.id) - sharedParentNodes.indexOf(node2.id);
             } else {
-              return parseFloat(parents1[0].id.slice(1)) - parseFloat(parents2[0].id.slice(1));
+              return Number(parents1[0].id.slice(1)) - Number(parents2[0].id.slice(1));
             }
           } else if (parents1.length || parents2.length) {
             return parents1.length - parents2.length;
@@ -76074,8 +79625,14 @@ ${content}</tr>
       var latestHash = computedHash();
       if (_cachedHash !== latestHash) {
         _cachedHash = latestHash;
-        window.history.replaceState(null, computedTitle(false), latestHash);
-        updateTitle(true);
+        window.history.replaceState(null, computedTitle(
+          false
+          /* includeChangeCount */
+        ), latestHash);
+        updateTitle(
+          true
+          /* includeChangeCount */
+        );
         const q = utilStringQs(latestHash);
         if (q.map) {
           corePreferences("map-location", q.map);
@@ -76084,7 +79641,10 @@ ${content}</tr>
     }
     var _throttledUpdate = throttle_default(updateHashIfNeeded, 500);
     var _throttledUpdateTitle = throttle_default(function() {
-      updateTitle(true);
+      updateTitle(
+        true
+        /* includeChangeCount */
+      );
     }, 500);
     function hashchange() {
       if (window.location.hash === _cachedHash)
@@ -76161,7 +79721,7 @@ ${content}</tr>
   }
   var X = {
     name: "x",
-    handles: ["w", "e"].map(type2),
+    handles: ["w", "e"].map(type),
     input: function(x, e) {
       return x == null ? null : [[+x[0], e[0][1]], [+x[1], e[1][1]]];
     },
@@ -76171,7 +79731,7 @@ ${content}</tr>
   };
   var Y = {
     name: "y",
-    handles: ["n", "s"].map(type2),
+    handles: ["n", "s"].map(type),
     input: function(y, e) {
       return y == null ? null : [[e[0][0], +y[0]], [e[1][0], +y[1]]];
     },
@@ -76181,7 +79741,7 @@ ${content}</tr>
   };
   var XY = {
     name: "xy",
-    handles: ["n", "w", "e", "s", "nw", "ne", "sw", "se"].map(type2),
+    handles: ["n", "w", "e", "s", "nw", "ne", "sw", "se"].map(type),
     input: function(xy) {
       return xy == null ? null : number22(xy);
     },
@@ -76189,7 +79749,7 @@ ${content}</tr>
       return xy;
     }
   };
-  function type2(t) {
+  function type(t) {
     return { type: t };
   }